DEF CON CTF Qualifier 2017 write-up
4/29 0:00-5/1 0:00(UTC) に開催されたDEF CON CTF Qualifier 2017で解けた問題のwrite-upです。
チーム名 CTF-infinitとして参加し、43pts獲得して173位でした。
crackme1 (Baby'sFirst)
crackme1_f92e0ab22352440383d58be8f046bebe.quals.shallweplayaga.me:10001 [https://2017.notmalware.ru/add6a6232ea1e9d42b925a7d2a2c5781bfccd6fd/8a97fb8c264a3b34dad0a707dbfc92832067a0fa0f2b5a576c73557960b11506.tar.bz2]
x86-64のELFが提供され、リモートに繋いでみると何か答えをBase64で送れと言われる。
$ file magic_dist magic_dist: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-musl-x86_64.so.1, stripped $ nc crackme1_f92e0ab22352440383d58be8f046bebe.quals.shallweplayaga.me 10001 send your solution as base64, followed by a newline
とりあえずELFファイルを逆アセンブルし、解析
$ objdump -D -Mintel magic_dist > magic_dist.asm
c6cから始まる関数を見てみると955, 971など細かく関数をcallしている。
引数(rdi)に渡しているアドレスは、1バイトずつずらしている。
c6c: 55 push rbp c6d: 53 push rbx c6e: 48 89 fd mov rbp,rdi c71: 48 83 ec 08 sub rsp,0x8 c75: 48 0f be 3f movsx rdi,BYTE PTR [rdi] c79: e8 bd fc ff ff call 93b <_init+0x243> c7e: 48 0f be 7d 01 movsx rdi,BYTE PTR [rbp+0x1] c83: 48 c1 f8 03 sar rax,0x3 c87: 48 89 c3 mov rbx,rax c8a: e8 c6 fc ff ff call 955 <_init+0x25d> c8f: 48 0f be 7d 02 movsx rdi,BYTE PTR [rbp+0x2] c94: 48 01 c3 add rbx,rax c97: 48 c1 fb 03 sar rbx,0x3 c9b: e8 d1 fc ff ff call 971 <_init+0x279> ca0: 48 0f be 7d 03 movsx rdi,BYTE PTR [rbp+0x3] ca5: 48 01 c3 add rbx,rax ca8: 48 c1 fb 03 sar rbx,0x3 cac: e8 da fc ff ff call 98b <_init+0x293> cb1: 48 0f be 7d 04 movsx rdi,BYTE PTR [rbp+0x4] cb6: 48 01 c3 add rbx,rax cb9: 48 c1 fb 03 sar rbx,0x3 cbd: e8 e3 fc ff ff call 9a5 <_init+0x2ad> cc2: 48 0f be 7d 05 movsx rdi,BYTE PTR [rbp+0x5] :
呼び出されている関数の中身を見てみると、引数(rdi)と1バイト比較。
イコールならeaxに値を代入してret。notイコールのときに呼ばれる758は、<.plt.got>セクションにあるし、exit関数っぽい。とりあえず比較している1バイトを集める。
: 93b: 48 83 ff 79 cmp rdi,0x79 ; "y" 93f: 74 0e je 94f <_init+0x257> 941: 48 83 ec 08 sub rsp,0x8 945: bf 01 00 00 00 mov edi,0x1 94a: e8 09 fe ff ff call 758 <_init+0x60> 94f: b8 a7 00 00 00 mov eax,0xa7 954: c3 ret 955: 48 83 ff 65 cmp rdi,0x65 ; "e" 959: 74 0e je 969 <_init+0x271> 95b: 48 83 ec 08 sub rsp,0x8 95f: bf 02 00 00 00 mov edi,0x2 964: e8 ef fd ff ff call 758 <_init+0x60> 969: 48 c7 c0 9b ff ff ff mov rax,0xffffffffffffff9b 970: c3 ret 971: 48 83 ff 73 cmp rdi,0x73 ; "s" 975: 74 0e je 985 <_init+0x28d> 977: 48 83 ec 08 sub rsp,0x8 97b: bf 03 00 00 00 mov edi,0x3 980: e8 d3 fd ff ff call 758 <_init+0x60> 985: b8 a0 00 00 00 mov eax,0xa0 98a: c3 ret :
集めた文字を連結すると、"yes and his hands shook with ex"という文字列になった。試しにBase64でエンコードして送信してみたらフラグだった。
$ echo "yes and his hands shook with ex" | base64 | nc crackme1_f92e0ab22352440383d58be8f046bebe.quals.shallweplayaga.me 10001 send your solution as base64, followed by a newline 4a2181aaf70b04ec984c233fbe50a1fe600f90062a58d6b69ea15b85531b9652 The flag is: important videos best playlist Wigeekuk8
magic (CrackMe_2000)
cm2k-magic_b46299df0752c152a8e0c5f0a9e5b8f0.quals.shallweplayaga.me:12001 [https://2017.notmalware.ru/5e1d5bc4e73657be1b008fbb6b08a7604e81d7cb/91ae7f2ec76f00975849c44b3d8ec8ed897fab7335c156d949bd15ea156338b3.tar.bz2]
解凍するとx86-64のELFが200個ほどあった。とりあえず逆アセンブルして眺めてみたところ、crackme1と同じ形式なことがわかった。
: 93b: 48 83 ff 64 cmp rdi,0x64 ; d 93f: 74 0e je 94f <_init+0x257> 941: 48 83 ec 08 sub rsp,0x8 945: bf 01 00 00 00 mov edi,0x1 94a: e8 09 fe ff ff call 758 <_init+0x60> 94f: b8 6c 00 00 00 mov eax,0x6c 954: c3 ret 955: 48 83 ff 65 cmp rdi,0x65 ; e 959: 74 0e je 969 <_init+0x271> 95b: 48 83 ec 08 sub rsp,0x8 95f: bf 02 00 00 00 mov edi,0x2 964: e8 ef fd ff ff call 758 <_init+0x60> 969: b8 49 00 00 00 mov eax,0x49 96e: c3 ret 96f: 48 83 ff 2e cmp rdi,0x2e ; . 973: 74 0e je 983 <_init+0x28b> 975: 48 83 ec 08 sub rsp,0x8 979: bf 03 00 00 00 mov edi,0x3 97e: e8 d5 fd ff ff call 758 <_init+0x60> 983: b8 72 00 00 00 mov eax,0x72 988: c3 ret : df6: 55 push rbp df7: 53 push rbx df8: 48 89 fd mov rbp,rdi dfb: 48 83 ec 08 sub rsp,0x8 dff: 48 0f be 3f movsx rdi,BYTE PTR [rdi] e03: e8 33 fb ff ff call 93b <_init+0x243> e08: 48 0f be 7d 01 movsx rdi,BYTE PTR [rbp+0x1] e0d: 48 c1 f8 03 sar rax,0x3 ; 0x6c >> 0x3 = 0xd e11: 48 89 c3 mov rbx,rax e14: e8 3c fb ff ff call 955 <_init+0x25d> e19: 48 0f be 7d 02 movsx rdi,BYTE PTR [rbp+0x2] e1e: 48 01 c3 add rbx,rax e21: 48 c1 fb 03 sar rbx,0x3 e25: e8 45 fb ff ff call 96f <_init+0x277> e2a: 48 0f be 7d 03 movsx rdi,BYTE PTR [rbp+0x3] :
200個を手作業でやるわけにはいかないので、pythonで自動収集するプログラムを作成。
問題の文字列収集は、比較部分のニーモニック(cmp rdi,0xXX)に該当する機械語が"48 83 ff XX"だったので、逆アセンブル結果から該当する機械語を含む行だけ抽出したら、うまいぐあいに文字の比較部分だけ抽出できた。最終的な回答コードが以下になった。
#!/usr/bin/python import os import re import glob import base64 import subprocess import socket def read_data(f, delim="\n"): data = "" while not data.endswith(delim): data += f.read(1) return data def make_ans(fname, data): data = data.split("\n") cmp = "" for d in data: if "\t48 83 ff " not in d: continue a = d.split(",")[1] a = chr(int(a, 16)) print d, "; ", a cmp += a print fname print "[+]str: ", cmp print "[+]Base64: ", base64.b64encode(cmp) return base64.b64encode(cmp) if __name__ == "__main__": # run objdump files = glob.glob("./magic_dist/*") ans_list = {} # collect ans for f in files: arg = ["objdump", "-d", "-Mintel", f] asm = subprocess.Popen(arg, stdout=subprocess.PIPE) data, err = asm.communicate() q = f.split("/")[2] ans_list[q] = make_ans(f, data) # connect to server host = "cm2k-magic_b46299df0752c152a8e0c5f0a9e5b8f0.quals.shallweplayaga.me" port = 12001 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((host, port)) sf = s.makefile("rw", bufsize=0) while True: data = read_data(sf) print data if "flag" in data: break elif 'send your solution as base64, followed by a newline' in data: continue data = data.split("\n")[0] ans = ans_list[data] sf.write(ans + "\n")
コードとしては、Objdumpで逆アセンブル、その結果から"\t48 83 ff " を含む行を抽出。比較されているバイトを連結し、Base64エンコードして辞書作成。サーバーへの回答時は、サーバーからの質問をキーとしてエンコードしている回答を送信しているだけ。
何度か回答に成功するとフラグがもらえた。
$ ./solve.py 93b: 48 83 ff 64 cmp rdi,0x64 ; d 955: 48 83 ff 6f cmp rdi,0x6f ; o 96f: 48 83 ff 63 cmp rdi,0x63 ; c 989: 48 83 ff 74 cmp rdi,0x74 ; t 9a3: 48 83 ff 6f cmp rdi,0x6f ; o 9bd: 48 83 ff 72 cmp rdi,0x72 ; r 9d7: 48 83 ff 20 cmp rdi,0x20 ; 9f3: 48 83 ff 63 cmp rdi,0x63 ; c a0d: 48 83 ff 61 cmp rdi,0x61 ; a a27: 48 83 ff 6d cmp rdi,0x6d ; m a41: 48 83 ff 65 cmp rdi,0x65 ; e a5b: 48 83 ff 20 cmp rdi,0x20 ; a75: 48 83 ff 69 cmp rdi,0x69 ; i a8f: 48 83 ff 6e cmp rdi,0x6e ; n aa9: 48 83 ff 2c cmp rdi,0x2c ; , ac3: 48 83 ff 20 cmp rdi,0x20 ; adf: 48 83 ff 73 cmp rdi,0x73 ; s af9: 48 83 ff 68 cmp rdi,0x68 ; h b13: 48 83 ff 61 cmp rdi,0x61 ; a b2d: 48 83 ff 6b cmp rdi,0x6b ; k b47: 48 83 ff 69 cmp rdi,0x69 ; i b61: 48 83 ff 6e cmp rdi,0x6e ; n b7b: 48 83 ff 67 cmp rdi,0x67 ; g b95: 48 83 ff 20 cmp rdi,0x20 ; bb1: 48 83 ff 68 cmp rdi,0x68 ; h bcb: 48 83 ff 69 cmp rdi,0x69 ; i be5: 48 83 ff 73 cmp rdi,0x73 ; s c01: 48 83 ff 20 cmp rdi,0x20 ; c1b: 48 83 ff 68 cmp rdi,0x68 ; h c35: 48 83 ff 65 cmp rdi,0x65 ; e c4f: 48 83 ff 61 cmp rdi,0x61 ; a c69: 48 83 ff 64 cmp rdi,0x64 ; d c83: 48 83 ff 2e cmp rdi,0x2e ; . c9f: 48 83 ff 20 cmp rdi,0x20 ; cbb: 48 83 ff 22 cmp rdi,0x22 ; " cd5: 48 83 ff 57 cmp rdi,0x57 ; W cef: 48 83 ff 65 cmp rdi,0x65 ; e d0b: 48 83 ff 6c cmp rdi,0x6c ; l ./magic_dist/e005a1973167b4cf47100c81bca178b98646a128e05a6beb804226888be3f344 [+]str: doctor came in, shaking his head. "Wel [+]Base64: ZG9jdG9yIGNhbWUgaW4sIHNoYWtpbmcgaGlzIGhlYWQuICJXZWw= : send your solution as base64, followed by a newline c0d5312126c2a52cb23f91694a22ba32284e59336fb5176ed92dc1cd23b62655 : 省略 : be422c4d780fcc9f29d01283ad76088529af9b4dc7a69c3bb9979fb51a23824e The flag is: a color map of the sun sokemsUbif
解けた問題は以上です。力不足感が半端ないので、もっと精進したい。