CTF for ビギナーズ 2016 弘前 Write-up
CTF for ビギナーズ 2016 弘前が、私の所属する研究室から徒歩8秒の講義室で開催されたので、参加してきました。結果は1100ptsで4位(同点が結構いましたが)でした(1位は3人で1400ptsでした)。
最後のCTF演習のwrite-upだけ簡単に書きます(※最後のbin300は時間内に解けてません)。
Misc100: README
問題文に書かれたctf4b{}形式のflagをコピペして終わり。
Forensics100: みてみよう
与えられたpcapファイルをWiresharkで開いてみてみると、HTTPでflag.pngをダウンロードしているのを見つけたのでそのファイルを抽出。開いて見ても真っ白い画像だったので、バイナリエディタで眺めてみたらflagがあった。
Forensics200: エクスポートできるかな?
与えられたpcapファイルを見ると、FTPでPNGデータをやりとりしていたので、エクスポートして開くとflagが書いてた。
Forensics200: ICMP?
与えられたpcapファイルを見ると、ICMPのrequestとreplyがひたすら続いていたので眺めてると、何やら明らかにサイズがでかいICMPパケットがいくつかある。ということでデータ部分をよく見ると、なぜかHTTPリクエストとHTTPレスポンスが入っている。HTTPリクエストでflag.txtを要求しているので、レスポンスのボディを見てみるとbase64っぽい文字列がありデコードするとflagが得られた。
Binary100: HiddenFlag
strings bin100_1 | grep ctf4b
でflagが出た。
Binary200: 復習
講義でやった内容(5つのkeyを探す問題)のkeyが3つバージョン。与えられたバイナリ内の3つの関数Stage1~Stage3の戻り値(eax)がそのままkeyになるので、命令を辿っていけば分かる。
echo -en "23\n945\n-46\n" | ./bin200_1
でflagが出た。
Binary200: ASCII
とりあえず与えられたバイナリを実行してみるとInput flag>>
と出てくる。objdumpで逆アセンブルしてみるとcheck_flagという関数があるので見てみると次のように命令が並んでいる。
mov BYTE PTR [ebp-0x28],0x63 mov BYTE PTR [ebp-0x27],0x74 mov BYTE PTR [ebp-0x26],0x66 mov BYTE PTR [ebp-0x25],0x34 mov BYTE PTR [ebp-0x24],0x62 mov BYTE PTR [ebp-0x23],0x7b mov BYTE PTR [ebp-0x22],0x63 mov BYTE PTR [ebp-0x21],0x30 mov BYTE PTR [ebp-0x20],0x6d mov BYTE PTR [ebp-0x1f],0x70 mov BYTE PTR [ebp-0x1e],0x34 mov BYTE PTR [ebp-0x1d],0x72 mov BYTE PTR [ebp-0x1c],0x31 mov BYTE PTR [ebp-0x1b],0x6e mov BYTE PTR [ebp-0x1a],0x67 mov BYTE PTR [ebp-0x19],0x5f mov BYTE PTR [ebp-0x18],0x77 mov BYTE PTR [ebp-0x17],0x31 mov BYTE PTR [ebp-0x16],0x37 mov BYTE PTR [ebp-0x15],0x68 mov BYTE PTR [ebp-0x14],0x5f mov BYTE PTR [ebp-0x13],0x31 mov BYTE PTR [ebp-0x12],0x6e mov BYTE PTR [ebp-0x11],0x70 mov BYTE PTR [ebp-0x10],0x75 mov BYTE PTR [ebp-0xf],0x37 mov BYTE PTR [ebp-0xe],0x7d mov BYTE PTR [ebp-0xd],0x0
ASCIIっぽい値と文字列の終端っぽい0x0を格納しているのでこれをASCIIに直したらflagが出た。
Binary300: HiddenFlag -returns-
とりあえず与えられたバイナリを実行してみると
HiddenFlag returns You cannot get flag! Haha
と言われる。objdumpで逆アセンブルしてみるとmain関数は文字列をputsで出力するだけで終わっている。しかし、main以外にgenflagという関数が一つあり、関数名からここでflagを生成しているっぽい。
08048514 <genflag>:
8048514: 55 push ebp
8048515: 89 e5 mov ebp,esp
8048517: 56 push esi
8048518: 53 push ebx
8048519: 83 ec 40 sub esp,0x40
804851c: 65 a1 14 00 00 00 mov eax,gs:0x14
8048522: 89 45 f4 mov DWORD PTR [ebp-0xc],eax
8048525: 31 c0 xor eax,eax
8048527: c6 45 df 04 mov BYTE PTR [ebp-0x21],0x4
804852b: c6 45 e0 b2 mov BYTE PTR [ebp-0x20],0xb2
804852f: c6 45 e1 0f mov BYTE PTR [ebp-0x1f],0xf
8048533: c6 45 e2 47 mov BYTE PTR [ebp-0x1e],0x47
8048537: c6 45 e3 33 mov BYTE PTR [ebp-0x1d],0x33
804853b: c6 45 e4 84 mov BYTE PTR [ebp-0x1c],0x84
804853f: c6 45 e5 7f mov BYTE PTR [ebp-0x1b],0x7f
8048543: c6 45 e6 dd mov BYTE PTR [ebp-0x1a],0xdd
8048547: c6 45 e7 44 mov BYTE PTR [ebp-0x19],0x44
804854b: c6 45 e8 bd mov BYTE PTR [ebp-0x18],0xbd
804854f: c6 45 e9 d6 mov BYTE PTR [ebp-0x17],0xd6
8048553: c6 45 ea 98 mov BYTE PTR [ebp-0x16],0x98
8048557: c6 45 eb ad mov BYTE PTR [ebp-0x15],0xad
804855b: c6 45 ec 98 mov BYTE PTR [ebp-0x14],0x98
804855f: c6 45 ed d2 mov BYTE PTR [ebp-0x13],0xd2
8048563: c6 45 ee 36 mov BYTE PTR [ebp-0x12],0x36
8048567: c6 45 ef 14 mov BYTE PTR [ebp-0x11],0x14
804856b: c6 45 f0 f1 mov BYTE PTR [ebp-0x10],0xf1
804856f: c6 45 f1 26 mov BYTE PTR [ebp-0xf],0x26
8048573: c6 45 f2 85 mov BYTE PTR [ebp-0xe],0x85
8048577: c6 45 f3 1b mov BYTE PTR [ebp-0xd],0x1b
804857b: c7 04 24 00 00 00 00 mov DWORD PTR [esp],0x0
8048582: e8 49 fe ff ff call 80483d0 <srand@plt>
8048587: c7 04 24 16 00 00 00 mov DWORD PTR [esp],0x16
804858e: e8 0d fe ff ff call 80483a0 <malloc@plt>
8048593: 89 45 d8 mov DWORD PTR [ebp-0x28],eax
8048596: c7 45 d4 00 00 00 00 mov DWORD PTR [ebp-0x2c],0x0
804859d: eb 21 jmp 80485c0 <genflag+0xac>
804859f: 8b 55 d4 mov edx,DWORD PTR [ebp-0x2c]
80485a2: 8b 45 d8 mov eax,DWORD PTR [ebp-0x28]
80485a5: 8d 1c 02 lea ebx,[edx+eax*1]
80485a8: 8d 55 df lea edx,[ebp-0x21]
80485ab: 8b 45 d4 mov eax,DWORD PTR [ebp-0x2c]
80485ae: 01 d0 add eax,edx
80485b0: 0f b6 30 movzx esi,BYTE PTR [eax]
80485b3: e8 38 fe ff ff call 80483f0 <rand@plt>
80485b8: 31 f0 xor eax,esi
80485ba: 88 03 mov BYTE PTR [ebx],al
80485bc: 83 45 d4 01 add DWORD PTR [ebp-0x2c],0x1
80485c0: 8b 45 d4 mov eax,DWORD PTR [ebp-0x2c]
80485c3: 83 f8 14 cmp eax,0x14
80485c6: 76 d7 jbe 804859f <genflag+0x8b>
80485c8: 8b 55 d4 mov edx,DWORD PTR [ebp-0x2c]
80485cb: 8b 45 d8 mov eax,DWORD PTR [ebp-0x28]
80485ce: 01 d0 add eax,edx
80485d0: c6 00 00 mov BYTE PTR [eax],0x0
80485d3: 8b 45 d8 mov eax,DWORD PTR [ebp-0x28]
80485d6: 8b 4d f4 mov ecx,DWORD PTR [ebp-0xc]
80485d9: 65 33 0d 14 00 00 00 xor ecx,DWORD PTR gs:0x14
80485e0: 74 05 je 80485e7 <genflag+0xd3>
80485e2: e8 a9 fd ff ff call 8048390 <__stack_chk_fail@plt>
80485e7: 83 c4 40 add esp,0x40
80485ea: 5b pop ebx
80485eb: 5e pop esi
80485ec: 5d pop ebp
80485ed: c3 ret
80485ee: 66 90 xchg ax,ax
さらっと見てみると、先ほどの問題と同じようにmov BYTE PTR [ebp-0xYY],0xZZ
のような命令が並んでいる。しかし、ASCIIではない。そこでもう少し詳しく見ていくと、どうやらrand()で得られる乱数と1byteずつxorして、malloc()で確保した領域に入れているっぽい。ということで、gdbを使用しmainで実行を止めた後、eipをgenflagのアドレスに書き換えて、ループが終わったあたりまで実行し、malloc()で確保した領域を表示してみたらflagが出た。
$ gdb -q bin300 (gdb) b *main (gdb) run (gdb) set $eip=*genflag (gdb) u *0x80485d6 (gdb) x/s $eax
感想
今回初めて「CTFの講義」を聴きましたが、知らなかったこともいろいろあり勉強になりました。webの講義も受けていたのにweb問を1問も解けなかったのが残念でした。久しぶりのCTFでしたが全体的に難しすぎない良い感じの問題が多かったので楽しめました。同じ大学の同期や後輩も参加していましたが、みんな楽しめたようで良かったです。