---
# System prepended metadata

title: Grey Cat CTF

---

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

```