We are given following source code and hints:
Stack6 looks at what happens when you have restrictions on the return address.
This level can be done in a couple of ways, such as finding the duplicate of the payload ( objdump -s will help with this), or ret2libc , or even return orientated programming.
It is strongly suggested you experiment with multiple ways of getting your code to execute here.
We will solve this stack exercise with return-to-libc and return-orientated programming. The source code looks similar to stack five however, its mentioned as hint: we have a restricted return address. Let’s disassemble getpath()
Have a look at <getpath+32>
: it tells us how big our buffer is up to the beginning of the basepointer $ebp
: 0x4c
(=76 in decimal). So we need 80 characters (+4 because we want to have the old $ebp
inclusive) as padding. Any additional characters will override the return address. Our stack looks at <getpath+32> like this:
Running the exploit from stack five results to an “bzzzt (0xbffffcc0)” in stdout. Looks like we can not execute our shellcode on the stack:
And indeed: Our stack is located beginning from 0xbffeb000
, this means we will not take the jump at <getpath+62>
and exit the program. I will show here two solutions: 1. return-to-libc and 2. return-oriented programming
Return-to-libc:
We start stack6 with gdb, search for system and remember its address:(gdb) print system
$1 = {} 0xb7ecffb0 <__libc_system>
Then, we search for /bin/sh, but not in gdb since it seems to show a wrong address for /bin/sh. We will use strings and print the offsetroot@protostar:/opt/protostar/bin# strings -t x /lib/libc-2.11.2.so | grep "bin/sh"
11f3bf /bin/sh
Adding the offset to the address where libc is loaded results to 0xb7e97000+0x11f3bf = 0xb7fb63bf
We are not done yet. Since we are calling the system
function and passing it an argument (/bin/sh), we should also put a return address on the stack. Otherwise our exploit will not work. The return address of system
does not have to be a valid address. Our stack should look like this before we execute ret in <getpath+117>
:
This stack looks similar to a resulting stack with a “normal” function call: First we push the arguments on the stack, then we push the return address on the stack.
Our exploit is ready:
Another way to solve stack six is return oriented programming. Basically we will make ret <getpath+117>
call itself. This will pop the return address from top of the stack and set the instruction pointer $eip again to ret <getpath+117>
The resulting exploit was only working in gdb, but not when piping it to the stdin of stack6. It seems like on the bottom of the stack (higher memory region) environment variables are different. We can overcome this with a NOP slide. The total amount of No-operation was chosen randomly.