This is my writeup for the twenty-fifth challenge in the PlaidCTF 2011 competition. The information for the challenge was:

“Amalgamated has banned the use of Solitaire due to loss of productivity.
The only employee who would write a new game for everyone only likes ‘retro’ games, and has placed a text-adventure version of pacman on a company server.
We don’t believe he could have coded this securely, and the server contains a vital key.
Connect to the game here and find the key.
nc a9.amalgamated.biz 60123”

There was no binary available for download, so this level was actually completely blind. Connecting to the game we get:

Typing “help” gave a list of valid commands:

Walking around in the maze eating pills we notice a few things. First I noticed that after eating 16 pills, each increasing my number of points with 8, my number of points suddenly becomes -128. This indicates that a signed 8-bit integer is used to store the number of points.

We also notice that the number of power points seem to determine which item that is listed in our status. Each time we eat a powerpill the number of points increase with 40, and each time we make a move the number of power points (if any) decreases with one. The somehow odd “t” command which is described as “wait” decreases the number of power points with one as well, and surely this must be for a reason.

Moving on through the game eating pills and powerpills as we encounter them, we will sooner or later run into this situation:

We cannot eat another powerpill since this would put us over the maximum of 128. However, if a signed 8-bit integer is used for the number of powerpoints as well the real maximum should be 127. Let’s use the “t” command a few times until our number of powerpoints is 88, and let’s see what happens when we eat the powerpill:

Notice anything strange? Well, besides now having a negative number of powerpoints (which we sort of expected) we can also see that our item-string is now “n” instead of “The some-name Trophy!”. Since the number of powerpoints seemed to determine the item that is listed, it seems likely that the number of powerpoints is used as an index into an array of items/trophies and that when a negative index is being used (-128) it will point into some other string that in this case happened to be “n”.

So where does this “n” come from? Well, since “n” is one of the commands for this game it could certainly be a command string that I’ve entered earlier. It’s not the last command I’ve entered though, so if “n” is indeed a command it is probably stored in a command history buffer. Looking back through the scrollback we also notice:

See the “Command limit reached.” message? We got that on our 127:th command, which probably means that a history of 127 commands are being stored in an array. If this array is stored right before the item string array, the “n” listed as our item after getting a negative number of powerpoints may be taken from this command history array. So, let’s see what happens if we use “t” or some other command until the command limit is reached again:

As you can see I’ve jumped ahead a bit to show you how this bug is turned into an exploitable vulnerability. The very first command entered after the command limit has been reached is used as the item-string, and is actually being passed directly as the format string argument to presumably printf(). This allows to read memory, like we do above, or even write to arbitrary addresses using the %n format string specifier.

After the number of power points have been wrapped into -128, it stays there, so now we can just wrap around the command history buffer each time we want to use a different format string. I developed the following script for being able to play around, enter different format strings and examine their output:

Note that {32-bit-integer-in-hex} will be converted to a raw binary 32-bit integer by the script. This can be used to embed addresses to dump or overwrite. Here’s a sample session:

Here I first determine the offset to the command buffer, by dumping the stack four bytes at a time with %x. The first three bytes are overwritten by a command that has been sent later (‘t’ = 0x74), so if we want to embed an address to read from or write into we should prepend some padding. My second attempt uses %12$s to dereference the pointer that I embed at offset 12 (0x08048000). Obviously NUL-bytes are not a problem, as long as they are located after the format string. The format string buffer is actually located in dynamically allocated memory on the heap, while the command buffer is located in a local variable on the stack. The only problematic byte is 0x0a (e.g. ‘\n’ = line-feed), which ends the command string and is converted to a NUL-byte in the buffer.

Using this technique we are able to dump the entire binary for the level, except for a few bytes at addresses containg 0x0a that we assume are NUL-bytes. This produces a valid enough binary for further analysis in IDA Pro, where we can clearly see the vulnerable call to printf:

We also see that fgets() is used to read our commands, and that the line-feed character is converted to a NUL-byte, just as we have observed:

If we use the format string vulnerability to overwrite a GOT-entry, fgets() seems to be the perfect choice since its first argument happens to be a pointer to our buffer. If we embed a command line to be executed there and point fgets() into system() instead, our command line will be executed.

Now we just need to find system(), either by bruteforcing it or by reading a GOT-entry and calculating the address to system() based on its offset from the function whose GOT-entry we’ve read. We used the latter method to find system() based on its offset from fgets(). Since we had not yet noticed that a5 and a9 used the same libc, we first dumped libc using this vulnerability as well. :) Finally, we ended up with the following exploit:

And finally, here is a sample run:

This is my writeup for the thirty-sixth challenge in the PlaidCTF 2011 competition. The information for the challenge was:

“AED came up with a secret sharing program that looks like innocent food ordering program.
However, there is an information that if you are able to order the following set of food, you can get the secret key.

IMPORTANT: SOUND is VERY VERY IMPORTANT for this mission!!!! MAKE THE VOLUME LARGE before you actually do stuff…

Reverse the program to find out the key!

10 Regular Hamburgers
5 Cheeseburgers
17 French Fries
8 Hot Dogs
20 Regular Coke”

Taking a quick look at the challenge with IDA Pro and OllyDbg respectively I could see that it’s packed, and that it uses miscellaneous anti-debugging and anti-dumping techniques. To get acquainted with the application I tried to make the order, which gave me the following error message after adding 10 regular hamburgers, 5 cheeseburgers and 11 french fries: “You cannot have more than 25 items in your cart.”

