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. :)