Hey girls and guys! Following a request for write-ups from Circles (excellent job organizing the CTF by the way), we’re going to analyze how we captured Giratina (in the form of a flag). Without further ado, let’s begin!
The description of the challenge from the player board is the following:
“Giratina exploits some times while playing asciipoke :)”
The keyword “exploit”, as well as the fact that the challenge was in the “Exploit” category, gives us a strong indication that we need to exploit a Buffer Overflow vulnerability to get our flag.
Step 1: Identification
First things first! We need to find where the asciipoke (whatever that is) is hiding.
The first place to look is the pokestore and the PlayMon interface. Having a quick look at the pokestore, there is no sign of Giratina or asciipoke. It’s time to look in the PlayMon interface. By logging in the PlayMon interface using the credentials “user:user”, it appears that asciipoke is a 32-bit ELF file located at “/home/user/games/”.
Let’s run asciipoke and try to figure out what we need to do to get the flag and capture Giratina! The program asks for a Pokemon name and expects one of the following: blastoise, bulbasaur, charizard, pikachu and wartortle. When we type one of the aforementioned Pokemon names, the asciipoke program outputs the figure of the Pokemon in the form of ASCII art, hence the name “asciipoke”. By providing a long string (100 A’s), the program crashes due to a segmentation fault.
It’s time to investigate what caused the crash and what’s happening behind the scenes. Running asciipoke using GDB (GNU Debugger), we see that there is a buffer overflow vulnerability due to insufficient bounds checking. If you look closely below, you will see that the EBP and EIP registers are filled with 0x41414141 (AAAA) which indicates that our input has overwritten them.
By using the following command we can disassemble asciipoke to view the executable in assembly form.
objdump -D asciipoke -M intel
Scrolling down to the main method, we see that it makes a call to the read_input function which is probably the function responsible for handling our input. By investigating the read_input function we see that the it uses the scanf library function to read input from stdin (see 08048827) and that the input buffer starts 28 bytes before EBP (1c in hex is 28 in decimal). This means that the program reserves 28 bytes for the input buffer.
080487e3: lea eax, [ebp-0x1c]
For the hexadecimal-to-decimal conversion we used tconv, a custom wrapper script we developed for the CTF (we couldn’t find anything that wasn’t overkill for our purposes). For more info about tconv checkout https://github.com/runesec/tconv (we welcome forks and pull requests).
Now we know that 28 bytes are reserved for the input buffer which is just before the Base Pointer of the read_input function. This means that the next 4 bytes will be stored in the EBP and the next 4 bytes will override the return address (i.e., the address that the EIP register will jump to when it completes the function. So we can now control the flow of execution but we still haven’t figured out what we need to do to get the flag! Let’s fire up gdb to see the functions of asciipoke.
It appears that there is a function called pokemon_found which is not called during program execution. The name of the function is particularly suspicious, so let’s disassemble the asciipoke binary again (using objdump as we did earlier) and have a look at the pokemon_found function. We can see that it uses the fopen() library function which is used to open files. Considering that there is a file called asciipoke_flag in the same directory with asciipoke, it is reasonable to believe that asciipoke opens the asciipoke_flag file when the pokemon_found function is executed.
Maybe we should try to manipulate the program to call the pokemon_found function and see what happens!
Step 2: Plan attack
We need to craft a payload which will override the return address in an attempt to redirect the flow of execution and execute the pokemon_found function which is located at 0x080485fb.
Before crafting our payload, it is important to remember that our machine is little-endian which means that we need to reverse the order of the bytes of the pokemon_function address, i.e., \xfb\x85\x04\x08. This can be easily done using tconv as illustrated below.
Now, we need to fill the input buffer which is 28 bytes long, plus the next 4 bytes which is the EBP, plus the next 4 bytes which is the return address we want to override. Our payload should look something similar to the following:
Step 3: Execute
Let’s pipe our payload directly into the asciipoke binary and see what happens.
Hope you found the above useful. If you have any questions, drop us a comment on Facebook or Twitter.