この大会は2018/9/22 18:00(JST)~2018/9/23 18:00(JST)に開催されました。
今回もチームで参戦。結果は 681点で1005チーム中44位でした。
自分で解けた問題をWriteupとして書いておきます。
XORnigma (Junior)
XOR暗号。フラグはDCTF{で始まることを考慮し、キーを割り出す。キーの1バイト目と5バイト目が同じなので、4バイトと考え、復号する。
import itertools def xor_two_str(s, key): key = key * (len(s) / len(key) + 1) return ''.join(chr(ord(x) ^ ord(y)) for (x,y) in itertools.izip(s, key)) enc = '000000003f2537257777312725266c24207062777027307574706672217a67747374642577263077777a3725762067747173377326716371272165722122677522746327743e' enc = enc.decode('hex') flag_head = 'DCTF{' key = '' for i in range(len(flag_head)): key += chr(ord(enc[i]) ^ ord(flag_head[i])) key = key[:4] flag = xor_two_str(enc, key) print flag
DCTF{fcc34eaae8bd3614dd30324e932770c3ed139cc2c3250c5b277cb14ea33f77a0}
Multiple Flags (Junior)
手旗信号の画像。
https://ja.wikipedia.org/wiki/%E6%89%8B%E6%97%97%E4%BF%A1%E5%8F%B7を参考に、文字にしていく。
(文字)DCTFSPECIALFLAG(数字)00(文字)AA(数字)00(文字)AA(数字)00991337(文字)DCTF
DCTFSPECIALFLAG00AA00AA00991337DCTF
Passport (Junior)
demo.binと異なるバイナリで、md5が同じファイルをアップロードすればフラグが表示されるようだ。
試しにdemo.binのmd5の値で調べてみる。
cee9a457e790cf20d4bdaa6d69f01e41
http://www.xefan.com/archives/83875.htmlに衝突する2つのファイルが書いてあり、片方はdemo.binと一致する。もう一つのバイナリを作成すればよい。
バイナリエディタでdemoの一部を修正する。
・オフセット0x15:0x70→0x74 ・オフセット0x2b:0x5c→0xdc
この作成したバイナリファイルをアップロードすると、フラグが表示された。
DCTF{04c8d0052e3ffd8d21934e392c272a0494f23433901941c93fab82b50be27c1a}
Ransomware (Reverse)
ransomware.pycをEasyPythonDecompilerでデコンパイルする。
import string from random import * import itertools def caesar_cipher(OOO0O0O00OOO0O0OO, O0O0O0O0OOOO0OOOO): O0O0O0O0OOOO0OOOO = O0O0O0O0OOOO0OOOO * (len(OOO0O0O00OOO0O0OO) / len(O0O0O0O0OOOO0OOOO) + 1) return ''.join((chr(ord(O0O0O00O0000O00O0) ^ ord(OO0000000O0OO00OO)) for O0O0O00O0000O00O0, OO0000000O0OO00OO in itertools.izip(OOO0O0O00OOO0O0OO, O0O0O0O0OOOO0OOOO))) f = open('./FlagDCTF.pdf', 'r') buf = f.read() f.close() allchar = string.ascii_letters + string.punctuation + string.digits password = ''.join((choice(allchar) for OOO0OO0OO00OO0000 in range(randint(60, 60)))) buf = caesar_cipher(buf, password) f = open('./youfool!.exe', 'w') buf = f.write(buf) f.close()
cease_cipher関数は読みにくいので、置き換える。
def caesar_cipher(x, y): y = y * (len(x) / len(y) + 1) return ''.join((chr(ord(a) ^ ord(b)) for a, b in itertools.izip(x, y)))
簡単に言えば, XOR関数で、実行している部分を見ると、鍵の長さは60であることがわかる。PDFに復号できることを前提に少しずつ調整しながら鍵を見つけていく。
def str_xor(s1, s2): return ''.join(chr(ord(a) ^ ord(b)) for a, b in zip(s1, s2)) with open('youfool!.exe', 'rb') as f: data = f.read() key = '' #### key 0-6 PDF_HEAD = '%PDF-1.' key += str_xor(PDF_HEAD, data[:len(PDF_HEAD)]) #### key 7-9 AFTER_FIL = 'ter' key += str_xor(AFTER_FIL, data[1387:1390]) #### key 10-11 AFTER_LENG = 'th' key += str_xor(AFTER_LENG, data[8470:8472]) #### key 12-15 AFTER_CAT = 'alog' key += str_xor(AFTER_CAT, data[672:676]) #### key 16-19 AFTER_MIDI = 'aBox' key += str_xor(AFTER_MIDI, data[856:860]) #### key 20-22 AFTER_FLATEDEC = 'ode' key += str_xor(AFTER_FLATEDEC, data[10220:10223]) #### key 23-24 AFTER_PARE = 'nt' key += str_xor(AFTER_PARE, data[10043:10045]) #### key 25-27 AFTER_IM = 'age' key += str_xor(AFTER_IM, data[9625:9628]) #### key 28-30 AFTER_LEN = 'gth' key += str_xor(AFTER_LEN, data[1408:1411]) #### key 31-32 AFTER_FILT = 'er' key += str_xor(AFTER_FILT, data[10531:10533]) #### key 33-34 AFTER_TY = 'pe' key += str_xor(AFTER_TY, data[10173:10175]) #### key 35-43 AFTER_FL = 'ateDecode' key += str_xor(AFTER_FL, data[9695:9704]) #### key 44-45 EOF_TAIL = 'OF' key += str_xor(EOF_TAIL, data[10784:10786]) #### key 46-50 AFTER_FLATEDECODE_L = 'ength' key += str_xor(AFTER_FLATEDECODE_L, data[1066:1071]) #### key 51-56 AFTER_EXT = 'GState' key += str_xor(AFTER_EXT, data[10071:10077]) #### key 57-59 AFTER_RESO = 'urc' key += str_xor(AFTER_RESO, data[897:900]) print '[+] key:', key pdf = '' for i in range(0, len(data), 60): dec = str_xor(data[i:i+60], key) print dec, i # for arrangement pdf += dec with open('FlagDCTF.pdf', 'wb') as f: f.write(pdf)
復号したPDFは3ページにわたり、フラグが書かれている。
DCTF{d915b5e076215c3efb92e5844ac20d0620d19b15d427e207fae6a3b894f91333}