もいんもいん

ゆっぴぃ(Yuppy_orz)のメモ書き

SECCON 2014 横浜大会 バイナリ組 write-up

SECCON 2014 横浜大会に参加してきました。 バイナリ後半組、4問目で予選通過。 決勝リーグで早々と振り落とされるかと思いきや、運良く決勝まで残れました。 決勝にて早押しクイズで敗退。

後半組 1問目(10.zip) - まだ解けていません

オークション負け。 見守る。 カセットビジョンテニス(縦横反転)で勝てばフラグが表示されるらしい。 挑戦者はその場でうさみみハリケーンをダウンロードして会場を沸かせてました。

オークション時間が切れ、挑戦開始。最近kusano_kさんの日記で知ったx64_dbgにて解析開始。 このツール、64bit対応しているのはいいのだけどまだ品質がこなれておらず、step/nextで追いかけ中 落ちることがままあり。今回もデバッガ内で追いかけ中、点数が入った後落ちる。うーむollydbgに戻すか。ん? 再発? って犯人はIsDebuggerPresentか!というのに気づいたところで時間切れ。弱いな俺。ジャンル間違った感ひしひし。

後半組 2問目(04.txt) - 負け
00201000 >/$ 55             PUSH EBP
00201001  |. 8BEC           MOV EBP,ESP
00201003  |. 57             PUSH EDI
00201004  |. 8B7D 08        MOV EDI,DWORD PTR SS:[EBP+8]
00201007  |. 85FF           TEST EDI,EDI
00201009  |. 7E 0D          JLE SHORT 00201018
0020100B  |. 83FF 02        CMP EDI,2
0020100E  |. 7F 08          JG SHORT 00201018
00201010  |. B8 01000000    MOV EAX,1
00201015  |. 5F             POP EDI
00201016  |. 5D             POP EBP
00201017  |. C3             RETN
00201018  |> 8D47 FE        LEA EAX,DWORD PTR DS:[EDI-2]
0020101B  |. 56             PUSH ESI
0020101C  |. 50             PUSH EAX
0020101D  |. E8 DEFFFFFF    CALL 00201000
00201022  |. 4F             DEC EDI
00201023  |. 57             PUSH EDI
00201024  |. 8BF0           MOV ESI,EAX
00201026  |. E8 D5FFFFFF    CALL 00201000
0020102B  |. 83C4 08        ADD ESP,8
0020102E  |. 03C6           ADD EAX,ESI
00201030  |. 5E             POP ESI
00201031  |. 5F             POP EDI
00201032  |. 5D             POP EBP
00201033  \. C3             RETN
00201034     CC             INT3
00201040 >/$ 6A 2E          PUSH 2E
00201042  |. E8 B9FFFFFF    CALL 00201000
00201047  |. 6A 2D          PUSH 2D
00201049  |. 8BC8           MOV ECX,EAX
0020104B  |. E8 B0FFFFFF    CALL 00201000
00201050  |. 03C8           ADD ECX,EAX
00201052  |. 51             PUSH ECX
00201053  |. 68 F4202000    PUSH OFFSET format = "Key: %lu"
00201058  |. FF15 A0202000  CALL DWORD PTR DS:[<&MSVCR100.printf>]
0020105E  |. 83C4 10        ADD ESP,10
00201061  |. 33C0           XOR EAX,EAX
00201063  \. C3             RETN

オークション負け。見守る。コード部分ブロック範囲指定、Immunity Debuggerに流し込んでいる模様。手慣れてるなあ。

オークション時間が切れ、挑戦開始。同じように真ん中のコード部分をブロック範囲指定、デバッガに流し込み。普通に先頭から実行しただけでは動かないので 後半部分から実行されるような位置になるよう調整。(エントリポイントが後半であるようなヒントも出てた) ジャンプ先が前半部分のアドレスよりも低いアドレスとなるようなので、そこから実際のコードまでを全部0x90(NOP)で つぶして実行。動くようになる。けどprintfのところで落ちる。あーprintfのアドレスを実際のアドレスに変えないと動かないなー、とか考えてしまい printfのアドレスを探そうとしている途中に回答されてしまい終了。落ち着いて考えるとprintf呼ぶ直前にブレークしてレジスタの中身みればいいだけじゃん…。実際は緊張してこんなもんです。

後半組 3問目(06.zip) - 負け

オークション負け。見守る。暗号化前のテキストを復元せよ。前で解いてる方がIDAに突っ込むとfreadの文字、0x40の文字が 見える。ファイルサイズも64バイト。64バイト=512ビットということでSHA-512逆算か?とか一瞬身構えてしまうが画面上にCrypto系の関数名は見当たらず、コードもそれほど長くない。出力も64バイト。なんだ単なるテーブル変換か、とあたりをつける。

