SECCON 2014 横浜大会 Write-up(バイナリ後半組)
SECCON 2014 横浜大会に出た。バイナリ予選の後半組で予選を通過したが、翌日のクイズ大会で初戦敗退(´・ω・`)
バイナリ予選は前半組と後半組に分けられ、それぞれ5問の問題が1問ずつ出題され、最初に解いた人から抜けていく方式。1人が前に出てプロジェクタに画面を写す代わりに、問題がn分早く配られるという形式だった。最も短いnを提示した人が前に出るオークション形式。他の人が解いている様子を見るのはなかなか面白かった。こういう形式なので、問題は簡単。以下Write-up。
1問目
テニスゲーム。100点先取でゲーム終了でフラグが表示される。ゲームスピードが遅いので100点は待てない。タイトルからVMを解析する面倒な問題かと思ったけど、そんなことはなかった。デバッガで動かしていると、点数が入ったときにプログラムが落ちる。IsDebuggerPresentで検索すると、下記のようなコードがある。
00AB3A39 |> \FF15 94E0BC00 |CALL DWORD PTR DS:[<&KERNEL32.IsDebugge>; [IsDebuggerPresent 00AB3A3F |. 85C0 |TEST EAX,EAX 00AB3A41 |. 0F85 A2000000 |JNZ ScriptGa.00AB3AE9 00AB3A47 |. 8B85 A4FEFFFF |MOV EAX,DWORD PTR SS:[EBP-15C] 00AB3A4D |. 83F8 64 |CMP EAX,64 00AB3A50 |. 7D 25 |JGE SHORT ScriptGa.00AB3A77 00AB3A52 |. 83FF 64 |CMP EDI,64 00AB3A55 |. 7D 20 |JGE SHORT ScriptGa.00AB3A77 00AB3A57 |. 833D 9467F500>|CMP DWORD PTR DS:[F56794],0 00AB3A5E |.^ 0F85 0CFEFFFF \JNZ ScriptGa.00AB3870
都合の良いことに、点数をチェックしているコードも見える。00AB3A41のJNZをNOPにして、00AB3A4Dと00AB3A52の定数を1にすると、点数が入った瞬間にゲームが終了する。その状態でウィンドウを閉じると、キーが表示される。
PlayGame
2問目
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で適当なプログラムを開いて、このプログラムを貼り付けて動かせば良い。エントリポイントが先頭ではなく00201040ということと、00201035-0020103Fが抜けているということに注意。
2971215073
3問目
これが解けて決勝に進めた。
暗号化するプログラムと暗号文が与えられて、暗号化前の文を答える問題。プログラムを読むと入力を並び替えるプログラムだった。逆算すれば良い。
A = "5wonKRJB7y pyTLD90ss VNF=2utrXPH4via QIA6xnseSKC8zro:UME-1titWOG\0" D = [""]*256 T = [ 0x3A, 0x32, 0x2A, 0x22, 0x1A, 0x12, 0x0A, 0x02, 0x3C, 0x34, 0x2C, 0x24, 0x1C, 0x14, 0x0C, 0x04, 0x3E, 0x36, 0x2E, 0x26, 0x1E, 0x16, 0x0E, 0x06, 0x40, 0x38, 0x30, 0x28, 0x20, 0x18, 0x10, 0x08, 0x39, 0x31, 0x29, 0x21, 0x19, 0x11, 0x09, 0x01, 0x3B, 0x33, 0x2B, 0x23, 0x1B, 0x13, 0x0B, 0x03, 0x3D, 0x35, 0x2D, 0x25, 0x1D, 0x15, 0x0D, 0x05, 0x3F, 0x37, 0x2F, 0x27, 0x1F, 0x17, 0x0F, 0x07, ] for i in range(64): D[T[i]] = A[i] print "".join(D)
ABCDEFGHIJKLMNOPQRSTUVWX Key: transposition rstuvwxyz012456789-=
ちなみに、隣の人は暗号文をさらに何度も暗号化して解いていた。なるほど。この操作は置換群だから、有限回の操作で元に戻るし、作問者がそこまで考えていなければ、その回数はそんなに多くなさそう。
transposition
4問目
与えられたプログラムを動かすと答えが出るけど、ものすごく時間がかかるので、なんとかしろ、という問題。プログラムを解析すると処理は以下の通り。
int c = 0; int n = 1; while (true) { int t = 0; for (int i=1; i<=n; i++) if (n%i==0) t++; if (t==2) c++; n++; if (c>=10000000) break; } n--; printf("Key: %d", n);
10000000番目の素数を求めるプログラム。
179424673
5問目
ボーナス問題らしい。前に出た人が解いてしまったので、他の参加者への問題の配付は無し。引数に2014を与えると、
Key: Enjoy_2014
と表示するプログラムだった。
Enjoy_2014