Binary Exploitation

Heap Exploitation

Heap exploitation techniques covering heap memory management, use-after-free, double-free, heap overflow, and tcache poisoning attacks.

Contents

Heap Exploitation

Sources: HackTricks - Libc Heap | How2Heap


Heap Basics

The heap is dynamic memory allocated at runtime via malloc(), calloc(), realloc() and freed with free().

char *ptr = malloc(0x20);  // Allocate 0x20 bytes on heap
strcpy(ptr, "hello");
free(ptr);                  // Return chunk to allocator

Memory Layout

[ Text | Data | BSS | Heap →  ...  ← Stack ]
                      ↑ grows up    ↑ grows down

Chunk Structure (malloc_chunk)

struct malloc_chunk {
    size_t prev_size;    // Size of previous chunk (if free)
    size_t size;         // Size of this chunk + flags (3 LSBs)
    // --- user data starts here when allocated ---
    chunk* fd;           // Forward pointer (only when free)  
    chunk* bk;           // Backward pointer (only when free)
    chunk* fd_nextsize;  // Large bins only
    chunk* bk_nextsize;  // Large bins only
};

Size Field Flags (3 LSBs)

BitNameMeaning
0x1PREV_INUSEPrevious chunk is allocated
0x2IS_MMAPPEDChunk obtained via mmap()
0x4NON_MAIN_ARENAChunk from secondary arena

Allocated vs Free Chunk

Allocated:

+------------------+
| prev_size        |  (or prev chunk's data)
+------------------+
| size      | A|M|P|
+------------------+
| user data        |
| ...              |
+------------------+

Free:

+------------------+
| prev_size        |
+------------------+
| size      | A|M|P|
+------------------+
| fd               |  → next free chunk
+------------------+
| bk               |  → prev free chunk
+------------------+
| (unused)         |
+------------------+

Bins (Free Chunk Storage)

When chunks are freed, they’re placed in bins for reuse:

Tcache Bins (glibc >= 2.26)

  • Per-thread cache, fastest allocation
  • 64 singly-linked lists (sizes 0x20 to 0x410 on x64)
  • Max 7 chunks per bin
  • LIFO (Last In, First Out)
  • Minimal security checks (exploit-friendly)

Fast Bins

  • Sizes: 0x20 to 0x80 (x64)
  • Singly-linked (LIFO), never coalesced
  • Chunks NOT marked as free (PREV_INUSE stays set)
  • Filled after tcache is full

Unsorted Bin

  • Single doubly-linked list
  • “Staging area” — freed chunks land here first (if not tcache/fastbin)
  • On next malloc(), chunks sorted into small/large bins or reused

Small Bins

  • 62 doubly-linked lists
  • Sizes: 0x20 to 0x3F0 (x64)
  • FIFO (First In, First Out)
  • Exact size match

Large Bins

  • 63 doubly-linked lists
  • Sizes > 0x3F0 (x64)
  • Sorted by size within each bin
  • Best-fit allocation

Common Heap Attacks

Use-After-Free (UAF)

Accessing memory after free(). If chunk is reallocated, attacker controls data.

char *a = malloc(0x20);
free(a);           // 'a' is freed but pointer still exists
char *b = malloc(0x20);  // b gets same chunk as 'a'
// Writing to 'a' now overwrites 'b's data

Double Free

Freeing same chunk twice → appears in free list twice → two allocations return same chunk.

free(a);
free(b);  // or something else to avoid glibc double-free check
free(a);  // 'a' in free list twice
// Now malloc() returns 'a' twice → overlapping chunks

Tcache Double Free (glibc < 2.29): No key check, trivial. Tcache Double Free (glibc >= 2.29): Tcache adds a key field; must overwrite it.

Heap Overflow

Overflowing from one chunk into adjacent chunk’s metadata.

Fastbin Dup / Tcache Poisoning

Corrupt fd pointer of free chunk → next allocation at arbitrary address.

# Tcache poisoning (simplified)
# 1. Free chunk A → tcache: A
# 2. Overwrite A->fd to point to target 
# 3. malloc() → returns A
# 4. malloc() → returns TARGET (arbitrary write!)

Corrupt fd/bk of a chunk to get arbitrary write during unlink(). Modern glibc has safety checks: P->fd->bk == P && P->bk->fd == P

House Techniques

TechniqueTargetCondition
House of ForceTop chunkOverflow into top chunk size
House of SpiritFastbin/TcacheForge fake chunk, free it
House of LoreSmall binCorrupt bk pointer
House of EinherjarBackward consolidationOff-by-one null byte
House of Orange_IO_FILE / unsorted binNo free() needed
House of RomanPartial overwriteNo leak needed
House of RabbitFastbin consolidationCorrupt fastbin fd

Useful GDB Commands (with pwndbg/GEF)

# Inspect heap state
heap                  # Overview of all chunks
bins                  # Show all bins (tcache, fast, unsorted, small, large)
vis_heap_chunks       # Visual representation
tcachebins            # Tcache specifically
fastbins             
smallbins

# Inspect specific chunk
heap chunk <addr>
malloc_chunk <addr>

# Track allocations
# set breakpoints on malloc/free
b *malloc
b *free

Key glibc Version Changes

VersionChange
2.26Tcache introduced
2.29Tcache key (double-free check)
2.32Tcache fd pointer PROTECT_PTR (XOR with heap addr >> 12)
2.34__malloc_hook / __free_hook removed
2.35+Further hardening of pointer mangling

References