この大会は2022/12/17 15:30(JST)~2022/12/18 15:30(JST)に開催されました。
今回もチームで参戦。結果は310点で91チーム中21位でした。
自分で解けた問題をWriteupとして書いておきます。
Welcome (misc)
Discordに入り、#rulesチャネルでリアクションすると、たくさんのチャネルが現れた。#randomチャネルのメッセージを見ると、マスクされたメッセージにフラグが書いてあった。
flag{w3lc0m3_70_b4ckd00r_2022}
Fishy (crypto)
暗号化処理の概要は以下の通り。
・modulus = pow(2, 32) ・s_boxes: 256個のランダム32ビット整数の配列の4個の配列 ・s_boxes.txtにs_boxesを書き込み ・initial_sub_keys: 既知の18個の32ビット整数のhex文字列の配列 ・key: 18個の32ビット整数のhex文字列の連結 ・processed_sub_keys: initial_sub_keysとkeyのXOR ・pt: フラグの2進数文字列 ・ptの長さが64で割り切れるように先頭に"0"を付与 ・pt: フラグの16進数文字列 ・ct = '' ・pt(16進数文字列)の16バイトごとに以下繰り返し ・xl = ptの16バイトの前半8バイト ・xr = ptの16バイトの後半8バイト ・16回以下繰り返し ・tmp = xl ・xl = bin(int(xl, 16) ^ int(processed_sub_keys[j], 16))[2:].zfill(32) ・xa = int(xl[:8], 2) ・xb = int(xl[8:16], 2) ・xc = int(xl[16:24], 2) ・xd = int(xl[24:32], 2) ・xa = (s_boxes[0][xa] + s_boxes[1][xb]) % modulus ・xc = s_boxes[2][xc] ^ xa ・f_out = (xc + s_boxes[3][xd]) % modulus ・xl = hex(int(xr, 16) ^ f_out)[2:].zfill(8) ・xr = tmp ・xrt = xr ・xr = hex(int(xl, 16) ^ int(processed_sub_keys[16], 16))[2:].zfill(8) ・xl = hex(int(xrt, 16) ^ int(processed_sub_keys[17], 16))[2:].zfill(8) ・ct にxl + xrを結合 ・ctを出力
Mersenne Twisterの特性を使って、s_boxesの値からkeyを算出できる。またinitial_sub_keysとkeyの値からprocessed_sub_keysを算出できる。あとは暗号化データから逆算し、フラグを求めればよい。
#!/usr/bin/env python3 import random def untemper(rand): rand ^= rand >> 18; rand ^= (rand << 15) & 0xefc60000; a = rand ^ ((rand << 7) & 0x9d2c5680); b = rand ^ ((a << 7) & 0x9d2c5680); c = rand ^ ((b << 7) & 0x9d2c5680); d = rand ^ ((c << 7) & 0x9d2c5680); rand = rand ^ ((d << 7) & 0x9d2c5680); rand ^= ((rand ^ (rand >> 11)) >> 11); return rand initial_sub_keys = [ "243f6a88", "85a308d3", "13198a2e", "03707344", "a4093822", "299f31d0", "082efa98", "ec4e6c89", "452821e6", "38d01377", "be5466cf", "34e90c6c", "c0ac29b7", "c97c50dd", "3f84d5b5", "b5470917", "9216d5d9", "8979fb1b", ] modulus = pow(2, 32) with open('s_boxes.txt', 'r') as f: s_boxes = eval(f.read()) N = 624 state = [] _rand = [] for j in range(4): for i in range(256): if len(state) != 624: state.append(untemper(s_boxes[j][i])) else: _rand.append(s_boxes[j][i]) state.append(N) random.setstate([3, tuple(state), None]) for i in range(256 * 4 - 624): r = random.getrandbits(32) assert r == _rand[i] key = "".join([hex(random.getrandbits(32))[2:].zfill(8) for i in range(18)]) processed_sub_keys = [ hex(int(initial_sub_keys[i], 16) ^ int(key[8 * i : 8 * (i + 1)], 16))[2:].zfill(8) for i in range(len(initial_sub_keys)) ] with open('enc.txt', 'r') as f: ct = f.read().rstrip().split(' ')[-1] pt = '' for i in range(0, len(ct), 16): xl = ct[i:i+8] xr = ct[i+8:i+16] xrt = hex(int(xl, 16) ^ int(processed_sub_keys[17], 16))[2:].zfill(8) xl = hex(int(xr, 16) ^ int(processed_sub_keys[16], 16))[2:].zfill(8) xr = xrt for j in range(15, -1, -1): xl2 = xl tmp = xr xl = tmp tmp = bin(int(tmp, 16) ^ int(processed_sub_keys[j], 16))[2:].zfill(32) xa = int(tmp[:8], 2) xb = int(tmp[8:16], 2) xc = int(tmp[16:24], 2) xd = int(tmp[24:32], 2) xa = (s_boxes[0][xa] + s_boxes[1][xb]) % modulus xc = s_boxes[2][xc] ^ xa f_out = (xc + s_boxes[3][xd]) % modulus xr = hex(int(xl2, 16) ^ f_out)[2:].zfill(8) pt += xl + xr flag = bytes.fromhex(pt).decode() print(flag)
flag{d0n't_u53_th3_m3r53nn3_r4nd0m_g3n3r4t0r_w1th0ut_c4ut10n_<3}
Feedback (misc)
アンケートに答えたら、フラグが表示された。
flag{th4nks_f0r_pl4y1ng_b4ckd00r_c7f}