# 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

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}**