# 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:

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()
```