Level Text

#include "../common/common.c" #define NAME "final0" #define UID 0 #define GID 0 #define PORT 2995 /* * Read the username in from the network */ char *get_username() { char buffer[512]; char *q; int i; memset(buffer, 0, sizeof(buffer)); gets(buffer); /* Strip off trailing new line characters */ q = strchr(buffer, '

'); if(q) *q = 0; q = strchr(buffer, '\r'); if(q) *q = 0; /* Convert to lower case */ for(i = 0; i < strlen(buffer); i++) { buffer[i] = toupper(buffer[i]); } /* Duplicate the string and return it */ return strdup(buffer); } int main(int argc, char **argv, char **envp) { int fd; char *username; /* Run the process as a daemon */ background_process(NAME, UID, GID); /* Wait for socket activity and return */ fd = serve_forever(PORT); /* Set the client socket to STDIN, STDOUT, and STDERR */ set_io(fd); username = get_username(); printf("No such user %s

", username); }

Intro

This level combines stack overflow and network programming for a remote exploit. The goal in this exercise is to get root privileges.

A short overview of the program: Starting in main, the process gets daemonized and waits for incoming connections from port 2995. Input, output and standard error descriptors are all redirected to the client socket. get_username() function gets called and the return value is printed to stdout which is redirected to the connected client socket. So far so good. In function get_username(), we can see that a buffer of 512 bytes gets cleared and filled using gets() function. From previous tasks we know that this is a insecure function in the way that it does not check if the user given input can be accommodated inside the buffer given as the argument. Later, after some character stripping, the buffer content gets converted to uppercase, copied and a pointer to it gets returned.

The first approach that came to my mind was making a tcp binding shellcode, putting it into buffer and overflowing the return address to point to the beginning of that shellcode. The main problem I needed to deal with was the toupper processing of the buffer. That is a problem because some shellcode operation code bytes fall in the range that would get transformed to uppercase characters (range 0x61 – 0x7a) and make a different instruction when executed. I will explain in more detail how I dealt with this in the Solution section.

Solution

Considering the approach described in the previous section, solution steps would look something like this:

Find location of return address. Find the location where the shellcode will be placed. Make shellcode. Construct and execute exploit.

Step1: We need to somehow find the location of return address we wish to overflow and make it point to our shellcode. Actually, we need to find the offset from the start of the buffer to the location of the return address. Instead of just using GDB to find all the addresses, I decided to take a different approach this time, for learning purposes. I wrote a simple program that looks like this:

I don’t know if this is the optimal solution but it works. In an infinite loop, we are creating connections with the “final0” daemon process which runs on a virtual machine located at 192.168.56.101:2995. Each connection will send 512 bytes to fill the buffer and additional i filler bytes (i increments every iteration) to try and hit the return address. This works because every time we send valid input, the daemon will respond with a message: “No such username” (or something similar), but when we hit the return address, the program on the virtual machine server will crash and generate a core dump instead of giving us that message. So the goal is to simply add more bytes in every iteration until no meaningful reply is received from the server which indicates that the program crashed.

NOTE: I posted an image instead of a code snippet because most of the time WordPress wrongly formats the snippet and turns it into gibberish.

After running the code, we get that the offset from the start of the buffer to the return address is 512 + 20 = 532 bytes. To verify this, we can look at the core dump using GDB command “gdb ./final0 /tmp/core_file” and then looking at the saved eip from the stack frame:

Step 2: Finding the location to place our shellcode. Well, because we have a pretty strong limitation given by toupper processing, I considered placing the shellcode immediately after the return address, that is, somewhere outside the buffer which will be toupper processed. Here is a diagram to show what I mean:

So our exploit payload would look something like this:

512_bytes_to_fill_buffer + 20_filler_bytes_to_reach_return + 4_bytes_address_to_NOP_sled + shellcode_bytes

Step 3: Next, we need to craft an exploit. This is supposed to be the harder part if we wan’t to do it by hand, but I’ll just skip doing it by hand this time and use a tool named msfvenom that comes preinstalled with Kali Linux. This tool provides functionality for crafting and encoding shellcodes for a variety of platforms. Although I think that writing shellcode by hand is better for learning and understanding purposes, I think that learning to use such tool is of great use when participating in CTF-s or when time is of the essence.

What kind of shellcode are we looking to make? Well, we have a remote virtual machine to exploit and get root access to so we will need some network programming involved. The usual stuff I found on the internet were TCP binding shellcodes so I used one of those. The idea is to create a remote listening process that listens on some port and waits for us to connect to it. When we connect to that port, the remote process will redirect stdin, stdout and stderr to the connected client socket (us) and using an execve call, spawn a shell which we will be able to send commands to. I will now show you how to do that using msfvenom.

Msfvenom provides a great deal of functionality but we will need only a small fraction of it for solving this exercise. Using the command: “msfvenom -l payloads | grep linux/x86 | grep tcp” we can list all interesting payloads and find the one that suits us. The one I used was: “linux/x86/shell_bind_tcp“. The best part about this tool and shellcodes it provides is that the shellcode is modular and you can specify the port you want for the process to listen on. So by looking at manpages and examples, we can construct the following command:

With -p option we choose a payload, and each payload can have additional arguments such as LPORT which is used to set which port will be used to listen on, -a option is used to specify the architecture (32 bit in this case because our victim system is an x86 system), then we choose Linux as our target platform and with -f we choose the format in which the shellcode will get outputted as (in our case Python is used because a Python script will be used to send the payload to the VM). If we omitted the -f option we would just get the raw instruction bytes. Now we can just copy and paste this python code into our python attack script.

Step 4: Constructing and executing the exploit. The only thing that is left for us to find out is the address of the NOP sled we will jump to when redirecting program execution. To find that out, we can construct our exploit to look like this:

“a” * offset + “bbbb” + nopsled * 20 + shellcode

and then simply look through the generated core dump and find out where the NOP bytes are (“\x90”):

Now when we found location of our NOP sled, we can simply use any address from that NOP sled to overwrite the return address with. Let’s choose 0xbffffc74 for example. The full exploit code now looks like this:

“a” * offset + “\x74\xfc\xff\xbf” + nopsled * 20 + shellcode

After executing the attack script, we can verify on the server side that there really is a process listening on TCP port 4444 using the command: “netstat -lt“:

And when we connect to the remote VM on TCP port 4444 using netcat we can get the shell and root access:

NOTE: I uploaded the full python attack script on my github page here.

That’s all, thanks for reading! 😀