I recently participated in the 2016 DEFCON CTF qualifiers. This is a write-up for the XKCD challenge which was in the PWN category.
Might want to read that comic as well… 1354
The XKCD for 1354 was related to Heart Bleed so it was obvious that this would be related to the Heart Bleed bug.
Running file on the binary revealed that it was a 64 bit elf and it was not stripped.
$ file xkcd
xkcd; ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, not stripped
Running the binary resulted in a missing flag error. This lets us know that the binary will be opening a flag server side.
In gdb it is clear that it is attempting to open a file named ‘flag’ for reading.
I created a flag file in our working directory and re-ran the binary. This time I get a MALFORMED REQUEST error no matter what input I give it. Of course I tried feeding it a large number of ‘A’s but got the same result. Time to start tearing this binary a part.
A quick look in objdump shows what I expect as far as an fread followed by a fgetln. I also see a call to strtok.
Running the binary with test data makes it easy to walk through the binary and see what it is expecting. It splits our input on ‘?’. It compares the first half of the input followed by the second half of the input. It then splits on ‘)’ and ‘(‘. If at any time, invalid input is detected, the execution flow is redirected to give the MALFORMED REQUEST error and exits.
After walking through the application, I discovered the valid input is: SERVER, ARE YOU STILL THERE? IF SO, REPLY “test” (4 LETTERS)
The binary does a srtlen on the input given and if the number of letters requested is longer than the input, the program returns “NICE TRY” and exits.
I identified the location of the input text buffer as well as the flag text buffer.
The buffer that is holding the input from the user runs up against the text that was read in from the flag file. I test sending just less than the buffer to confirm the null terminating characters before the flag text.
We need to find a way to trick the program into thinking that we have given more data than we have in order to get more data back (the flag). The strlen function is reading in at the beginning of the string that was carved out with strtok and ends at the terminating null character.
By testing with input, I can see that the input buffer is 0x200 bytes. When I send it an input of exactly 512 bytes, our buffer runs right up against the flag and there are no terminating null characters.
Now we try reading in more data than we give it to access the flag.
As you can see, we got the first part of the flag in the output.
Now that we have reverse engineered the binary and found the vulnerability, we can write an exploit to get the flag from the server.
Below is a short python script to exfiltrate the flag from the server one character at a time.
from pwn import *
host = 'xkcd_be4bf26fcb93f9ab8aa193efaad31c3b.quals.shallweplayaga.me'
port = 1354
buff = 'A'*512
for letter in flagSize(1, 50):
r = remote(host, port)
payload = 'SERVER, ARE YOU STILL THERE? IF SO, REPLY "%s" (%d LETTERS)' % (buff, 512 + letter)
line = r.recvline()
The final flag was: