# Heap Exploitation

This module is literally just an explanation about how various parts of the heap work. The heap is an area of memory used for dynamic allocation (that is, it can allocate an amount of space that isn't known at compile time), usually through the use of things like [malloc()](https://man7.org/linux/man-pages/man3/malloc.3.html). The thing is malloc has a lot of functionality behind how it operates in order to efficiently do its job (both in terms of space and run time complexity). This gives us a large attack surface on malloc, like in certain situations in which we can leverage something such as a single null byte overflow into full blown remote code execution. However in order to carry out these attacks effectively, you will need to understand how certain parts of the heap work (it can get a bit more complicated than overwriting a saved return address of a function in the stack). The purpose of this module is to explain some of those parts. Let's get to work. Let's get to work.

## Libc

The first thing I would like to say is that on linux all of the source code for standard functions like malloc and calloc is located in the libc. Across different libc versions the code for various functions changes, including the code for malloc. That means that different libc's mallocs operate in different ways. For instance, the same binary running with two different libc versions, can see different behavior in the heap. You'll see this come up a lot. When you are working on a heap challenge, make sure you are using the right libc file (assuming the heap challenge is libc dependent). You might need to use something like `LD_PRELOAD` to do this (which you can see how I tackle this in the upcoming sections).

## Malloc Chunk

When we call malloc, it returns a pointer to a chunk. Let's take a look at the memory allocation of the chunk for this code:

```
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void main(void)
{
    char *ptr;

    ptr = malloc(0x10);

    strcpy(ptr, "panda");
}
```

We can see the memory of the heap chunk here:

```
─────────────────────────────────────────────────────────────── code:x86:64 ────
   0x[PII_REDACTED]4b <main+22>        mov    rax, QWORD PTR [rbp-0x8]
   0x[PII_REDACTED]4f <main+26>        mov    DWORD PTR [rax], 0x646e6170
   0x[PII_REDACTED]55 <main+32>        mov    WORD PTR [rax+0x4], 0x61
 → 0x[PII_REDACTED]5b <main+38>        nop    
   0x[PII_REDACTED]5c <main+39>        leave  
   0x[PII_REDACTED]5d <main+40>        ret    
   0x[PII_REDACTED]5e                  xchg   ax, ax
   0x[PII_REDACTED]60 <__libc_csu_init+0> push   r15
   0x[PII_REDACTED]62 <__libc_csu_init+2> mov    r15, rdx
─────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "try", stopped, reason: BREAKPOINT
───────────────────────────────────────────────────────────────────── trace ────
[#0] 0x[PII_REDACTED]5b → main()
────────────────────────────────────────────────────────────────────────────────
gef➤  search-pattern panda
[+] Searching 'panda' in memory
[+] In '[heap]'(0x[PII_REDACTED]00-0x55555557a000), permission=rw-
  0x[PII_REDACTED]60 - 0x[PII_REDACTED]65  →   "panda"
gef➤  x/4g 0x[PII_REDACTED]50
0x[PII_REDACTED]50:    0x0    0x21
0x[PII_REDACTED]60:    0x61646e6170    0x0
```

So we can see here is our heap chunk. Every heap chunk has something called a heap header (I often call it heap metadata). On `x64` systems it's the previous `0x10` bytes from the start of the heap chunk, and on `x86` systems it's the previous `0x8` bytes. It contains two separate values, the previous chunk size, and the chunk size.

```
0x0:    0x00     - Previous Chunk Size
0x8:    0x21     - Chunk Size
0x10:   "panda"     - Content of chunk
```

The previous chunk size (if it is set, which it isn't in this case) designates the size of a previous chunk in the heap layout that has been freed. The heap size in this case is `0x21`, which differs from the size we requested. That's because the size we pass to malloc, is just the minimum amount of space we want to be able to store data in. Because of the heap header, `0x10` extra bytes are added on `x64` systems (extra `0x8` bytes are added on `x86`) systems. Also in some instances it will round a number up, so it can deal with it better with things like binning. For instance if you hand malloc a size of `0x7f`, it will return a size of `0x91`. It will round up the size `0x7f` to `0x80` so it can deal with it better. There is an extra `0x10` bytes for the heap header. Also the `0x1` from both the `0x91` and `0x21` come from the previous in use bit, which just signifies if the previous chunk is in use, and not freed.

Also the first three bits of the malloc size are flags which specify different things (part of the reason for rounding). If the bit is set, it means that whatever the flag specifies is true (and vice versa):

```
0x1:     Previous in Use     - Specifies that the chunk before it in memory is in use
0x2:     Is MMAPPED          - Specifies that the chunk was obtained with mmap()
0x4:     Non Main Arena      - Specifies that the chunk was obtained from outside of the main arena
```

We will talk about what some of this means later on.

## Binning

So when malloc frees a chunk, it will typically insert it into one of the bin lists (assuming it can't do something like consolidate it with the top chunk). Then with a later allocation, it will check the bins to see if there are any freed chunks that it could allocate to serve the request. The purpose of this is so it can reuse previous freed chunks, for performance improvements.

#### Fast Bins

The fast bin consists of 7 singly-linked lists, which are typically referred to by their `idx`. On `x64` the sizes range from `0x20` - `0x80` by default. Each idx (which is an index to the fastbins specifying a linked list of the fast bin) is separated by size. So a chunk of size `0x20` would fit into `idx` `0`, a chunk of size `0x30` would fit into `idx` `1`, and so on and so forth.

```
────────────────────── Fastbins for arena 0x7ffff7dd1b20 ──────────────────────
Fastbins[idx=0, size=0x10]  ←  Chunk(addr=0x602010, size=0x20, flags=PREV_INUSE)  ←  Chunk(addr=0x602030, size=0x20, flags=PREV_INUSE)
Fastbins[idx=1, size=0x20]  ←  Chunk(addr=0x602050, size=0x30, flags=PREV_INUSE)
Fastbins[idx=2, size=0x30]  ←  Chunk(addr=0x602080, size=0x40, flags=PREV_INUSE)
Fastbins[idx=3, size=0x40]  ←  Chunk(addr=0x6020c0, size=0x50, flags=PREV_INUSE)
Fastbins[idx=4, size=0x50]  ←  Chunk(addr=0x602110, size=0x60, flags=PREV_INUSE)
Fastbins[idx=5, size=0x60]  ←  Chunk(addr=0x602170, size=0x70, flags=PREV_INUSE)
Fastbins[idx=6, size=0x70]  ←  Chunk(addr=0x6021e0, size=0x80, flags=PREV_INUSE)
```

Note the actual structure of a fastbin is a linked list, where it points to the next chunk in the list (granted it points to the heap header of the next chunk):

```
gef➤  x/g 0x602010
0x602010: 0x602020
gef➤  x/4g 0x602020
0x602020: 0x0 0x21
0x602030: 0x0 0x0
```

This list of freed chunks is called the "fas