I had some free time over the weekend and I decided to jump into a CTF competition to get some practice in. I haven’t heard about PWNSEC yet so I decided to take a look at their CTF and solve a few challenges.
Taco Shop was a simple reverse engineering challenge at PWNSEC CTF 2024. The challenge could be solved multiple ways and I decided to stick to a manual solution to learn as much from solving it as I can. In the end, I’ve collected some useful references and added a few tools under my belt
Initial analysis
Running the challenge will show a menu to choose from:
I tried playing around with it for a bit at first. Passing negative numbers as menu choices and aside from a few witty meals I quickly realized there isn’t anything to be gained from such blind tampering.
I decided to load it into Ghidra
and while the analysis concluded I took a look at the exports in r2:
Not very helpful either. I jumped into Ghidra and saw it couldn’t recover many functions either:
Guessing it might be compressed or packed somehow I used strings
to possible get references and found what I was looking for:
According to their website:
UPX is a free, secure, portable, extendable, high-performance executable packer for several executable formats.
Since I wasn’t familiar with it, I looked up how unpacking is done and after a bit of gooooooogling I stumbed upon this article: https://dlnhxyz.medium.com/manually-unpacking-a-upx-packed-binary-with-radare2-part-1-7039317c2ed8
First round of unpacking
This was perfect as It didn’t just allow me to get some practice with manual binary analysis, but I had a chance to practice with radare2
as well! I’m a sucker for CLI goodies so I read through the article and tried to follow along.
I learned how to use the visual debugger interface. Stepping over and into functions and the dcs
command to run until we encounter a syscall
. I got to where I could dump all memory maps with the dmda
command, reconstructed the unpacked elf file from these separate regions and I was successful.
I checked the resulting binary with strings
once again and found a bunch of interesting strings.
Unfortunately, all of this was just trolling:
I threw the entire thing into Ghidra once again but this time it was even worse:
So I thought I’d try going back to r2
and debug the binary but I got the following error:
The binary detects the presence of the debugger by using ptrace
. We can see this in the strace
output from earlier:
Looking at the definition of ptrace
we can see this might happen if the binary is already being traced. Indeed it is as we’ve already attached GDB to it.
Naturally, we can simple patch this check and jump over it.
Second round of unpacking
In GDB, I would’ve used the catch syscall ptrace
command to set a breakpoint at around ptrace
and move my way up from there. But how could I do that with r2
? I wanted to learn!
I didn’t find how to do this easily and the break command didn’t work for me so I came up with the following:
- Load the binary into
r2
- List the mapped memory regions with
dm
- Move the starting and ending addresses of the mapped, unpacked binary to
dcu <starting address> <ending address>
as these are where we’ll eventually find the relevant code - Let it run until we’ve hit the segments where the relevant code is
I had to run this a few times as I wasn’t sure I was on the right track but then I noticed the following:
We can clearly see __libc_start_main
being called. From here I only had to take a few steps and I got to Nirvana:
Reversing the final stage
As I was sure at this point the correct code was mapped to memory I did the trick of dumping the memory ranges with dmda
again and after loading the resulting binary into Ghidra, creating a few functions and cleaning it up a bit I got the actual code in there:
From here it was fairly straightforward:
- The binary reads your choice
- It then checks your input against a “secret password”
- If it’s correct, you get the flag
The secret password based on the function is the base64 decoded value of RnIzM19QNGwzU3QxbjMK
which is Fr33_P4l3St1n3
Passing the password to the program will give you the following:
Not sure if I’m an idiot, but I didn’t realize the flag was PWNSEC{Fr33_P4l3St1n3}
…. I thought there was another secret item to find in there. I even hit up an organizer to check if there’s something else I’ve missed but after a while I submitted the flag and got the points.
Interesting challenge. Learned a lot, practiced reversing, familiarized myself with r2
and got the flag. This was pretty cool!
~ r4bbit