セキュキャンCTF equations, hidden のWriteup
昨日に引き続き、セキュリティキャンプ全国大会2016で開催されたCTFの話題です。 当日手を付けて、解けなかった問題2つ equations と hidden をピックアップしてWriteupを書きます。
equations
i386のバイナリのようなので逆コンパイラ(貧乏人用)に突っ込みます。
こんな結果を得られました。
# 自分が当日になぜこの作業をしなかったのか謎い…
// Address range: 0x804847d - 0x8048547 int main(int argc, char ** argv) { int32_t v1 = (int32_t)argv; // 0x80484ab_0 if (argc <= 3) { // 0x804848c printf("Usage %s <a> <b> <c>\n", (char *)*(int32_t *)argv); // branch -> 0x8048546 // 0x8048546 return -1; } int32_t str_as_i = atoi((char *)*(int32_t *)(v1 + 4)); // 0x80484b6 int32_t str_as_i2 = atoi((char *)*(int32_t *)(v1 + 8)); // 0x80484ca int32_t str_as_i3 = atoi((char *)*(int32_t *)(v1 + 12)); // 0x80484de if (check(str_as_i, str_as_i2, str_as_i3) == 0) { // 0x8048535 puts("Wrong key..."); // branch -> 0x8048546 } else { // 0x8048507 printf("Congratz! flag is FLAG{%d}\n", calc_flag(str_as_i, str_as_i2, str_as_i3)); // branch -> 0x8048546 } // 0x8048546 return 0; } // Address range: 0x8048548 - 0x80485c4 int32_t check(int32_t a1, int32_t a2, int32_t a3) { int32_t result = 0; // 0x80485c4_2 if (5 * a2 + 3 * a1 == -4 * a3) { // 0x8048575 if (2 * (2 * a2 + a1) == -5 * a3) { // 0x804859a result = -8 * a3 == a2 - a1; // branch -> 0x80485c3 } else { result = 0; } } // 0x80485c3 return result; }
コードを見ると3元1次方程式の存在を確認できます。
考えるのも無駄なので Mathematica(貧乏人用) に突っ込んで終わりです。
# 3つ目の式は無くても解が変わらないというね…
Solve[{3x + 5y + 4z = 0, 2x + 4y + 5z = 0, x - y - 8z = 0}, {x,y,z}]
で、解が不定になってしまいましたが、xを特定の値に縛ることをバイナリがしてないのでフラグが1つに定まりません。 ここで終わりにします。
@K_atc この問題の連立方程式から求まった解を,一つに定めるためのルーチンを書いていたのですが,本番バイナリにそれが含まれていないことに後ほど気が付きました
— 【しふくろ】友利奈緒㌠ (@shift_crops) 2016年8月28日
ごめんなさい🙇
想定解は9 -7 2を与えた時のものです
hidden
バイナリが64ビットで、貧乏人用デコンパイラが使えないので、objdumpとテキストエディタで頑張りました。 といっても長くないので検討をつけやすいです。
見るべき箇所は main
での genflag
の呼び出しと、 genflag
の中身です。
何をしているのかは下のpythonスクリプトを見て感じ取ってください。
0000000000400ee0 <main>: 400ee0: 55 push rbp 400ee1: 48 89 e5 mov rbp,rsp 400ee4: 48 81 ec 20 02 00 00 sub rsp,0x220 400eeb: 64 48 8b 04 25 28 00 mov rax,QWORD PTR fs:0x28 400ef2: 00 00 400ef4: 48 89 45 f8 mov QWORD PTR [rbp-0x8],rax 400ef8: 31 c0 xor eax,eax 400efa: 48 c7 85 e0 fd ff ff mov QWORD PTR [rbp-0x220],0x401111 # "flag : %s" 400f01: 11 11 40 00 400f05: 48 c7 85 e8 fd ff ff mov QWORD PTR [rbp-0x218],0x40111c # "You cannot get flag! Hahaha\n" 400f0c: 1c 11 40 00 400f10: bf 39 11 40 00 mov edi,0x401139 # "== HiddenFlag ==\n" 400f15: e8 46 fa ff ff call 400960 <puts@plt> # puts("== HiddenFlag ==\n") 400f1a: 48 8d 85 f0 fd ff ff lea rax,[rbp-0x210] 400f21: be 00 02 00 00 mov esi,0x200 # 0x200 400f26: 48 89 c7 mov rdi,rax # [rbp-0x8] 400f29: b8 00 00 00 00 mov eax,0x0 # retval 400f2e: e8 34 00 00 00 call 400f67 <genflag> # genflag([rbp-0x8], 0x200) 400f33: 48 8b 85 e0 fd ff ff mov rax,QWORD PTR [rbp-0x220] # "flag : %s" 400f3a: 48 8d 95 f0 fd ff ff lea rdx,[rbp-0x210] # = flag 400f41: 48 89 d6 mov rsi,rdx # [rbp-0x210] 400f44: 48 89 c7 mov rdi,rax # arg0 400f47: b8 00 00 00 00 mov eax,0x0 # retval 400f4c: e8 df f9 ff ff call 400930 <printf@plt> # printf("flag : %s", [rbp-0x210]) # => printf("You cannot get flag! Hahaha\n") 400f51: 48 8b 4d f8 mov rcx,QWORD PTR [rbp-0x8] 400f55: 64 48 33 0c 25 28 00 xor rcx,QWORD PTR fs:0x28 # check stack canary 400f5c: 00 00 400f5e: 74 05 je 400f65 <main+0x85> #--------------------------------------------------------------------- 400f60: e8 6b fa ff ff call 4009d0 <__stack_chk_fail@plt> 400f65: c9 leave 400f66: c3 ret
from ctypes import CDLL libc = CDLL('libc.so.6') arr = [ 0x21, 0x8a, 0x28, 0x34, 0x2a, 0xca, 0x7b, 0x81, 0x59, 0xa1, 0x89, 0xf4, 0x91, 0xca, 0x93, 0x2e, 0x4f, 0xb0, 0xb, 0xf8, 0x0, 0x0, 0x0, 0x0 ] arr2 = [ 0x10, 0xf7, 0x5e, 0x1b, 0xe, 0xca, 0x7d, 0x9e, 0x1d, 0xa3, 0xdd, 0x98, 0xad, 0x96, 0xd0, 0x25, 0x14, 0xf6, 0x3a, 0xc9, 0x2e, 0x85, 0x9a, 0x8d ] libc.srand(0) for i in range(0x18): arr[i] ^= (0xff & libc.rand()) libc.srand(0) for i in range(0x18): arr2[i] ^= (0xff & libc.rand()) flag = ''.join(map(lambda x: chr(x), arr)) flag += ''.join(map(lambda x: chr(x), arr2)) print(flag) """ [katc@K_atc seccamp-2016]$ python hidden.py FLAG{51mpl3_c1ph3r_çw17h_57r4ng3_m3ch4n15m} """ """ 0000000000400f67 <genflag>: 400f67: 55 push rbp 400f68: 48 89 e5 mov rbp,rsp 400f6b: 41 54 push r12 400f6d: 53 push rbx 400f6e: 48 83 ec 40 sub rsp,0x40 400f72: 48 89 7d b8 mov QWORD PTR [rbp-0x48],rdi # [rbp-0x48] := [rbp-0x8] 400f76: 89 75 b4 mov DWORD PTR [rbp-0x4c],esi # [rbp-0x4c] := 0x200 400f79: 64 48 8b 04 25 28 00 mov rax,QWORD PTR fs:0x28 400f80: 00 00 400f82: 48 89 45 e8 mov QWORD PTR [rbp-0x18],rax 400f86: 31 c0 xor eax,eax 400f88: c6 45 d0 21 mov BYTE PTR [rbp-0x30],0x21 # arr[0] 400f8c: c6 45 d1 8a mov BYTE PTR [rbp-0x2f],0x8a # arr[1] 400f90: c6 45 d2 28 mov BYTE PTR [rbp-0x2e],0x28 # ... 400f94: c6 45 d3 34 mov BYTE PTR [rbp-0x2d],0x34 400f98: c6 45 d4 2a mov BYTE PTR [rbp-0x2c],0x2a 400f9c: c6 45 d5 ca mov BYTE PTR [rbp-0x2b],0xca 400fa0: c6 45 d6 7b mov BYTE PTR [rbp-0x2a],0x7b 400fa4: c6 45 d7 81 mov BYTE PTR [rbp-0x29],0x81 400fa8: c6 45 d8 59 mov BYTE PTR [rbp-0x28],0x59 400fac: c6 45 d9 a1 mov BYTE PTR [rbp-0x27],0xa1 400fb0: c6 45 da 89 mov BYTE PTR [rbp-0x26],0x89 400fb4: c6 45 db f4 mov BYTE PTR [rbp-0x25],0xf4 400fb8: c6 45 dc 91 mov BYTE PTR [rbp-0x24],0x91 400fbc: c6 45 dd ca mov BYTE PTR [rbp-0x23],0xca 400fc0: c6 45 de 93 mov BYTE PTR [rbp-0x22],0x93 400fc4: c6 45 df 2e mov BYTE PTR [rbp-0x21],0x2e 400fc8: c6 45 e0 4f mov BYTE PTR [rbp-0x20],0x4f 400fcc: c6 45 e1 b0 mov BYTE PTR [rbp-0x1f],0xb0 400fd0: c6 45 e2 0b mov BYTE PTR [rbp-0x1e],0xb 400fd4: c6 45 e3 f8 mov BYTE PTR [rbp-0x1d],0xf8 400fd8: c6 45 e4 00 mov BYTE PTR [rbp-0x1c],0x0 400fdc: c6 45 e5 00 mov BYTE PTR [rbp-0x1b],0x0 400fe0: c6 45 e6 00 mov BYTE PTR [rbp-0x1a],0x0 400fe4: c6 45 e7 00 mov BYTE PTR [rbp-0x19],0x0 # arr[0x17] 400fe8: 8b 45 b4 mov eax,DWORD PTR [rbp-0x4c] 400feb: 83 f8 18 cmp eax,0x18 400fee: 76 07 jbe 400ff7 <genflag+0x90> #--------------------------------------------------------------------- 400ff0: c7 45 b4 18 00 00 00 mov DWORD PTR [rbp-0x4c],0x18 # [rbp-0x4c] := 0x18 #--------------------------------------------------------------------- 400ff7: bf 00 00 00 00 mov edi,0x0 # 0 400ffc: e8 ef f9 ff ff call 4009f0 <srand@plt> # srand(0) 401001: c7 45 cc 00 00 00 00 mov DWORD PTR [rbp-0x34],0x0 # [rbp-0x34] = 0 # i := [rbp-0x34] 401008: eb 27 jmp 401031 <genflag+0xca> #===================================================================== 40100a: 8b 45 cc mov eax,DWORD PTR [rbp-0x34] # arr[i] = [rbp-0x34] 40100d: 48 63 d0 movsxd rdx,eax 401010: 48 8b 45 b8 mov rax,QWORD PTR [rbp-0x48] 401014: 48 8d 1c 02 lea rbx,[rdx+rax*1] # rbx := [i + [rbp-0x48]] 401018: 8b 45 cc mov eax,DWORD PTR [rbp-0x34] 40101b: 48 98 cdqe 40101d: 44 0f b6 64 05 d0 movzx r12d,BYTE PTR [rbp-0x30+rax*1] # r12d := arr[i] 401023: e8 f8 f9 ff ff call 400a20 <rand@plt> # rand() 401028: 44 31 e0 xor eax,r12d # arr[i] ^= char(rand()) 40102b: 88 03 mov BYTE PTR [rbx],al 40102d: 83 45 cc 01 add DWORD PTR [rbp-0x34],0x1 # [rbp-0x34] += 1 (i++) #--------------------------------------------------------------------- 401031: 8b 45 cc mov eax,DWORD PTR [rbp-0x34] 401034: 3b 45 b4 cmp eax,DWORD PTR [rbp-0x4c] 401037: 7c d1 jl 40100a <genflag+0xa3> # [rbp-0x34] < 0x18 #--------------------------------------------------------------------- """ """ [katc@K_atc seccamp-2016]$ gdb -q hidden gdb-peda$ b printf gdb-peda$ r gdb-peda$ disas genflag Dump of assembler code for function genflag: 0x0000000000400f67 <+0>: push rbp 0x0000000000400f68 <+1>: mov rbp,rsp 0x0000000000400f6b <+4>: push r12 0x0000000000400f6d <+6>: push rbx 0x0000000000400f6e <+7>: sub rsp,0x40 0x0000000000400f72 <+11>: mov QWORD PTR [rbp-0x48],rdi # [rbp-0x48] := [rbp-0x8] 0x0000000000400f76 <+15>: mov DWORD PTR [rbp-0x4c],esi 0x0000000000400f79 <+18>: mov rax,QWORD PTR fs:0x28 0x0000000000400f82 <+27>: mov QWORD PTR [rbp-0x18],rax 0x0000000000400f86 <+31>: xor eax,eax 0x0000000000400f88 <+33>: mov BYTE PTR [rbp-0x30],0x10 0x0000000000400f8c <+37>: mov BYTE PTR [rbp-0x2f],0xf7 0x0000000000400f90 <+41>: mov BYTE PTR [rbp-0x2e],0x5e 0x0000000000400f94 <+45>: mov BYTE PTR [rbp-0x2d],0x1b 0x0000000000400f98 <+49>: mov BYTE PTR [rbp-0x2c],0xe 0x0000000000400f9c <+53>: mov BYTE PTR [rbp-0x2b],0xca 0x0000000000400fa0 <+57>: mov BYTE PTR [rbp-0x2a],0x7d 0x0000000000400fa4 <+61>: mov BYTE PTR [rbp-0x29],0x9e 0x0000000000400fa8 <+65>: mov BYTE PTR [rbp-0x28],0x1d 0x0000000000400fac <+69>: mov BYTE PTR [rbp-0x27],0xa3 0x0000000000400fb0 <+73>: mov BYTE PTR [rbp-0x26],0xdd 0x0000000000400fb4 <+77>: mov BYTE PTR [rbp-0x25],0x98 0x0000000000400fb8 <+81>: mov BYTE PTR [rbp-0x24],0xad 0x0000000000400fbc <+85>: mov BYTE PTR [rbp-0x23],0x96 0x0000000000400fc0 <+89>: mov BYTE PTR [rbp-0x22],0xd0 0x0000000000400fc4 <+93>: mov BYTE PTR [rbp-0x21],0x25 0x0000000000400fc8 <+97>: mov BYTE PTR [rbp-0x20],0x14 0x0000000000400fcc <+101>: mov BYTE PTR [rbp-0x1f],0xf6 0x0000000000400fd0 <+105>: mov BYTE PTR [rbp-0x1e],0x3a 0x0000000000400fd4 <+109>: mov BYTE PTR [rbp-0x1d],0xc9 0x0000000000400fd8 <+113>: mov BYTE PTR [rbp-0x1c],0x2e 0x0000000000400fdc <+117>: mov BYTE PTR [rbp-0x1b],0x85 0x0000000000400fe0 <+121>: mov BYTE PTR [rbp-0x1a],0x9a 0x0000000000400fe4 <+125>: mov BYTE PTR [rbp-0x19],0x8d 0x0000000000400fe8 <+129>: mov eax,DWORD PTR [rbp-0x4c] 0x0000000000400feb <+132>: cmp eax,0x18 0x0000000000400fee <+135>: jbe 0x400ff7 <genflag+144> #--------------------------------------------------------------------- 0x0000000000400ff0 <+137>: mov DWORD PTR [rbp-0x4c],0x18 0x0000000000400ff7 <+144>: mov edi,0x0 # 0 0x0000000000400ffc <+149>: call 0x4009f0 <srand@plt> # srand(0) 0x0000000000401001 <+154>: mov DWORD PTR [rbp-0x34],0x0 # i = 0 0x0000000000401008 <+161>: jmp 0x401031 <genflag+202> #===================================================================== 0x000000000040100a <+163>: mov eax,DWORD PTR [rbp-0x34] 0x000000000040100d <+166>: movsxd rdx,eax 0x0000000000401010 <+169>: mov rax,QWORD PTR [rbp-0x48] # rax := ? 0x0000000000401014 <+173>: lea rbx,[rdx+rax*1] 0x0000000000401018 <+177>: mov eax,DWORD PTR [rbp-0x34] 0x000000000040101b <+180>: cdqe 0x000000000040101d <+182>: movzx r12d,BYTE PTR [rbp+rax*1-0x30] 0x0000000000401023 <+188>: call 0x400a20 <rand@plt> 0x0000000000401028 <+193>: xor eax,r12d 0x000000000040102b <+196>: mov BYTE PTR [rbx],al 0x000000000040102d <+198>: add DWORD PTR [rbp-0x34],0x1 # i++ #--------------------------------------------------------------------- 0x0000000000401031 <+202>: mov eax,DWORD PTR [rbp-0x34] 0x0000000000401034 <+205>: cmp eax,DWORD PTR [rbp-0x4c] 0x0000000000401037 <+208>: jl 0x40100a <genflag+163> #--------------------------------------------------------------------- """
ブレークポイントが打てないし、printfの出力がobjdumpと食い違っていたのですが、何らかの仕組みが働いてコードが書き換わるようです。 フラグが前後半に分かれて出現します。前半は実行前のコード、後半はprintf呼び出し時に見ることができます。 てなわけで、
flag: FLAG{51mpl3_c1ph3r_çw17h_57r4ng3_m3ch4n15m}
明日、また会社かよ…
(報告)Docker版の方はARMのrev問が動くようになりましたー