Exploiting Format Strings: Getting the Shell
In this article, we will have a look at how to exploit format String vulnerabilities to get a shell.
In this article, we will briefly have a look at how to overwrite specific memory location, how to inject our shellcode in current memory of program and further overwrite the some desired memory address to execute our shellcode.
NOTE: Memory addresses shown in the commands can be totally different in your setup so you need to make calculation adjustments according to that.
Global Offset Table (GOT):
It is used by the program at compile time to determine the location of the function of used from external libraries. In this case, we are using objdump command to determine the location of putchar function using command: objdump -R ./fmt
We will now try to write arbitrary values to this memory location. To do that we open the program in gdb and executes the following command:
run $(python –c ‘print “x14xa0x04x08″‘)-%8$n
NOTE: The address used in the command is in little endian format because of intel architecture.
As can be seen, we can write some decimal value to the chosen memory location which in this case is 5. Also, if we examine the EIP it currently points to our arbitrary data. Till now we have got the idea that we need somehow to write memory address 0x5 with our shellcode memory address.
As we all know when a program executes it can access environment variables. Therefore, to inject our shellcode in current program memory, we exported an environment variable named SHELLCODE, we need to export this in the same terminal in which we are debugging our program, else it will not load when the program executes.
Our next is find the address where our shellcode begins; we do that by executing the following command within the debugger: find $esp,$esp+2000,0×90909090. As can be seen, the debugger returns us multiple 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
To write 0xbffff852 to the desired address we need to split it into two parts, and we will be writing first four lower order bytes, and then we go for higher order bytes. So first we need to write 0xf852, but we are already writing 0x10. Therefore, we will simply subtract 0xf852 – 0x10 which gives us 62834. Let’s write that down in our payload and rerun the program using following command:
run $(python –c ‘print “x14xa0x04x08″‘)-%62834u-%8$n
As can be seen, 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 our desired address. We can also check this by simply subtracting 0x5f82 – 0xf578. So our final payload becomes:
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 higher order bytes, we will be using another memory location into our format string and as we already know our first argument is placed at the 8th position so our second argument will be placed at the 9th position in the stack. As we have added four more bytes to our payload, we need to subtract these from the values we are currently writing i.e. 62844 becomes 62840. Therefore, our payload becomes:
run $(python –c ‘print “x14xa0x04x08″+”x16xa0x04x08″‘)-%62840u-%8$n-%9$n
By looking at the following screenshot, we will understand why we choose 0x0804a016 memory location. As we can see that 0x0804a014 is referencing 0xf852 and 0x0804a015 is referencing 0xf5 which is part of some lower order bits of desired memory address. Therefore, we chose 0x0804a016to write remaining bytes.
As we can see that our lower 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. After doing so, we got 51837. However, there are two more dashes (shown in blue color) introduced in our payload which constitutes for subtracting two from the value obtained. 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.