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に食わせると共に、VMwareなUbuntuから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が出る系の何か。というか放心状態だったのでよく覚えていません。