32 bit ELF, with Partial RELRO, stack canary found, NX & PIE enabled.
First we'll have to play a game:
We'll have to control V with wasd, and the goal is to reach the E without being touched by those As. In the final stage, E will be changed to T, and we'll win the game by reaching T. After we beat the game, it will ask us to input a TARDIS KEY. At this moment, teammate yench started writing a python script to beat the game, while me and other teammates try to figure out what is the TARDIS KEY.
We found the following C code:
So it looks like the TARDIS KEY is a 10-byte-long string, which every character is the machine code in sub_EB8(), and the machine code should be an alpha-numeric character after it does the & 0x7F operation. After we dump the machine code and wrote a script to extract the correct byte, we got the TARDIS KEY = "UeSlhCAGEp".
Looks like it only gave us 2 options. But after we reverse the binary, we found that it actually has 3 options.
We'll have to make unk_50AC = 1. The only way to achieve this is to successfully turn on the TARDIS console:
The line LOBYTE(v4) = sub_E08(); will do the following checking:
and we can only write dword_50A4 in function sub_BCB():
Notice that dword_50B0 is the fd, and dword_50B0 is our input buffer(where the program store our options). By overflowing dword_50B0, we can overwrite the value stored in dword_50B0 (the initial value is 3, we'll have to overwrite it to 0(stdin) so we can write our input into dword_50A4).
To sum up, here are the steps for enabling the option 3:
1. Overwrite the fd (dword_50B0) into 0 by overflowing dword_50B0
2. Write the value into dword_50A4 so it can pass the checking function sub_E08(). Notice that sub_BCB() is called by sending the SIGALARM signal, so be aware of the timing.
3. Select option 1, for turning on the TARDIS console.
4. Option 3 will be enabled successfully after we turn on a TARDIS console.
Here's the payload:
After we successfully enable option 3, let's see what does it do:
So it will let us input our coordinates, and check the coordinates' value. If the coordinates are (51.492137, -0.192878), it will trigger the format string vulnerability. After leaking some messages, we found that we're able to leak the stack address. This is very important, since the binary has the PIE & Partial RELRO protection, we don't know where the text's base address is, neither functions' GOT address. But if we can leak the stack address, we can calculate the location that stored the return address, and leak the return address to calculate the text's base address. After we have the text's base address, we can calculate the functions' GOT address, and leak the function pointer. After we got all the memory address, we can use the format string vulnerability to overwrite atof's GOT entry into system's address, and execute our command by entering our commands as the coordinates.
So to sum up:
1. Leak the stack address and calculate the return address' location
2. Leak the return address and calculate the text's base address
3. Calculate atof's GOT and leak the function pointer
4. Calculate system's address and overwrite atof's GOT entry
5. Input coordinates "[command], [garbage]" to execute our commands
Here's the exploit. The part that beating the game was done by yench, while the rest was done by me.
Flag: Would you like a Jelly Baby? !@()*ASF)9UW$askjal