IV固定のCBCモードでECB のChosen Plaintext Attackのようなものをやれという問題。リクエストの回数に制限がなく、時間も20minと十分にとってあったので、適切なサーバを使って高速ネットワークに頼ればなんとかなる
IVがわかっているので最初のblockがAAAA... になるように調節して、あとはChosen Plaintext Attackの要領をやるだけで良い。なかなかおもしろかった
from ptrlib import Socket, xor import sys from binascii import hexlify import proofofwork # sock = Socket("localhost", 10000) sock = Socket("170.106.35.18", 16442) # sock = Socket("81.68.174.63", 16442) postfix, hash = sock.recvregex(r"sha256\(XXXX\+([0-9a-zA-Z]+)\) == ([0-9a-f]+)") s = proofofwork.sha256(hash.decode(), text=b'?' * 4 + postfix) print("[+] PoW: {}".format(s[:4])) sock.sendline(s[:4]) ivhex = sock.recvregex("IV is: ([0-9a-f]+)")[0] iv = bytes.fromhex(ivhex.decode()) def encrypt(m): global iv sock.sendlineafter("> ", "1") sock.sendlineafter("(in hex): ", hexlify(m)) result = bytes.fromhex(sock.recvline().decode()) iv = result[-16:] return result def calc_prefix(): return xor(b"A" * 16, iv) def calc_block(known): if len(known) < 16: return b"A" * (15 - len(known)) l = len(known) % 16 if l == 0: return b"A" * 15 else: return b"A" * (15 - l) known = b"" for x in range(1, 4): for i in range(16): block = calc_block(known) result = encrypt(calc_prefix() + block) wannaget = result[16*x:16*(x+1)] for b in range(256): sys.stdout.write("{},".format(b)) sys.stdout.flush() prefix = calc_prefix() block = calc_block(known) + known + bytes([b]) result = encrypt(prefix + block) result = result[16*x:16*(x+1)] if result == wannaget: known += bytes([b]) break else: raise Exception(":(") sys.stdout.write("\n") print([b for b in known]) sock.sendlineafter("> ", "2") sock.sendlineafter("(in hex): ", hexlify(known)) print(sock.recvline())