This weekend, I participated in the Facebook CTF event. The quality of challenges in this CTF was decent, but the event was marred by significant connectivity problems, rendering it unplayable for a significant portion of time for me.
I solved two challenges during this event, as always, the writeups are below.
This challenge was presented as a web challenge, with corresponding source code, which you can download here.
We can identify the core of the challenge by reviewing db.php:
Inspection of the source code shows that there is surprisingly limited attack surface, and that all SQL queries are sensibly parameterised. A poor choice of setup in the CTF gave the solution away: I noticed that at one point, two “facebook” entries were present in the “top 5” list.
This indicated that it was possible to both add another entry called “facebook” (or close to it), and that the web application was a shared, stateful application – an interesting choice for the expected player turnout.
A bit of fiddling later, and I was able to add “facebook” with an encoded space (“+”) at the end:
Following this, I could extract the flag by correctly supplying the secret that I knew.
Logic would have it that this was an edge case in MySQL, regarding adding items with blank spaces after them in queries, or matching them – a useful trick for later, but 100 points for now.
This challenge was presented as a pwnable challenge. The pwn binary can be downloaded here, along with the corresponding libc.
Upon initial analysis, this application performed some floating point maths:
I did some local debugging with gdb and comparing inputs and outputs, but got nowhere until I used retdec to decompile the binary. You can download the decompiled source here.
This made the program logic much clearer, and the structure was immediately revealed as a “rop builder” challenge: the program would effectively allow the user to enter rop gadgets at will as floats, and then trigger a stack-based overflow. To bypass the first hurdle, I created a simple C program which did the appropriate float conversion. You can download this here.
We can quickly confirm that we have the appropriate stack execution:
From here, traditional wisdom (and the fact that we have libc) indicates that we should leak an offset within libc, reset execution, then re-exploit the overflow to call a magic gadget (or system-equivalent point) to get a shell.
The leak was trivial to accomplish through loading RDI then calling puts at 0x400690. The program execution is reset to 0x400749, and then the exploit is re-fired against a known target. Of note, note that RBP is fucked at this point thanks to the leave instruction, and the remote target behaved differently to my local machine, resulting in a frustrating period of yes/no debugging via printf rop chain links – but flags are flags.
You can download the complete exploit here.
Thanks to the organisers and challenge creators of this CTF – this was a good exercise for someone who hasn’t CTF’ed for quite some time, and a steady reminder that no matter the strengths of one’s motivations, only results matter. See you in the next CTF.