http://167.71.246.232:8080/netrun.txt
Scroll down for netrun.php
, the source code given for the challenge.
The front end is simply a little form where you get to enter some plaintext and recieve ciphertext after a 128-bit AES-ECB encode.
The catch: the flag, along with some bytes of additional garbage, are added onto your input plaintext as (right) padding.
You gotta know your cryptography jargon to get a good foothold for this one. Googling "chosen plaintext attack aes ecb" got me to
https://crypto.stackexchange.com/questions/42891/chosen-plaintext-attack-on-aes-in-ecb-mode
and eventually
https://cedricvanrompay.gitlab.io/cryptopals/challenges/09-to-13.html#Challenge-12---Byte-at-a-time-ECB-decryption-(Simple)
which was a really nice beginner's tutorial on doing exactly the attack needed here. (Credits to Cédric Van Rompay)
The idea behind the attack: Send 31 bytes of something simple: in my case, this was 31 A
s. Call this the target
cyphertext.
The 32nd byte will be the first byte of the right padding (the CTF's format was flag{...}
, so in this case, we already know it's 'f'
).
Because AES-ECB is a (16-byte) block cypher, 32 bytes of plaintext correspond exactly to 32 bytes of cyphertext.
The rest of the padding past the f
won't affect those first two blocks of cyphertext.
Then, run through all printable characters i
, and check if 31 A
s + i (so all 32 bytes) produces are cyphertext
that shares a 32 byte prefix with the target
cyphertext above.
When we get to i = 'f'
, the current cyphertext and the target cyphertext will share that prefix. That's how we know we found the first byte of the padding.
Finally, repeat this by shifting the A
s buffer down: use a target plaintext of 30 A
s following by an f
.
Once we find that the cyphertext from 30 A
s + 'f'
+ i shares a common prefix, we've found the next byte.
Continue until either our buffer of A
s run out, or we get the entire flag: flag{b4d_bl0cks_for_g0nks}
.
Our pitfalls:
- The first time around, I chose a buffer of 16
A
s. This was too short, and we had to figure out how to generalize the approach. - The length of the cyphertext / common prefix was different from what we expected. This was because we needed to b64decode the response.
- We started this a couple hours before the end of the competition. We should've attempted this sooner, and got more sleep instead.