Heap Exploitation Basics

cryfrogg

Heap is a really nice thing :/

Chunks

Memories in heap are allocated in chunks:

1
2
3
4
5
6
7
8
9
10
11
12
low
curr -> | prev_size* | 8
| size | | | PREV_INUSE | 8
| fd* | 8 -
| bw* | 8 | data
/ / |
next -> | prev_size* | -
| size | | | PREV_INUSE |
/ /
high
*: Present if the previous chunk is freed.
The data of curr uses prev_size of the next chunk!

The size field is 8 bytes, but the last 3 bits are reserved for flags.
The most important flag is bit 0: PREV_INUSE, which will be discussed later.

Now we have different types of bins/chunks.

Bin Size List Merge Number of Lists Order
tcache [0x20;0x410] doubly-linked each size LIFO
fastbin [0x20;0x80] singly-linked (✅) each size LIFO
smallbin (0x80;0x400) doubly-linked each size FIFO
largebin [0x400;0x20000) doubly-linked logarithmic size-sorted
unsorted chunks (0x80;0x20000) doubly-linked one LIFO-ish

Chunk sizes are always 0x10 aligned, and the minimum is 0x20.
We also have a special top chunk that keeps track of the heap memory!

Tcache:

  • most prioritized, max = 7 for each possible size!
  • Per-thread management structure on heap!
  • tcache key stored on bk pointer for double-free detection

FD Corruption (fastbin / tcache)

Let’s say we have a chunk A with size 0x20,
and somewhere in the memory we have the arena (or tcache struct) with a list pointing to B.

1
2
3
4
5
6
7
A ->  |   ...   | 8 
size | 0x21 | 8 (bit 1 for PREV_INUSE)
data / ... /
/ ... /

arena / tcache_struct:
-> | &B |

Steps:

  1. free A, now the chunk looks like this:
1
2
3
4
5
6
7
A ->  |   ...   | 8 
size | 0x21 | 8
fd | &B | 8
bw | (tcache_key) | 8

arena / tcache_struct:
-> | &A |
  1. Now we overflow fd of A to 0xdeadbeef:
1
2
3
4
5
6
7
A ->  |   ...           | 8 
size | 0x21 | 8
fd | 0xDEADBEEF | 8
bw | (tcache_key) | 8

arena / tcache_struct:
bin (0x20) -> | &A |
  1. Alloc a new chunk C with size 0x20
1
2
3
4
5
6
7
C ->  |   ...           | 8 
size | 0x21 | 8
fd | 0xDEADBEEF | 8
bw | (tcache_key) | 8

arena / tcache_struct:
bin (0x20) -> | 0xDEADBEEF |
  1. Now, if we try to alloc a new chunk with size 0x20, it will get the address from the bin and alloc a new chunk at address 0xDEADBEEF

Size Corruption

Let’s say we have two chunks A and B with size 0x20:

1
2
3
4
5
6
A ->  |   ...   | 
size | 0x21 |
/ ... /
B -> | ... |
size | 0x21 |
/ ... /
  1. Overflow size of A to 0x41
1
2
3
4
5
6
A ->  |   ...   | 
size | 0x41 |
/ ... /
B -> | ... |
size | 0x21 |
/ ... /
  1. Free A
1
2
3
4
5
6
A ->  |   ...   |  <- freed
size | 0x41 |
/ ... /
B -> | ... |
size | 0x21 |
/ ... |
  1. Alloc chunk C with size 0x38, now chunk B is inside C
1
2
3
4
5
6
C ->  |   ...   | -
size | 0x41 | |
/ ... / | belongs to C
B -> | ... | |
size | 0x21 | |
/ ... | -

Note

Usually we want to alloc size chunk_size - 0x8 to allow full control of the victim chunk.

Smallbin Consolidation (WIP)

Now we want to work with smallbins.
Let’s say we have four chunks A B C D with size 0x90.

1
2
3
4
5
6
7
8
9
10
11
12
13
A ->  |   ...   | 
size | 0x91 |
/ ... /
B -> | ... |
size | 0x91 |
/ ... /
C -> | ... |
size | 0x91 |
/ ... /
D -> | ... | <- prevents consolidation with top chunk
size | 0x91 |
/ ... /
top-> / ... /
  1. Fill tcache, so that we are working with smallbins
  2. Free A, (A could also be a fake chunk, as long as free() works!)
  3. Overflow to C: PREV_INUSE = 0 and prev_size -> A
  4. On glibc >= 2.29, overflow to A: size -> C
1
2
3
4
5
6
7
8
9
10
11
12
A ->  |   ...     | <- freed in unsorted bin
size | 0x121 | <- size = 0x90+0x90
/ ... /
B -> | 0x90 |
size | 0x90 |
/ ... /
C -> | 0x120 | <- prev_size = 0x90+0x90
size | 0x90 |
/ ... /
D -> | ... |
size | 0x91 |
/ ... /
  1. Now we free C, and cause consilidation
1
2
3
4
5
6
7
8
9
10
11
12
A ->  |   ...     | -
size | 0x121 | |
/ ... / |
B -> | ... | |
size | 0x90 | | freed in unsorted bin
/ ... / |
C -> | 0x120 | |
size | 0x90 | |
/ ... / -
D -> | 0x1b0 |
size | 0x91 |
/ ... /
  1. Alloc chunk E with size 0x1a8
1
2
3
4
5
6
7
8
9
10
11
12
A ->  |   ...     | -
size | 0x121 | |
/ ... / |
B -> | ... | |
size | 0x90 | | now chunk E
/ ... / |
C -> | 0x120 | |
size | 0x90 | |
/ ... / |
D -> | ... | -
size | 0x91 |
/ ... /
  • Title: Heap Exploitation Basics
  • Author: cryfrogg
  • Created at : 2025-12-15 23:44:41
  • Updated at : 2025-12-17 22:26:13
  • Link: https://cryfrogg.github.io/CS/CTF/PWN/Heap-Exploitation-Basics/
  • License: This work is licensed under CC BY-NC-SA 4.0.