# Hack.lu 2013: Wannabe

One of our informants met a guy who calls himself Elite Arthur, he is a real jackass, and he thinks he is the best hacker alive. We got reason to believe that the robots hired him to write the firmwares for their weapons. But to write such a firmware we need the key to sign the code. Luckily for us, our informant also found his website: …. your job is to hack the server, find the flag and show this little cocksucker how skilled he really is. We count on you.

Alternatively, you can reach the challenge without a reverse proxy but also without SSL here: http://ctf.fluxfingers.net:1339

This challenge consists of two long parts. First some web stuff, then an exploitation challenge.

## The web page

First, we had to find a way to get onto the server. Our best call was to find a PHP code execution.

We figured out the “Bug bounty” page would be worth trying to get some sourcecode out of. The download function seemed very suspicious. By modifying the INSERT statement through the ‘rating’ parameter we could download any file we wanted:

This adds a download to ‘index.php’ (encoded as hex). By looking through the sourcecode we found the code where we could get our code to be executed:

And the code where to insert it:

But we still need the admin password for that. By digging deeper in the code we found a way to reset the password of the admin. This is done in four (easy) steps:

1. Request reset code for guest
2. use the SQLi to read it
3. reset password via GET with id=0x1 (vulnerable code shown below)
4. insert our code

When this code is executed, it resets the admin password and executes the code you supply on the command line. Why is this resetting the admin password? By using 0x1 we are exploiting the way php handles comparisons between different types:

While the weak comparison in line 1 interprets 0x1 as 1, it matches the id of ‘guest’, but the intval on line 6 returns 0 for 0x1, matching the id of ‘admin’. This allows us to use the reset code for ‘guest’ to reset the admin’s password.

## Exploitation

After we got shell access to the server, we found a file which looks like the flag /home/arthur/sign_key.flag , but for which we didn’t have read access. However, there was a suid executable together with its source code, which does have these permissions, so let’s take a look at it.

The binary has two modes, clean and sign, and will read the flag file and a password file in a constructor. The first thing the sign mode will do is to check if the contents of the password file match a user-supplied argument. Since we don’t know the password, this looks like a dead end.

The clean method on the other hand does not need the password. It iterates over all files in the folder ./uploads and checks them for occurences of the string system(".*"); .

As you can see, the function reads at most 192 bytes at a time and writes them into a global buffer array of size 255*192 using an unsigned char as index variable. This is a double off-by-one error.

If we provide a file with 256 system(""); entries, the global cookie variable will be overwritten. Also, if the argument to system is longer then 192 bytes, there will won’t be a null byte at the end of that entry. We can use these vulnerabilities in the log_result function:

If we wrote more than 192 bytes into found[i], snprintf will append the contents of found[i+1] as well which will overflow the local buffer. Since the overflow happens in a loop, we can even write data which includes null bytes by writing to the buffer multiple times, making the string shorter in each write. For example, if we want to write AAAA\x01\x00\x01\x00, we will write AAAAAA\x01 first and afterwards, overwrite the beginning with AAAA\x01\x00. The overflow protection is already bypassed as well, since we control the cookie variable as described before.

Finally, since the binary is not position-independent, we can simply call puts from the PLT, using a pop rdi gadget before that, to load the first parameter and print the flag from memory.

The final exploit works as follows:

1. write system(“AAAAAAA..”); 256 times to ./upload/pwn, which will overwrite the cookie variable
2. overwrite the saved return address with a ROP chain: “pop rdi” gadget; &key; puts@plt; exit@plt