Hacktricks-skills glibc-heap-exploitation
A skill for understanding and exploiting glibc heap memory management, including tcache, fast bins, unsorted bins, small bins, large bins, and top chunk manipulation. Use this skill whenever working on binary exploitation challenges involving heap vulnerabilities, analyzing malloc/free behavior, debugging heap corruption issues, or when the user mentions heap exploitation, glibc malloc, memory bins, tcache attacks, fastbin attacks, or any heap-related CTF challenges.
git clone https://github.com/abelrguezr/hacktricks-skills
skills/binary-exploitation/libc-heap/bins-and-memory-allocations/SKILL.MDGlibc Heap Exploitation
This skill helps you understand and exploit glibc's heap memory management system. The glibc malloc implementation uses several types of bins to efficiently manage freed memory chunks.
Quick Reference
| Bin Type | Count | Max Chunks | Size Range (64-bit) | Link Type |
|---|---|---|---|---|
| Tcache | 64 per thread | 7 | 24-1032 bytes | Singly-linked |
| Fast | 10 | 0x80 | 16-80 bytes | Singly-linked (LIFO) |
| Unsorted | 1 | - | - | Doubly-linked |
| Small | 62 | - | 16-512 bytes | Doubly-linked |
| Large | 63 | - | 512+ bytes | Doubly-linked |
Core Concepts
Memory Chunk Structure
Each heap chunk has a header containing:
- Size field: Chunk size with flags (PREV_INUSE, IS_MMAPPED, NON_MAIN_ARENA)
- Next/Prev pointers: For doubly-linked lists (except fast/tcache bins)
Bin Selection Flow
When a chunk is freed, it goes through this decision tree:
-
Tcache check: Is chunk ≤ 512 bytes (64-bit) AND tcache bin not full (7 chunks)?
- Yes → Add to tcache bin
- No → Continue
-
Fast bin check: Is chunk ≤ 80 bytes (64-bit)?
- Yes → Add to fast bin (LIFO)
- No → Continue
-
Unsorted bin: Add to unsorted bin first
- May merge with adjacent free chunks
- Later sorted into small/large bins on demand
-
Small/Large bins: Based on size thresholds
- Small: 16-512 bytes (64-bit)
- Large: 512+ bytes
Exploitation Techniques
Tcache Poisoning
When to use: When you can control the
next pointer in a freed chunk.
Requirements:
- Target application uses tcache (glibc 2.26+)
- Can free same-size chunks multiple times
- Can control chunk content before free
Attack pattern:
1. Allocate chunk A (size X) 2. Allocate chunk B (size X) 3. Write fake next pointer to chunk A's content 4. Free chunk A (goes to tcache) 5. Free chunk B (goes to tcache) 6. Allocate chunk C → gets chunk B 7. Allocate chunk D → gets chunk A with fake next 8. Chunk D points to your controlled address
Key insight: Tcache uses singly-linked lists, so you only need to control the
next pointer, not prev.
Fastbin Attack
When to use: When tcache is disabled or full, and you can control freed chunk content.
Requirements:
- Chunk size fits fastbin (16-80 bytes on 64-bit)
- Can control chunk content
- Can trigger double-free or use-after-free
Attack pattern:
1. Allocate chunk A (fastbin size) 2. Allocate chunk B (fastbin size) 3. Write fake next pointer to chunk A 4. Free chunk A (goes to fastbin) 5. Free chunk B (goes to fastbin) 6. Allocate → gets chunk B 7. Allocate → gets chunk A with fake next
Key insight: Fastbins use LIFO, so the last freed chunk is allocated first.
Unsorted Bin Attack
When to use: When you need to manipulate chunk sizes or merge chunks.
Requirements:
- Chunk too large for fastbin/tcache
- Can control chunk size field
- Can trigger consolidation
Attack pattern:
1. Allocate chunk A (large size) 2. Allocate chunk B (large size) 3. Free chunk A (goes to unsorted bin) 4. Modify chunk A's size field 5. Allocate chunk C (triggers unsorted bin sorting) 6. Chunk A gets sorted with modified size
Key insight: Unsorted bin chunks are sorted into small/large bins on demand, allowing size manipulation.
Small Bin Attack
When to use: When you need precise control over chunk placement.
Requirements:
- Chunk size in small bin range (16-512 bytes)
- Can control chunk content
- Can trigger bin sorting
Attack pattern:
1. Allocate multiple chunks of same size 2. Free them all (go to unsorted, then small bin) 3. Modify chunk pointers in small bin 4. Allocate to get controlled chunk
Key insight: Small bins use doubly-linked lists, requiring control of both
next and prev pointers.
Large Bin Attack
When to use: For large allocations where size manipulation matters.
Requirements:
- Chunk size > 512 bytes
- Can control chunk size field
- Understand large bin sorting (by size)
Attack pattern:
1. Allocate large chunk A 2. Free chunk A (goes to unsorted, then large bin) 3. Modify chunk A's size field 4. Allocate large chunk B (triggers large bin search) 5. Chunk A found with modified size
Key insight: Large bins sort by size, so modifying size affects search order.
Analysis Tools
GEF Commands
# View all heap bins heap bins # View heap chunks heap chunks # View specific arena heap arena # View malloc state heap malloc-stats # Visualize heap heap visualize
Pwntools Heap Analysis
from pwn import * # Connect to process p = process('./vuln') # Read heap memory heap_addr = p.libc.symbols['__malloc_hook'] - 0x231000 heap_data = p.read(heap_addr, 0x1000) # Parse chunk headers for i in range(0, len(heap_data), 16): size = u64(heap_data[i:i+8]) & 0xfffffffffffff print(f"Chunk at {hex(heap_addr + i)}: size={hex(size)}")
Common Vulnerabilities
Use-After-Free (UAF)
Pattern: Free a chunk, then use the pointer without reallocating.
Exploitation:
- Trigger UAF on target chunk
- Allocate new chunk of same size
- New chunk overwrites freed chunk's memory
- Use UAF pointer to control new chunk
Double Free
Pattern: Free the same chunk twice.
Exploitation:
- Free chunk A (goes to bin)
- Free chunk A again (corrupts bin)
- Bin now has duplicate entries
- Allocate to get controlled chunk
Heap Overflow
Pattern: Write beyond chunk boundary.
Exploitation:
- Overflow into next chunk's header
- Modify next chunk's size
- Free next chunk (triggers consolidation)
- Control freed chunk's metadata
Off-by-One
Pattern: Write one byte beyond boundary.
Exploitation:
- Overflow into next chunk's PREV_INUSE bit
- Free next chunk (triggers merge)
- Merge creates larger chunk
- Control merged chunk's metadata
Debugging Tips
Identify Bin Type
# In GEF gef➤ heap bins # Look for which bin contains your chunk # Check tcache Tcachebins[idx=X, size=0xXX, count=Y] # Check fastbin Fastbins[idx=X, size=0xXX] # Check unsorted Unsorted Bin for arena at 0xXXXX # Check small/large Small Bins for arena at 0xXXXX Large Bins for arena at 0xXXXX
Calculate Bin Index
Use the
calculate_bin_index.py script (see scripts/) to determine which bin a chunk will go to based on its size.
Track Allocation Order
# Track malloc/free order allocations = [] frees = [] # In your exploit allocations.append(malloc(size)) frees.append(free(ptr)) # Analyze which bin each freed chunk goes to
Best Practices
- Always check glibc version: Tcache was added in 2.26, behavior differs between versions
- Understand ASLR: Heap addresses may be randomized
- Check canaries: Stack canaries don't protect heap, but heap canaries exist
- Use debug builds: Compile with
and run with-g
for better analysisgdb - Test on clean environment: Use
carefully, it can affect behaviorLD_PRELOAD
References
- Azeria Labs - Heap Exploitation Part 1
- Azeria Labs - Heap Exploitation Part 2
- CTF Wiki - Glibc Heap
- Dhaval Kapil - Heap Exploitation
Scripts
See the
scripts/ directory for helper tools:
- Calculate which bin a chunk size belongs tocalculate_bin_index.py
- Parse and analyze heap memory dumpsanalyze_heap_dump.py
- Generate test programs for specific bin typesgenerate_test_program.py