オークション時間が切れ、挑戦開始。処理予想通り。早々にテーブルを見つけ出し、切り出して逆変換コードを作成している間に回答されてしまい終了。うーむ。この手の処理は普段だと「1からつくってもすぐ」みたいな感覚があるからわざわざ持ち歩かないけど、こういう時間争いの場面では必要なんだな。反省。

後半組 4問目(02.exe) - 勝ち

オークション勝利。とりあえず壁紙を単色に変えてから前に出て投影。時間がかかる計算処理になっているそうな。解析開始。 とりあえずollydbgに食わせると共に、VMwareUbuntuからfile、upx -d、hexdump -C、objdump -d、strings等により難読化されていない普通のPEバイナリであり、鍵はそのままでは見えないことを確認する。(前半戦でupxされてた問題があった)

00E71000  /$ 53             PUSH EBX
00E71001  |. 56             PUSH ESI
00E71002  |. 57             PUSH EDI
00E71003  |. BE 01000000    MOV ESI,1
00E71008  |. 33DB           XOR EBX,EBX
00E7100A  |. 8D9B 00000000  LEA EBX,DWORD PTR DS:[EBX]
00E71010  |> 33FF           /XOR EDI,EDI
00E71012  |. 8D4F 01        |LEA ECX,DWORD PTR DS:[EDI+1]
00E71015  |. 3BF1           |CMP ESI,ECX
00E71017  |. 7C 1C          |JL SHORT 02.00E71035
00E71019  |. 8DA424 0000000>|LEA ESP,DWORD PTR SS:[ESP]
00E71020  |> 8BC6           |/MOV EAX,ESI
00E71022  |. 99             ||CDQ
00E71023  |. F7F9           ||IDIV ECX
00E71025  |. 85D2           ||TEST EDX,EDX
00E71027  |. 75 01          ||JNZ SHORT 02.00E7102A
00E71029  |. 47             ||INC EDI
00E7102A  |> 41             ||INC ECX
00E7102B  |. 3BCE           ||CMP ECX,ESI
00E7102D  |.^7E F1          |\JLE SHORT 02.00E71020
00E7102F  |. 83FF 02        |CMP EDI,2
00E71032  |. 75 01          |JNZ SHORT 02.00E71035
00E71034  |. 43             |INC EBX
00E71035  |> 46             |INC ESI
00E71036     81FB 80969800  |CMP EBX,989680
00E7103C  |.^7C D2          \JL SHORT 02.00E71010
00E7103E  |. 4E             DEC ESI
00E7103F  |. 56             PUSH ESI                                 ; /<%d>
00E71040  |. 68 F420E700    PUSH 02.00E720F4                         ; |format = "Key: %d"
00E71045  |. FF15 A420E700  CALL DWORD PTR DS:[<&MSVCR100.printf>]   ; \printf
00E7104B  |. 83C4 08        ADD ESP,8
00E7104E  |. FF15 9C20E700  CALL DWORD PTR DS:[<&MSVCR100.getchar>]  ; [getchar
00E71054  |. 5F             POP EDI
00E71055  |. 5E             POP ESI
00E71056  |. 33C0           XOR EAX,EAX
00E71058  |. 5B             POP EBX
00E71059  \. C3             RETN

該当処理は上のような感じ。どう見ても二重ループなので確かに遅そう。緊張してるのでCDQとかIDIVとか意味ど忘れ(超弱い)。とりあえずF8を押しっぱなしにしてレジスタの変化を見守る。処理の加速度的な落ち方を見て素数判定系とピンとくる。終了条件は0x989680、関数電卓に突っ込むと10,000,000(ゼロ7個)。

10,000,000以下の最大素数? と早とちりして回答を試み誤答。思考停止。ふたたびF8押しっぱなしとかして気を落ち着かせる。

数がでかいから遅い系の処理なのであれば、終了条件の数値が小さければ答えが出るのでは?と思いつき、バイナリエディタで0x989690(10,000,000)を0x03E8(1000)に書き換えたもの・0x2710(10000)に書き換えたもの処理をすることを思いつく。前者が数秒で答えが出る。7919。後者の答えは出ない。

スマホgoogle先生に聞くことにする。「1000 7919」で検索し「1000番目の素数」という文章を得る。これだ!と思い10,000,000番目の素数google先生に聞く。しかしそのものズバリの回答は得られず、近似方法とかアルゴリズムとかしか出てこない。焦っているのでタイプミス(ゼロの数間違う)とかもする。回答でてきた。179424673。そうこうしているうちに出題者からヒントが出始める。「これは実は素数の…」。うーわー。もうわかってるのにーやめてーーー

ヒント読み上げ中にノートへの回答転記が終わり、挙手して回答。正答。字汚くてスミマセンでした。

後半組 5問目(00.zip) - 配布無し、回答せず

サービス問題らしい。前に出た人が回答しちゃったので問題は取得できていません。コマンドラインに引数指定して実行するとkeyが出る系の何か。というか放心状態だったのでよく覚えていません。