# Grey Cat CTF ## Filter Plaintext ### Description `nc challs.nusgreyhats.org 32223` - chall.py ```python from Crypto.Cipher import AES from Crypto.Util.Padding import pad from hashlib import md5 import os with open("flag.txt", "r") as f: flag = f.read() BLOCK_SIZE = 16 iv = os.urandom(BLOCK_SIZE) xor = lambda x, y: bytes(a^b for a,b in zip(x,y)) key = os.urandom(16) def encrypt(pt): cipher = AES.new(key=key, mode=AES.MODE_ECB) blocks = [pt[i:i+BLOCK_SIZE] for i in range(0, len(pt), BLOCK_SIZE)] tmp = iv ret = b"" for block in blocks: res = cipher.encrypt(xor(block, tmp)) ret += res tmp = xor(block, res) return ret def decrypt(ct): cipher = AES.new(key=key, mode=AES.MODE_ECB) blocks = [ct[i:i+BLOCK_SIZE] for i in range(0, len(ct), BLOCK_SIZE)] tmp = iv ret = b"" for block in blocks: res = xor(cipher.decrypt(block), tmp) if (res not in secret): ret += res tmp = xor(block, res) return ret secret = os.urandom(80) secret_enc = encrypt(secret) print(f"Encrypted secret: {secret_enc.hex()}") secret_key = md5(secret).digest() secret_iv = os.urandom(BLOCK_SIZE) cipher = AES.new(key = secret_key, iv = secret_iv, mode = AES.MODE_CBC) flag_enc = cipher.encrypt(pad(flag.encode(), BLOCK_SIZE)) print(f"iv: {secret_iv.hex()}") print(f"ct: {flag_enc.hex()}") print("Enter messages to decrypt (in hex): ") while True: res = input("> ") try: enc = bytes.fromhex(res) dec = decrypt(enc) print(dec.hex()) except Exception as e: print(e) continue ``` ### Solution Đầu tiên ta phải biết cách mã hóa của challenge: ![image](https://hackmd.io/_uploads/SJj2bVzbR.png) Sau khi đọc code thì ta nhận ra mình cần phải tìm được `secret` để biết được `secret_key` Tuy nhiên khi chúng ta decrypt `enc_secret` nếu như nó tồn tại trong secret thì sẽ bị xóa đi Vậy chúng ta làm như thế nào: - Giờ chúng ta sẽ đi tìm `iv` để encrypt `secret` trước - Để ý đoạn code này: ```python tmp = iv ret = b"" for block in blocks: res = xor(cipher.decrypt(block), tmp) if (res not in secret): ret += res tmp = xor(block, res) ``` - Khi chia `enc_secret` ra từng block, nếu chúng ta descrypt $enc\_secret_0 + enc\_secret_0$ thì trong $res_0 = secret_0$ và sẽ bị xóa tuy nhiên lúc này $tmp = D(encS_0) \oplus iv \oplus encS_0$ và sau đó ta sẽ nhận lại được 1 xâu là $res_1 = iv \oplus encS_0$ - Từ đó ta có thể tìm lại $iv$ - Tiếp đến ta cần tìm $S_0$ để tạo tiền đề tìm full `secret` - Nếu chúng ta descrypt $encS_1 + encS_0$ thì ta sẽ có $res_0 = D(encS_1) \oplus iv$ và $res_1 = D(encS_0) \oplus D(encS_1) \oplus iv \oplus encS_1 = S_0 \oplus D(encS_1) \oplus encS_1$ - Từ $res_0$ ta có thể tìm lại $D(encS_1)$ vì đã có $iv$ và ta dùng $D(encS_1)$ để tìm lại được $S_0$ - Giờ thì mọi chuyện trở nên dễ dàng hơn, ta chỉ cần lần lượt gửi $encS_i$ đến thì $res_0 = D(enc_i) \oplus iv$ từ đó ta tìm được $S_i = D(encS_i) \oplus encS_i \oplus S_{i - 1} = res_0 \oplus iv \oplus encS_i \oplus S_{i - 1}$ - Cuối cùng thì ta tính `secret_key` và tìm lại flag thôi ```python from pwn import * from Crypto.Util.number import * from Crypto.Cipher import AES from hashlib import md5 r = remote("challs.nusgreyhats.org", 32223) # r = process(["python3", "chall.py"]) context.log_level = "DEBUG" r.recvuntil(b"Encrypted secret: ") enc_secret = bytes.fromhex(r.recvline().strip().decode()) r.recvuntil(b"iv: ") iv = bytes.fromhex(r.recvline().strip().decode()) r.recvuntil(b"ct: ") ct = bytes.fromhex(r.recvline().strip().decode()) r.sendlineafter(b"> ", (enc_secret[:16].hex() * 2).encode()) dec = bytes.fromhex(r.recvline().strip().decode()) print("Decrypted:", dec.hex()) iv_secret = xor(dec, enc_secret[:16]) print("IV Secret:", iv_secret.hex()) r.sendafter(b"> ", (enc_secret[16:32].hex() + enc_secret[:16].hex()).encode() + b"\n") dec = bytes.fromhex(r.recvline().strip().decode()) # print(dec.hex()) dec_ct1 = xor(dec[:16], iv_secret) secret = xor(dec[16:32], dec_ct1) secret = xor(secret, enc_secret[16:32]) print("Secret:", secret.hex()) for i in range(16, len(enc_secret), 16): r.sendlineafter(b"> ", enc_secret[i:i + 16].hex().encode()) dec = bytes.fromhex(r.recvline().strip().decode()) tmp = xor(dec, iv_secret) tmp = xor(tmp, enc_secret[i - 16:i]) tmp = xor(tmp, secret[i - 16:i]) secret += tmp print("Secret:", secret.hex()) cipher = AES.new(key=md5(secret).digest(), iv=iv, mode=AES.MODE_CBC) print(cipher.decrypt(ct).decode()) r.interactive() ```