When clicking OK and then the Order-button, I got: “Your order confirmation code is Th3m1d4_iS_s!cK”. At this point I couldn’t imagine that I’ve already found the real key, so I continued with trying to reverse-engineer the program for a while before attempting a different order, which resulted in a completely scrambled string as the order confirmation code. Turns out that the developers for this mission messed something up bigtime, and that “Th3m1d4_iS_s!cK” was the actual key. Might look into actually reversing the program someday, but for now I settle with the key. :D

I’m glad that our team would have won the competition even without these 250 points though, wouldn’t have felt fair if this would have been the difference between winning and losing. :)

This is my writeup for the twenty-sixth challenge in the PlaidCTF 2011 competition. The information for the challenge was:

“nc a9.amalgamated.biz 10241”

The binary for the server listening on this port was also available for download. Turns out that this challenge is almost identical with hashcalc1, except for the fact that it is executed through inetd instead of using its own socket handling. Also, in this case the call to strlen() in the function that calculates the hash is inlined. There is another call to strlen() in the function that writes to the socket though. Since the string has been prepended with “<hash> (” before our buffer we need to make sure that this string can be interpreted as valid instructions as well, without triggering a crash.

To change the hash I could simply append to the string, and ended up with the following:

In another tty:

This is my writeup for the twenty-third challenge in the PlaidCTF 2011 competition. The information for the challenge was:

“It seems like AED also has some plans to raise hacker force!
We found this binary as an exploitation practice program in the office, but they forgot to remove the setgid flag on the program.
So we can get the secret key!
ssh username@a5.amalgamated.biz”

Using IDA Pro I see that the binary contains a deliberate stackbased buffer overflow, designed to allow us to overwrite a pointer that is later dereferenced and written into with a user defined value. The decompiled code is as follows:

The pointer p is located directly after the 64-bytes buffer we’re overflowing, and the value we’re writing into the pointer is taken from our second command line argument. Since exit() is called directly after this, we use this to overwrite its GOT-entry. As you can see below, this is located at 0x80497f4.

Since a pointer to our buffer is located at offset 8 on the stack when exit() is called, due to the previous strncpy() call, we can use a pop-pop-ret trampoline to jump there. I found one at address 0x80484d2, and could use this for the following exploit:

If NX would have been effective this challenge would have required some further digging to find a suitable ROP gadget for running system() or execve() for instance. In this case I settled with this to get the key: K3Ys_t0_15_M1nUtEs_0f_F4mE

This is my writeup for the twenty-second challenge in the PlaidCTF 2011 competition. The information for the challenge was:

“nc a9.amalgamated.biz 30001”

The binary for the server listening on this port was also available for download. Simply running strings on the binary reveals that it is a forking socket server that spawns a new process to handle each incoming connection. Connecting to the service we get:

This is an example of connecting to the service on my own machine:

The service prompts for a string, calculates its hash and prints it out to the user before closing the connection. If we send a string slightly larger than 256 bytes the connection is abruptly closed though, which most likely indicates a buffer overflow. Since the binary is compiled with stack canaries enabled this may not be all that useful though. A quick inspection in IDA Pro reveals that the buffer overflow is due to a vsprintf() in the function at 0x08048b22, which I’ve named sock_printf() to be a bit more descriptive. The decompiled version is as follows:

There is also code for checking a stack cookie, but since that is automatically inserted by the compiler I’ve omitted that part from my decompiled code. As you can see, there really isn’t much of value to overwrite on the stack unless we can predict (or bruteforce) the stack cookie, or patch the GOT-entry for ___stack_chk_fail(). Luckily for us there is another issue to exploit, that is revealed by simply sending a “%n” as the string to hash. This will also result in the connection being abruptly closed, which indicates a format string vulnerability.

In IDA Pro we can see that the format string vulnerability is triggered by an fprintf(log_fp, buf), right before the hash is calculated. Since the output is written to a logfile and not back to the socket we are not able to use this to read data from the stack. Since our buffer is on the stack we can easily use this to achieve arbitrary writes to arbitrary addresses though, by embedding the addresses we want to write to in our buffer and finding the offset to the buffer by, for instance, embedding a known writable address in our buffer, using %n at different offsets and switching to a known invalid / non-writable address for each offset that does not trigger a crash. Since we have access to the binary we can determine the offset (5) directly by analyzing the code though.

Due to a mistake by the PlaidCTF organizers, NX was not effective and ordinary shellcode could be used, which saved me some time. Since strlen() is called directly after the vulnerable fprintf(), in the function that calculates the hash, I chose to use the format string vulnerability to overwrite the GOT-entry for strlen() at address 0x0804a41c. Since the stack is randomized it would require bruteforcing to find our shellcode in the stack, but since a pointer to our buffer is passed as the first argument to strlen() we can just stuff our shellcode into the beginning of the buffer and use a suitable trampoline from the binary itself, which is mapped on a fixed address. A pop-ret or a call eax would be good for this purpose, since the buffer pointer is copied into eax before being passed as an argument. I chose the latter, at address 0x080491cb.

At this point of the competition I felt pretty lazy, so ended up exploiting it with a one-liner instead of creating a script for it:

The file cb.bin is an 80 bytes connectback shellcode. Since the beginning of our buffer was at offset 5 I add 20 to this now when I’ve embedded the addresses to write to after the shellcode (20*4=80), and end up with %25$hn and %26$hn to overwrite the two most significant bytes and the two least significant bytes of the GOT-entry respectively.

In another tty I’ve set up a netcat listener on the port that the connectback shellcode connects to: