---
# System prepended metadata

title: FERMENTATION
tags: [Writeup_CTF]

---

# FERMENTATION

Đây là thử thách Flipping Oracle CBC, source như sau:
```
#!/usr/bin/env python3
import pickle
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
import os

KEY = os.urandom(16)
IV = os.urandom(16)
FLAG = 'redacted'

header = input("Header: ")
name = input("Name: ")
is_admin = False

data = header.encode() + pickle.dumps((name, is_admin))

encrypted = AES.new(KEY, AES.MODE_CBC, IV).encrypt(pad(data, 16))
print(encrypted.hex())

while True:
    data = bytes.fromhex(input().strip())
    try:
        if pickle.loads(unpad(AES.new(KEY, AES.MODE_CBC, IV).decrypt(data),16)[len(header):])[1] == 1:
            print(FLAG)
        else:
            print("Wait a minute, who are you?")
    except:
        print("Wait a minute, who are you?")
```

Trước hết, ta thấy name và is_admin được ở trong hàm pickle.dumps, đây là 1 hàm để khiến cho 2 giá trị này thành 1 đoạn byte
Với is_admin = True và name = 'hello' ta thấy nó có dạng ``b'\x80\x04\x95\x0c\x00\x00\x00\x00\x00\x00\x00\x8c\x05hello\x94\x88\x86\x94.'``, tức là sẽ có 1 giá trị là độ dài của name và giá trị name, ngoài ra với is_admin = True thì sẽ có 1 byte là \x88, còn khi False thì là \x89
Mục tiêu là khi decrypt thì giá trị byte phải là \x88

![](https://hackmd.io/_uploads/BJQgjwrs2.png)


Ta thấy khi decrypt thì iv sẽ là chính là Ciphertext của block trước, mà block chứa False là block 2 nên ta cần sửa Ciphertext của block 1
Thế nhưng, sau khi decrypt thì lại có 1 hàm là ``pickle.loads``, tức là phải có dạng như trên thì mới trả về 2 giá trị name và is_admin, thế nên ta phải để sang block 2, còn block 1 sẽ là header. Vì thế ``header = 'a'*16``

Ta thử độ dài của ``pickle.dumps((name, is_admin))`` khi name = 'a' thì được là 19, tức là byte is_admin là byte thứ 31, vẫn là block 2, thế nên ``name = 'a'``

Cipher_block 2 sau khi decrypt thì sẽ thu được is_admin = False, nhưng khi sửa byte thứ 15 của Cipher_block 1 bằng cách xor với 1 thì ta sẽ thu được is_admin = True
```
is_admin_pos_in_data = 31

new_cipher = bytearray(encrypted)

new_cipher[is_admin_pos_in_data - 16] ^= 1
```
Được rồi, lấy flag thui
```
from pwn import *

io = remote('challs.tfcctf.com',30659)

io.recvuntil(b"Header: ")
io.sendline(b'aaaaaaaaaaaaaaaa')
io.recvuntil(b"Name: ")
io.sendline(b"a")


encrypted = bytes.fromhex(io.recvline().strip().decode())
is_admin_pos_in_data = 31

new_cipher = bytearray(encrypted)

new_cipher[is_admin_pos_in_data - 16] ^= 1

io.sendline((new_cipher.hex()).encode())

io.interactive()

```
Flag: **TFCCTF{F3rm3nt3d_D1g1t4l_P1ckl3s_4nd_AES_My5t3r13s_Unr4v3ll3d}**