The Seer challenge involves exploiting a cryptographic vulnerability known as the Padding Oracle Attack. This attack allows an adversary to decrypt data encrypted with block ciphers in Cipher Block Chaining (CBC) mode without knowing the encryption key. The attack takes advantage of the way padding is handled in CBC mode, specifically when using PKCS7 padding.
In this challenge, we are given access to a remote service that encrypts data using AES in CBC mode. Our goal is to decrypt a given ciphertext by exploiting the padding oracle vulnerability.
The Padding Oracle Attack is a type of side-channel attack that exploits the padding validation of a cryptographic message. When a message is encrypted using CBC mode, it is divided into blocks, and each block is XORed with the previous ciphertext block before being encrypted. The last block is padded to ensure it is the correct length.
If the decryption process reveals whether the padding is correct or not, an attacker can use this information to decrypt the message. By sending modified ciphertexts to the oracle and observing the responses, the attacker can deduce the plaintext.
The solution to this challenge is implemented in Python, as shown in the solve.py script. The script connects to the remote service and performs the padding oracle attack to recover the plaintext.
padding_oracle_attack(ciphertext): This function implements the attack logic. It iterates over each block and each byte within the block, using the oracle to determine the correct padding and recover the plaintext.correctly_padded(p, ct): This function interacts with the remote service to check if a given ciphertext has valid padding.main(): The main function initiates the attack by retrieving the encrypted token from the service and calling the padding_oracle_attack function.from pwn import *import binasciifrom tqdm import tqdm# Connect to the servicep = remote('kubenode.mctf.io', 30024)#p = process('./chal.py', level="DEBUG")#Based on the script provided here: https://github.com/flast101/padding-oracle-attack-explaineddef padding_oracle_attack(ciphertext): BYTE_NB = 16 # AES block size block_number = len(ciphertext) // BYTE_NB decrypted = bytearray() total_bytes = block_number * BYTE_NB with tqdm(total=total_bytes, desc="Decrypting", unit="byte") as pbar: # Go through each block for i in range(block_number, 0, -1): current_encrypted_block = ciphertext[(i-1)*BYTE_NB:i*BYTE_NB] if i == 1: previous_encrypted_block = bytearray(16) else: previous_encrypted_block = ciphertext[(i-2)*BYTE_NB:(i-1)*BYTE_NB] bruteforce_block = bytearray(previous_encrypted_block) current_decrypted_block = bytearray(16) padding = 0 # Go through each byte of the block for j in range(BYTE_NB, 0, -1): padding += 1 # Bruteforce byte value for value in range(256): bruteforce_block[j-1] = (bruteforce_block[j-1] + 1) % 256 joined_encrypted_block = bytes(bruteforce_block) + current_encrypted_block # Ask the oracle if correctly_padded(p, joined_encrypted_block): current_decrypted_block[-padding] = bruteforce_block[-padding] ^ previous_encrypted_block[-padding] ^ padding # Prepare newly found byte values for k in range(1, padding+1): bruteforce_block[-k] = padding+1 ^ current_decrypted_block[-k] ^ previous_encrypted_block[-k] break pbar.update(1) # Update the progress bar for each byte processed decrypted = current_decrypted_block + decrypted # Remove padding return decrypted[:-decrypted[-1]]def correctly_padded(p,ct): p.sendlineafter(b'> ', b'2') p.sendline(binascii.hexlify(ct)) response = p.recvline().decode() return("fortune is as follows" in response or "your fortune seems corrupted." in response)def main(): # Get the initial token from the service p.sendlineafter(b'> ', b'1') response = p.recvline().decode() token_hex = response.split(',')[0].split()[-1] token_bytes = binascii.unhexlify(token_hex) # Perform the padding oracle attack plaintext = padding_oracle_attack(token_bytes)[16:] print(f"Recovered plaintext: {plaintext.decode(errors='ignore')}")if __name__ == "__main__": main()
MetaCTF{5t4r3_1nt0_7h3_ciph3r}
The explanation and implementation of the Padding Oracle Attack are based on the work by flast101. The solution script solve.py is adapted from this explanation to solve the challenge.