Racecar
I had tried this one before but couldn’t solve it. After learning about binary exploitation and writing a few blogs on it, I decided to give it another shot.
First things first, I fired up Ghidra and looked at the decompiled code.
There it is, a Format String Vulnerability in that printf
statement. What is a format string vulnerability, you ask? Simply put, it is a printf
statement without format specifiers, which allows attackers like us to exploit it by supplying format specifiers like %p
to leak pointer addresses from the program, by simply providing them in the input.
Now that I had a way to obtain some information, I just needed to figure out what I wanted to extract. Easy, right? The contents of the flag.txt
file! But for some reason, it took me half an hour to figure that out.
Anyway, I noticed that the contents of the flag.txt
file are being stored in the _stream
variable, and that value is printed only when we win the race.
We’re asked to give a victory speech after winning the race—that’s the entry point! I can send tons of %p
, convert the hex into ASCII characters, and challenge completed, easy… or so I thought. It took much longer than expected.
In the screenshot, there’s an fgets
statement that clearly states the value of _stream
(which contains the value of flag.txt
) is stored in local_3c
. Ghidra gave me the address of the local_3c
variable, so I took it over to gdb
to examine the state of the stack right after I provided the malicious input.
The address of the local_3c
variable was 0x00001002
, so I set a breakpoint on that address and ran the program. But the program crashed. Why? I still can’t figure it out. If any of you have an idea, let me know! After an hour of trying several methods, I decided to look at a writeup. Guess what? I learned there are alternative ways to set breakpoints in gdb
.
gdb-peda$ break * (car_menu+881)
Oh, by the way, that car_menu+881
came from the instruction at 0x00001002
.
gdb-peda$ x/i 0x00001002
Now, I just input a bunch of %p
in the victory speech part, but nothing happened. Then I realized I had created an empty flag.txt
. So, I put AAAA
inside that file and examined the stack again…
Just to make sure this wasn’t a coincidence, I changed the contents of flag.txt
to BBBB AAAA
and checked again.
Yeah, the contents of flag.txt
can actually be read from the stack.
I did the same thing with the server: provided a bunch of %p
in the victory speech part, and it returned hex!
Put all of that, after removing (nil)
values, into CyberChef to decode it.
And look at that! There’s something that looks like a flag. Remember the format of HTB flags: HTB{some_text}
. To convert this string into that pattern, I wrote some simple (but horrible) C code.
It’s not very good, but it gets the job done. :)