AlexCTF 供養(Writeup)
AlexCTFに参加。990ptで259位。
TR1: Hello there (Trivia 10)
IRCのチャンネル名にフラグがある。
IRC: #alexctf @freenode
#alexctf: Alexandria University student held capture the flag event ctf.oddcoder.com ALEXCTF{W3_w15h_y0u_g00d_luck}
TR2: SSL 0day (Trivia 20)
It lead to memory leakage between servers and clients rending large number of private keys accessible. (one word)
heartbleed
TR3: CA (Trivia 30)
What is the CA that issued Alexctf https certificate (flag is lowercase with no spaces)
letsencrypt
TR4: Doesn’t our logo look cool ? (Trivia 40)
トップページにあるアスキーアートのロゴの中にある。
$ grep -oP '[\w{}]' logo.txt | tr -d '\n' ALEXCTF{0UR_L0G0_R0CKS}
RE1: Gifted (Reversing 50)
stringsするとフラグがある。
$ strings gifted (snip) Enter the flag: AlexCTF{Y0u_h4v3_45t0n15h1ng_futur3_1n_r3v3r5ing} You got it right dude! Try harder! (snip)
RE2: C++ is awesome (Reversing 100)
特定のアドレスで動作を止めてメモリに入っているデータを見ると、文字列と数字の配列がある。
$ gdb --args ./re2 AAAA Reading symbols from ./re2...(no debugging symbols found)...done. (gdb) b *0x400c24 Breakpoint 1 at 0x400c24 (gdb) r Starting program: /tmp/re2 AAAA Breakpoint 1, 0x0000000000400c24 in ?? () 1: x/i $pc => 0x400c24: lea rax,[rbp-0x50] (gdb) x/80i $pc => 0x400c24: lea rax,[rbp-0x50] 0x400c28: mov rdi,rax 0x400c2b: call 0x4009f0 <std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::end()@plt> 0x400c30: mov QWORD PTR [rbp-0x20],rax 0x400c34: lea rdx,[rbp-0x20] 0x400c38: lea rax,[rbp-0x60] 0x400c3c: mov rsi,rdx 0x400c3f: mov rdi,rax 0x400c42: call 0x400d3d 0x400c47: test al,al 0x400c49: je 0x400c95 0x400c4b: lea rax,[rbp-0x60] 0x400c4f: mov rdi,rax 0x400c52: call 0x400d9a 0x400c57: movzx edx,BYTE PTR [rax] 0x400c5a: mov rcx,QWORD PTR [rip+0x20143f] # 0x6020a0 0x400c61: mov eax,DWORD PTR [rbp-0x14] 0x400c64: cdqe 0x400c66: mov eax,DWORD PTR [rax*4+0x6020c0] 0x400c6d: cdqe (snip) (gdb) x/s {long}0x6020a0 0x400e58: "L3t_ME_T3ll_Y0u_S0m3th1ng_1mp0rtant_A_{FL4G}_W0nt_b3_3X4ctly_th4t_345y_t0_c4ptur3_H0wev3r_1T_w1ll_b3_C00l_1F_Y0u_g0t_1t" (gdb) x/80wx 0x6020c0 0x6020c0: 0x00000024 0x00000000 0x00000005 0x00000036 0x6020d0: 0x00000065 0x00000007 0x00000027 0x00000026 0x6020e0: 0x0000002d 0x00000001 0x00000003 0x00000000 0x6020f0: 0x0000000d 0x00000056 0x00000001 0x00000003 0x602100: 0x00000065 0x00000003 0x0000002d 0x00000016 0x602110: 0x00000002 0x00000015 0x00000003 0x00000065 0x602120: 0x00000000 0x00000029 0x00000044 0x00000044 0x602130: 0x00000001 0x00000044 0x0000002b 0x00000000 0x602140 <std::cout>: 0xf7dce988 0x00007fff 0xf7dce9b0 0x00007fff (snip) (gdb) q A debugging session is active. Inferior 1 [process 11607] will be killed. Quit anyway? (y or n) y
数字の配列の順で文字列から文字を取り出すとフラグが得られる。
msg = "L3t_ME_T3ll_Y0u_S0m3th1ng_1mp0rtant_A_{FL4G}_W0nt_b3_3X4ctly_th4t_345y_t0_c4ptur3_H0wev3r_1T_w1ll_b3_C00l_1F_Y0u_g0t_1t" ary = [0x24, 0x0, 0x5, 0x36, 0x65, 0x7, 0x27, 0x26, 0x2d, 0x1, 0x3, 0x0, 0xd, 0x56, 0x1, 0x3, 0x65, 0x3, 0x2d, 0x16, 0x2, 0x15, 0x3, 0x65, 0x0, 0x29, 0x44, 0x44, 0x1, 0x44, 0x2b, 0x0] s = '' for i in ary: s += msg[i] print s
$ python test.py ALEXCTF{W3_L0v3_C_W1th_CL45535}L
RE4: unVM me (Reversing 250)
「HITCON CTF 2016 Quals 供養(Writeup)」で使ったshow_file.pyでディスアセンブルすると、5文字ごとに特定のmd5ハッシュ値と一致しているかを見ていることがわかる。
2 12 LOAD_CONST 2 (174282896860968005525213562254350376167L) 15 LOAD_CONST 3 (137092044126081477479435678296496849608L) 18 LOAD_CONST 4 (126300127609096051658061491018211963916L) 21 LOAD_CONST 5 (314989972419727999226545215739316729360L) 24 LOAD_CONST 6 (256525866025901597224592941642385934114L) 27 LOAD_CONST 7 (115141138810151571209618282728408211053L) 30 LOAD_CONST 8 (8705973470942652577929336993839061582L) 33 LOAD_CONST 9 (256697681645515528548061291580728800189L) 36 LOAD_CONST 10 (39818552652170274340851144295913091599L) 39 LOAD_CONST 11 (65313561977812018046200997898904313350L) 42 LOAD_CONST 12 (230909080238053318105407334248228870753L) 45 LOAD_CONST 13 (196125799557195268866757688147870815374L) 48 LOAD_CONST 14 (74874145132345503095307276614727915885L) 51 BUILD_LIST 13 54 STORE_NAME 1 (md5s) (snip) 12 >> 144 SETUP_LOOP 112 (to 259) 147 LOAD_NAME 6 (range) 150 LOAD_CONST 20 (0) 153 LOAD_NAME 4 (len) 156 LOAD_NAME 3 (flag) 159 CALL_FUNCTION 1 162 LOAD_CONST 19 (5) 165 CALL_FUNCTION 3 168 GET_ITER >> 169 FOR_ITER 86 (to 258) 172 STORE_NAME 7 (i) 13 175 LOAD_NAME 3 (flag) 178 LOAD_NAME 7 (i) 181 LOAD_NAME 7 (i) 184 LOAD_CONST 19 (5) 187 BINARY_ADD 188 SLICE+3 189 STORE_NAME 8 (s) 14 192 LOAD_NAME 9 (int) 195 LOAD_CONST 21 ('0x') 198 LOAD_NAME 0 (md5) 201 LOAD_ATTR 10 (new) 204 LOAD_NAME 8 (s) 207 CALL_FUNCTION 1 210 LOAD_ATTR 11 (hexdigest) 213 CALL_FUNCTION 0 216 BINARY_ADD 217 LOAD_CONST 22 (16) 220 CALL_FUNCTION 2 223 LOAD_NAME 1 (md5s) 226 LOAD_NAME 7 (i) 229 LOAD_CONST 19 (5) 232 BINARY_DIVIDE 233 BINARY_SUBSCR 234 COMPARE_OP 3 (!=) 237 POP_JUMP_IF_FALSE 169
文字種をいろいろ変えながらブルートフォースすると元の文字列が求まる。
from itertools import product from hashlib import md5 hashes = [ (174282896860968005525213562254350376167L), # md5('ALEXC') (137092044126081477479435678296496849608L), # md5('TF{dv') (126300127609096051658061491018211963916L), # md5('5d4s2') (314989972419727999226545215739316729360L), # md5('vj8nk') (256525866025901597224592941642385934114L), # md5('43s8d') (115141138810151571209618282728408211053L), # md5('8l6m1') (8705973470942652577929336993839061582L), # md5('n5l67') (256697681645515528548061291580728800189L), # md5('ds9v4') (39818552652170274340851144295913091599L), # md5('1n52n') (65313561977812018046200997898904313350L), # md5('v37j4') (230909080238053318105407334248228870753L), # md5('81h3d') (196125799557195268866757688147870815374L), # md5('28n4b') (74874145132345503095307276614727915885L) # md5('6v3k}') ] """ chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' for t in product(chars, repeat=5): x = ''.join(t) h = md5(x).hexdigest() h = int(h, 16) if h in hashes: print "%d == md5(%r)" % (h, x) """ """ chars = 'abcdefghijklmnopqrstuvwxyz0123456789' for t in product(chars, repeat=2): x = 'TF{' + ''.join(t) h = md5(x).hexdigest() h = int(h, 16) if h in hashes: print "%d == md5(%r)" % (h, x) """ """ chars = 'abcdefghijklmnopqrstuvwxyz0123456789' for t in product(chars, repeat=5): x = ''.join(t) h = md5(x).hexdigest() h = int(h, 16) if h in hashes: print "%d == md5(%r)" % (h, x) """ chars = 'abcdefghijklmnopqrstuvwxyz0123456789' for t in product(chars, repeat=4): x = ''.join(t) + '}' h = md5(x).hexdigest() h = int(h, 16) if h in hashes: print "%d == md5(%r)" % (h, x) # ALEXCTF{dv5d4s2vj8nk43s8d8l6m1n5l67ds9v41n52nv37j481h3d28n4b6v3k}
CR1: Ultracoded (Cryptography 50)
与えられたテキストを適当に変換すると、モールス信号を表す文字列が得られる。
data = open('zero_one').read() s = '' for x in data.split(): if x == 'ZERO': s += '0' else: s += '1' s = "%x" % int(s, 2) s = s.decode('hex') s = s.decode('base64') print s
$ python test.py .- .-.. . -..- -.-. - ..-. - .... .---- ..... --- .---- ... --- ..... ..- .--. ...-- .-. --- ..... . -.-. .-. ...-- - --- - -..- -
Morse Code Translator等で復号した文字列を適当に変換するとフラグが得られる。
ALEXCTFTH15O1SO5UP3RO5ECR3TOTXT ALEXCTF{TH15_1S_5UP3R_5ECR3T_TXT}
CR3: What is this encryption? (Cryptography 150)
「OpenSSLとPythonでRSA暗号の原理を知る」と同様に、RSAの復号を行うだけ。
p=0xa6055ec186de51800ddd6fcbf0192384ff42d707a55f57af4fcfb0d1dc7bd97055e8275cd4b78ec63c5d592f567c66393a061324aa2e6a8d8fc2a910cbee1ed9 q=0xfa0f9463ea0a93b929c099320d31c277e0b0dbc65b189ed76124f5a1218f5d91fd0102a4c8de11f28be5e4d0ae91ab319f4537e97ed74bc663e972a4a9119307 e=0x6d1fdab4ce3217b3fc32c9ed480a31d067fd57d93a9ab52b472dc393ab7852fbcb11abbebfd6aaae8032db1316dc22d3f7c3d631e24df13ef23d3b381a1c3e04abcc745d402ee3a031ac2718fae63b240837b4f657f29ca4702da9af22a3a019d68904a969ddb01bcf941df70af042f4fae5cbeb9c2151b324f387e525094c41 c=0x7fe1a4f743675d1987d25d38111fae0f78bbea6852cba5beda47db76d119a3efe24cb04b9449f53becd43b0b46e269826a983f832abb53b7a7e24a43ad15378344ed5c20f51e268186d24c76050c1e73647523bd5f91d9b6ad3e86bbf9126588b1dee21e6997372e36c3e74284734748891829665086e0dc523ed23c386bb520 def egcd(a, b): x,y, u,v = 0,1, 1,0 while a != 0: q,r = b//a,b%a; m,n = x-u*q,y-v*q b,a, x,y, u,v = a,r, u,v, m,n return b, x, y def modinv(a, m): g, x, y = egcd(a, m) if g != 1: return None # modular inverse does not exist else: return x % m d = modinv(e, (p-1)*(q-1)) m = pow(c, d, p*q) m = "%x" % m print m.decode('hex')
$ python test.py ALEXCTF{RS4_I5_E55ENT1AL_T0_D0_BY_H4ND}
Fore1: Hit the core (Forensics 50)
stringsすると長い文字列が見つかる。
$ strings fore1.core (snip) cvqAeqacLtqazEigwiXobxrCrtuiTzahfFreqc{bnjrKwgk83kgd43j85ePgb_e_rwqr7fvbmHjklo3tews_hmkogooyf0vbnk0ii87Drfgh_n kiwutfb0ghk9ro987k5tfb_hjiouo087ptfcv} (snip)
フラグフォーマットをヒントに、一定間隔で文字を拾うとフラグが得られる。
s = 'cvqAeqacLtqazEigwiXobxrCrtuiTzahfFreqc{bnjrKwgk83kgd43j85ePgb_e_rwqr7fvbmHjklo3tews_hmkogooyf0vbnk0ii87Drfgh_n kiwutfb0ghk9ro987k5tfb_hjiouo087ptfcv}' print s[3::5]
$ python test.py ALEXCTF{K33P_7H3_g00D_w0rk_up}
Fore3: USB probing (Forensics 150)
USBのパケットキャプチャファイルが与えられる。 サイズの大きなパケットを探すと、101番のパケットでPNGファイルが転送されているのが見つかる。
ALEXCTF{SN1FF_TH3_FL4G_0V3R_U58}
SC1: Math bot (Scripting 100)
与えられる数式を計算するだけ。evalを使うのは危険だが適当にやってしまった。
from minipwn import * s = socket.create_connection(('195.154.53.62', 1337)) for i in xrange(500): print recvuntil(s, ':\n') x = recvline(s) print x y = eval(x[:-2]) sendline(s, str(y)) interact(s)
$ python test.py __________ ______/ ________ \______ _/ ____________ \_ _/____________ ____________\_ / ___________ \ / ___________ \ / /XXXXXXXXXXX\ \/ /XXXXXXXXXXX\ \ / /############/ \############\ \ | \XXXXXXXXXXX/ _ _ \XXXXXXXXXXX/ | __|\_____ ___ // \\ ___ _____/|__ [_ \ \ X X / / _] __| \ \ / / |__ [____ \ \ \ ____________ / / / ____] \ \ \ \/||.||.||.||.||\/ / / / \_ \ \ ||.||.||.||.|| / / _/ \ \ ||.||.||.||.|| / / \_ ||_||_||_||_|| _/ \ ........ / \________________/ Our system system has detected human traffic from your IP! Please prove you are a bot Question 1 : 51592980733851622235329877819524 % 81337315219774907248751097819108 = Question 2 : 222530311273284491939188931042597 * 5582384329582694587240599887190 = (snip) Question 500 : 223942165497608593390730286109841 - 285025587991694605246774446376485 = Well no human got time to solve 500 ridiculous math challenges Congrats MR bot! Tell your human operator flag is: ALEXCTF{1_4M_l33t_b0t} *** Connection closed by remote host ***
所感
解けなかった問題は以下。
- RE3: Catalyst system (Reversing 150)
- RE5: packed movement (Reversing 350)
- CR2: Many time secrets (Cryptography 100)
- CR4: Poor RSA (Cryptography 200)
- CR5: Bring weakness (Cryptography 300)
- Fore2: Mail client (Forensics 100)
- Fore4: Unknown format (Forensics 200)
- SC2: Cutie cat (Scripting 150)