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