Tags: aes-cbc crypto padding-oracle
Rating:
We start by observing that there are two classes of possible responses. If we submit the given cookie, it gives `Nop. :(` or `Don't be rude!`. If we submit a random hex string, it gives `That cookie looks burned!`. This suggests a potential padding oracle attack. Typically, a padding oracle attack is used to decrypt messages, but in this case we use it to encrypt.
We start by looking at how AES-CBC decryption works.![](https://defuse.ca/images/cbc_decryption.png)
Let $C_n$ be the nth ciphertext block. Let $P_n$ be the nth plaintext block. Let $D$ be the AES decryption function.
We see that $P_n = D(C_n) \oplus C_\{n-1\}$ This means that we can control $P_n$ by selecting $C_\{n-1\} = D(C_n) \oplus P1_n$, where $P1_n$ is the desired plaintext. However, this means we have to determine $D(C_n)$.
Next, we have to understand how PKCS #7 padding works. Let's assume the block size is 16 bytes, and the last block of plaintext is only 9 bytes long. We pad the remaining 7 bytes with the hex of the number of bytes remaining, `07`, which becomes `07 07 07 07 07 07 07`. If the last block of plaintext is exactly 16 bytes, we still need to add padding to signal that the previous block is unpadded. In this case, we append a block of 16 null bytes.
If a program gives a different output when this padding is wrong, then we can use that to get $D(C_n)$.
Let $A[i]$ be the ith byte of A.
We start by sending a 2 block message, a block of null bytes and the $C_n$ we want to decrypt. The first block will be treated as the IV, and the second block will be decrypted and xored with the IV.
`00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00` $\oplus$ $D(C_n)$
The only way this could have correct padding is if $D(C_n)[16] \oplus IV[16]$ has a last byte of `01` (or `02 02`, etc... but these are rare). Then we have determined the last byte of $D(C_n)$, since $D(C_n)[16] \oplus IV[16] = 1$, $D(C_n)[16] = IV[16] \oplus 1 = 0 \oplus 1 = 1$
Otherwise, we increment the last byte of the IV.
`00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01` $\oplus$ $D(C_n)$
Again, if this has correct padding, we have determined the last byte of $D(C_n)$, since $D(C_n)[16] \oplus IV[16] = 1$, $D(C_n)[16] = IV[16] \oplus 1 = 1 \oplus 1 = 0$
In general, we continue incrementing the last byte of IV until we get correct padding.
Once we get the last byte of $D(C_n)$, we can extend this process to get the second last byte.
First, we select the last byte of $IV$ such that $D(C_n)[16] \oplus IV[16] = 2$, which simply means $IV[16] = 2 \oplus D(C_n)[16]$.
Again, if this has correct padding, it means that $D(C_n)[15] \oplus IV[15] = 2$, as `02 02` would be the only valid padding here. Using similar logic as before, we continue incrementing $IV[15]$ until we have correct padding and then determine $D(C_n)[15]$. We can then repeat this whole process for every byte until we have $D(C_n)$. We can then select $C_\{n-1\} = D(C_n) \oplus P1_n$.
Combining all of this, we can create our exploit. We start by creating a random block of 16 bytes which will be our $C_n$. We select a $C_\{n-1\}$ such that $P_n$ is what we desire. We repeat this process to find a $C_\{n-2\}$, etc... until we reach $C_1$. That block will be our IV. We append all blocks together to get a ciphertext that decrypts to the desired plaintext, in this case, `Maple Oatmeal Biscuits`, and submit to get the flag.