この大会は2021/10/9 9:00(JST)~2021/10/11 9:00(JST)に開催されました。
今回もチームで参戦。結果は 134点で210チーム中201位でした。
自分で解けた問題をWriteupとして書いておきます。
Alkaloid Stream (Crypto)
暗号の処理概要は以下の通り。
・flag: flagを2進数表記 ・key = keygen(len(flag)) ・keystream, public = gen_keystream(key) ※len(key)=600の場合 ・i=0, j=0, fake[0] ^= key[1] ・i=0, j=1, fake[0] ^= key[2] : ・i=0, j=199, fake[0] ^= key[200] ・i=1, j=0, fake[1] ^= key[2] ・i=1, j=1, fake[1] ^= key[3] : ・i=1, j=199, fake[1] ^= key[201] : ・i=398, j=0, fake[398] ^= key[399] : ・i=399, j=199, fake[399] ^= key[598] ・i=399, j=0, fake[399] ^= key[400] : ・i=399, j=199, fake[399] ^= key[599] ・i=597, j=0, fake[597] ^= key[598] ・i=597, j=1, fake[597] ^= key[599] ・i=598, j=0, fake[598] ^= key[599]
このことから以下のように算出し、fakeとkeyを求めることができる。
fake[599] = 0 -> key[599] = ペアの数値 fake[598] = key[599] -> key[598] = ペアの数値 fake[597] = key[598] ^ key[599] -> key[597] = ペアの数値 fake[596] = key[597] ^ key[598] ^ key[599] -> key[596] = ペアの数値 :
fakeとkeyを求めたら、keystreamを算出し、暗号文とXORをとればフラグになる。
#!/usr/bin/python3 import copy def xor(a, b): return [x ^ y for x, y in zip(a, b)] def recover_keystream(key, public): st = set(key) keystream = [] for v0, v1 in public: if v0 in st: keystream.append(0) elif v1 in st: keystream.append(1) else: assert False, "Failed to recover the keystream" return keystream def bytes_to_bits(inp): res = [] for v in inp: res.extend(list(map(int, format(v, '08b')))) return res def bits_to_bytes(inp): res = [] for i in range(0, len(inp), 8): res.append(int(''.join(map(str, inp[i:i+8])), 2)) return bytes(res) with open('output.txt', 'r') as f: enc = bytes.fromhex(f.readline().rstrip()) public = eval(f.readline().rstrip()) ln = len(public) key = [0] * ln fake = [0] * ln tmp_pub = copy.copy(public) for i in range(ln - 1, -1, -1): for p in tmp_pub: if p[0] == fake[i]: key[i] = p[1] if i > 0: for j in range(ln // 3): if i + j >= ln: break fake[i-1] ^= key[i + j] tmp_pub.remove([p[0], p[1]]) break if p[1] == fake[i]: key[i] = p[0] if i > 0: for j in range(ln // 3): if i + j >= ln: break fake[i-1] ^= key[i + j] tmp_pub.remove([p[0], p[1]]) break keystream = recover_keystream(key, public) enc = bytes_to_bits(enc) flag = bits_to_bytes(xor(enc, keystream)).decode() print(flag)
pbctf{super_duper_easy_brute_forcing_actually_this_one_was_made_by_mistake}