This weekend, Navaja Negra 8 CTF started, organized by ka0labs.org. This pwn challenge has the following statement:

Say the magic word to get the flag!

http://hackgym.ka0labs.org

The provided website is a phpinfo() output from the server, but with a string at the beginning.

lot_of_functions

As you can see, ka0labs team is formed by dick-painter teenagers. Ok let’s see what’s in the PHP Information. Scrolling down a bit, we can see an extension HackGym is loaded.

extension

At this point, a hint is released: Look at the HTML source code. And there it is, there’s a comment at the bottom of the HTML leaking a backup path for the loaded extension.

leak

Well, let’s download the shared object and open it using IDA and see what funcions we have:

ida_functions

If you have some PHP extensions background, you can easily identify what this functions are. For those newbies on PHP internals, there are a few functions PHP use when loading extensions, you can read more about this, from an offensive perspective in: https://www.tarlogic.com/en/blog/backdoors-php-extensions/

TL;DR: PHP_FUNCTION macro is where extension functions are defined.

So let’s analyze the PHP_FUNCION function, which really should be a PHP_FUNCTION macro, but for readability reasons, it’s badly written on purpose.

ida_lot_stuff

Ok lot of stuff, the interesting part is here

ida_php_funcion

This function is taking the X-Forwarded-For HTTP header, and passing it to kaboom function, so let’s see what this function does:

ida_php_funcion

In the first basic block, this function is taking our input, which is 256 bytes long, and writing it to a variable, there’s is another 256 bytes buffer containing the 8=====> ! JE! Target! 3% string. The next basic block, overwrites our buffer with this dick string.

On the third basic block, _ap_php_snprintf, a wrapper in PHP for snprintf function is called passing our overwritten buffer as argument. There’s more, the string of the placeholder will be nn8ed{...}. But wait, what placeholder string?

snprintf function works like this, you specify a string which is kind of a template string, and inside this template, you can specify placeholders which are going to be replaced based on what you indicate. For example:

char destination[256];
char * name = "Gonzalo";
snprintf(destination,256,"Hi my name is %s", name);

Will write the destination variable with "Hi my name is Gonzalo" string. Ok, do you remember that the replace string ended with a %? Din din din! We need to force the final string to end up in “s”, so the template string passed to snprintf will be 8=====> ! JE! Target! 3%s and the flag is going to be replaced as %s so the placeholder is replaced as seen in the example.

Let’s test:

GET / HTTP/1.0
Host: hackgym.ka0labs.org
X-Forwarded-For: XXXXXXXXXXXXXXXXXXXXXXXs
200 OK

8===D ! JE! Target! 3nn8ed{Th3_r1ght_f0rm4t_Off_by_1}

Win! The flag is returned at the beginning of the HTML as expected.

This challenge was easy for those people who know about format string bugs and PHP extensions, for those not so used to work with exploiting challenges or PHP extensions, is a great challenge to know some basics about it.

Congratz to ka0labs.org team and Navaja Negra.

See you!