In this article we will discuss about Exploiting format strings: Getting the shell.
Introduction to Exploiting format strings: Getting the shell:
In this article, we’ll look at how to exploit String format vulnerabilities to gain shell access.
In this article, we will briefly look at how to override a specific memory location, how to put our shellcode into the current program memory, and further override some desired memory address to run our shellcode.
NOTE: The memory addresses shown in the commands may be completely different in your setup, so you must adjust the calculation accordingly.
Global Offset Table (GOT):
It is used by the program at compile time to determine the location of a function used from external libraries. In this case, we use the objdump command to determine the location of the putchar function using the command: objdump -R ./fmt
Now we will try to write arbitrary values to this memory location. To do this, we open the program in gdb and execute the following command:
run $(python –c ‘print “x14xa0x04x08″”)-%8$n
NOTE: The address used in the command is in little endian format due to the Intel architecture.
As you can see, we can write some decimal value to the chosen memory location, which in this case is 5. Also, if we examine the EIP, it is currently pointing to our arbitrary data. So far we’ve had the idea that we need to somehow write memory address 0x5 with our shellcode memory address.
As we all know when a program starts it can access environment variables. Therefore, in order to put our shellcode in the current memory of the program, we exported an environment variable called SHELLCODE, we need to export it in the same terminal in which we debug our program, otherwise it will not be loaded when the program starts.
Our next step is to find the address where our shellcode starts; we do this by executing the following command in the debugger: find $esp,$esp+2000,0×90909090. As you can see, the debugger returns us more patterns.
Let’s examine next 15 instructions at any of these memory addresses using command:
x/15i 0xbffff852. As can be seen, it shows the instructions from our shellcode which also means we need to write any of the shown memory addresses to the memory address discussed in previous steps, i.e., 0x0804a014.
We will now be using format specifier “u” to write decimal values directly to the memory locations. In the following screenshot, we can see we can write ten decimal values to the desired memory location using by running program with command run $(python –c ‘print “x14xa0x04x08″‘)-%10u-%8$n
In order to write 0xbffff852 to the desired address, we need to split it into two parts and we will write the four low-order bytes first and then go to the high-order bytes. So first we have to write 0xf852, but we already write 0x10. So we simply subtract 0xf852 – 0x10, which gives us 62834. Let’s write that to our payload and run the program again with the following command:
run $(python –c ‘print “x14xa0x04x08″’)-%62834u-%8$n
As you can see, the program ended with a segmentation fault and we are only able to write 0xf578 instead of 0xf582, which means we need to write ten more decimal values to write the desired address. We can also check this by simply subtracting 0x5f82 – 0xf578. So our final cost is:
run $(python –c ‘print “x14xa0x04x08″’)-%62844u-%8$n
As can be seen, we are successfully able to write lower order 4 bytes to our desired memory location.
Now, to write the higher order bytes, we’re going to use a different memory location in our format string, and as we already know, our first argument is placed at position 8, so our second argument will be placed at position 9 on the stack. Having added four more bytes to our payload, we need to subtract them from the values we are currently writing, i.e. 62844 becomes 62840. So our payload will be:
run $(python –c ‘print “x14xa0x04x08″+”x16xa0x04x08″’)-%62840u-%8$n-%9$n
If we look at the following screenshot, we will understand why we chose the memory location 0x0804a016. As we can see, 0x0804a014 refers to 0xf852 and 0x0804a015 refers to 0xf5, which is part of some low-order bits of the desired memory address. Therefore, we chose 0x0804a016 to write the remaining bytes.
As we can see, our low-order bytes are intact. Now we are currently writing 0xf852 and we need to write 0xbfff. So we need to subtract f582 from 0xbfff. However, 0xbfff is a smaller value than 0xf582. Therefore, we will use some higher value for subtraction, which is 0x1bfff. We then got 51837. However, two more dashes (shown in blue) are introduced in our payload, representing the subtraction of two from the obtained value. Our final payload becomes:
run $(python –c ‘print “x14xa0x04x08″+”x16xa0x04x08″’)-%62840u-%8$n–%51835–%9$n
As can be seen, our debugger is executing another program which simply a bash shell.