この大会は2021/7/31 1:00(JST)~2021/8/1 1:00(JST)に開催されました。
今回もチームで参戦。結果は108点で443チーム中121位でした。
自分で解けた問題をWriteupとして書いておきます。
Mic Check
ルールのページにフラグが書いてあった。
CCTF{W3lc0me_t0_The_0ne_&_0nly_Crypt0_CTF_Mad3ـw1th_L0ve_f0r_Crypt0!}
Farm
暗号化処理は以下の通り。
・ALPHABET = string.printable[:62] + '\\=' ・key生成 ・64=2**6のため、14個の5乗以下の式を生成 ・積を返す(14個の5乗以下の式) ※64パターンしかない。 ・暗号化 ・m64: flagをbase64エンコード ・pkey = key**5 + key**3 + key**2 + 1 ・m64の各文字について、ALPHABET[F.index(pkey * maptofarm(chr(m)))]を算出し、結合する。
フラグが'CCTF{'から始まることを前提に、64パターンのキーをブルートフォースし、キーを求める。さらにフラグのbase64エンコード文字の各文字をブルートフォースで復号する。
#!/usr/bin/env sage from sage.all import * import string, base64, math def maptofarm(c): assert c in ALPHABET return F[ALPHABET.index(c)] ALPHABET = string.printable[:62] + '\\=' F = list(GF(64)) enc = '805c9GMYuD5RefTmabUNfS9N9YrkwbAbdZE0df91uCEytcoy9FDSbZ8Ay8jj' keys = [F[i] for i in range(64)] m64_head = base64.b64encode(b'CCT') for key in keys: pkey = key**5 + key**3 + key**2 + 1 if ALPHABET[F.index(pkey * maptofarm(chr(m64_head[0])))] == enc[0]: print('[+] key =', key) break pkey = key**5 + key**3 + key**2 + 1 print('[+] pkey =', pkey) m64 = '' for i in range(len(enc)): for m in ALPHABET: if ALPHABET[F.index(pkey * maptofarm(m))] == enc[i]: m64 += m break print('[+] m64 =', m64) flag = base64.b64decode(m64.encode()).decode() print('[*] flag =', flag)
実行結果は以下の通り。
[+] key = z6^5 + 1 [+] pkey = z6^5 + z6^3 + z6^2 + z6 [+] m64 = Q0NURntFbkNyWXA3STBuXzRuRF81dThTVGl0VXRJbjlfaU5fRmkzTGQhfQ== [*] flag = CCTF{EnCrYp7I0n_4nD_5u8STitUtIn9_iN_Fi3Ld!}
CCTF{EnCrYp7I0n_4nD_5u8STitUtIn9_iN_Fi3Ld!}
KeyBase
$ nc 01.cr.yp.toc.tf 17010 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + hi all, welcome to the simple KEYBASE cryptography task, try to + + decrypt the encrypted message and get the flag as a nice prize! + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | Options: | [G]et the encrypted flag | [T]est the encryption | [Q]uit G | encrypt(flag) = 9e8574ab8707c03ab04a181283d8bf9c8be334e850570739df1d6cb658bac696 | Options: | [G]et the encrypted flag | [T]est the encryption | [Q]uit T | Please send your 32 bytes message to encrypt: 0123456789abcdef0123456789abcdef | enc = 0****************************c89b26fae8a39a1af1d9a0c9a33b4198caf | key = a6346a6148918313e0695e4a3301**** | Options: | [G]et the encrypted flag | [T]est the encryption | [Q]uit Q Quitting ...
サーバの処理概要は以下の通り。
・iv, key: ランダム16バイト ・flag_enc: AES-CBC暗号化(hex) ・以下繰り返し ・メニュー選択(G/T/Q)表示 ・'g'選択の場合 ・flag_enc表示 ・'t'選択の場合 ・msg_inp: 32バイト入力 ・enc: msg_inpのAES-CBC暗号化(hex) ・r: 0~4ランダム ・s = 4 - r ・enc先頭rバイト + '*' * 28 + enc32-sバイト目以降を表示 ・keyの末尾2バイト以外 + '*' * 4を表示
encの2ブロック目は必ず表示される。AES-CBC暗号なので、以下のようになる。
平文1ブロック目 ^ IV --(AES暗号)--> 暗号1ブロック目 平文2ブロック目 ^ 暗号1ブロック目 --(AES暗号)--> 暗号2ブロック目
暗号2ブロック目をkeyのブルートフォースで復号し、平文2ブロック目とのXORをする。その結果暗号1ブロック目のわかっている文字が一致しているものを探す。keyがわかれば、同様に1ブロック目を復号し、平文1ブロック目とのXORでIVも割り出せる。あとはflagを復号すればよい。
import socket from Crypto.Cipher import AES from Crypto.Util.strxor import strxor def recvuntil(s, tail): data = '' while True: if tail in data: return data data += s.recv(1) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('01.cr.yp.toc.tf', 17010)) data = recvuntil(s, '[Q]uit\n').rstrip() print data + 'g' s.sendall('g\n') data = recvuntil(s, '\n').rstrip() print data enc_flag = data.split(' ')[-1].decode('hex') try_pt = 'a' * 32 ct0_0 = '' ct0_1 = '' while True: data = recvuntil(s, '[Q]uit\n').rstrip() print data + 't' s.sendall('t\n') data = recvuntil(s, '\n').rstrip() print data + try_pt s.sendall(try_pt + '\n') data = recvuntil(s, '\n').rstrip() print data try_ct = data.split(' ')[-1] if '*' not in try_ct[:4]: ct0_0 = try_ct[:4] if '*' not in try_ct[28:32]: ct0_1 = try_ct[28:32] ct1 = try_ct[32:] data = recvuntil(s, '\n').rstrip() print data key_part = data.split(' ')[-1][:-4] if ct0_0 != '' and ct0_1 != '': break found = False for k1 in range(256): for k2 in range(256): key = key_part.decode('hex') + chr(k1) + chr(k2) aes = AES.new(key, AES.MODE_ECB) pt1 = aes.decrypt(ct1.decode('hex')) ct0 = strxor('a' * 16, pt1).encode('hex') if ct0[:4] == ct0_0 and ct0[-4:] == ct0_1: found = True break if found: break print '[+] key =', key.encode('hex') pt0 = aes.decrypt(ct0.decode('hex')) iv = strxor('a' * 16, pt0) print '[+] iv =', iv.encode('hex') aes = AES.new(key, AES.MODE_CBC, iv) flag = aes.decrypt(enc_flag) print '[*] flag =', flag
実行結果は以下の通り。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + hi all, welcome to the simple KEYBASE cryptography task, try to + + decrypt the encrypted message and get the flag as a nice prize! + ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | Options: | [G]et the encrypted flag | [T]est the encryption | [Q]uitg | encrypt(flag) = 91e5f649d0f5a1be26406b49a6ccbda235d02e3f64a465299399c24e6fcc76e0 | Options: | [G]et the encrypted flag | [T]est the encryption | [Q]uitt | Please send your 32 bytes message to encrypt:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | enc = d46****************************52e3717df731872aca698b41a2eb6dd75 | key = 70f0320c155b873cd3bf78fd0ee0**** | Options: | [G]et the encrypted flag | [T]est the encryption | [Q]uitt | Please send your 32 bytes message to encrypt:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | enc = d463****************************2e3717df731872aca698b41a2eb6dd75 | key = 70f0320c155b873cd3bf78fd0ee0**** | Options: | [G]et the encrypted flag | [T]est the encryption | [Q]uitt | Please send your 32 bytes message to encrypt:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | enc = d****************************1352e3717df731872aca698b41a2eb6dd75 | key = 70f0320c155b873cd3bf78fd0ee0**** | Options: | [G]et the encrypted flag | [T]est the encryption | [Q]uitt | Please send your 32 bytes message to encrypt:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | enc = d4****************************352e3717df731872aca698b41a2eb6dd75 | key = 70f0320c155b873cd3bf78fd0ee0**** | Options: | [G]et the encrypted flag | [T]est the encryption | [Q]uitt | Please send your 32 bytes message to encrypt:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | enc = d46****************************52e3717df731872aca698b41a2eb6dd75 | key = 70f0320c155b873cd3bf78fd0ee0**** | Options: | [G]et the encrypted flag | [T]est the encryption | [Q]uitt | Please send your 32 bytes message to encrypt:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | enc = d46****************************52e3717df731872aca698b41a2eb6dd75 | key = 70f0320c155b873cd3bf78fd0ee0**** | Options: | [G]et the encrypted flag | [T]est the encryption | [Q]uitt | Please send your 32 bytes message to encrypt:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | enc = ****************************01352e3717df731872aca698b41a2eb6dd75 | key = 70f0320c155b873cd3bf78fd0ee0**** [+] key = 70f0320c155b873cd3bf78fd0ee01ca4 [+] iv = 002d5f79d5b5aa201c7c792d69a2fb20 [*] flag = CCTF{h0W_R3cOVER_7He_5eCrET_1V?}
CCTF{h0W_R3cOVER_7He_5eCrET_1V?}