yaklang/hack-skills
heap-exploitation
>- Heap exploitation playbook. Use when targeting ptmalloc2/glibc heap vulnerabilities including UAF, double free, overflow, off-by-one/null, and leveraging tcache/fastbin/unsortedbin attacks for arbitrary write or code execution.
Use judgment
Installs
3K
Stars
2.1K
Security
No audit
Freshness
Unknown
Updated
—
Compare
All-time #4322 Trending #8017 First seen Apr 9, 2026
8-week activity · all time api
Installation
Project
Global
Entire repo
Entire repo (global)
$
npx skills add yaklang/hack-skills --skill heap-exploitation
Copy
SKILL.md
SKILL: Heap Exploitation — Expert Attack Playbook
AI LOAD INSTRUCTION : Expert glibc heap exploitation techniques. Covers ptmalloc2 internals, bin structures, tcache mechanics, libc/heap leak methods, and attack selection by glibc version. Distilled from ctf-wiki heap sections, how2heap, and real-world exploitation. Base models often confuse glibc version constraints and miss safe-linking (PROTECT_PTR) introduced in 2.32.
0. RELATED ROUTING
[stack-overflow-and-rop](../stack-overflow-and-rop/SKILL.md) — when the overflow is on the stack rather than the heap
[format-string-exploitation](../format-string-exploitation/SKILL.md) — leak heap/libc addresses via format string
[arbitrary-write-to-rce](../arbitrary-write-to-rce/SKILL.md) — convert heap arbitrary write into code execution
[binary-protection-bypass](../binary-protection-bypass/SKILL.md) — bypass ASLR/RELRO to use heap write effectively
Advanced References
[HOUSEOF TECHNIQUES.md](./HOUSEOF TECHNIQUES.md) — House of Force/Spirit/Orange/Einherjar/Roman/Pig/Banana/Cat/Apple and tcache attacks
[IOFILE EXPLOITATION.md](./IOFILE EXPLOITATION.md) — IO FILE vtable hijack, FSOP, stdout/stdin abuse, exit flow exploitation
1. PTMALLOC2 STRUCTURE QUICK REFERENCE
malloc_chunk Layout (64-bit)
chunk pointer (returned by malloc - 0x10)
┌──────────────────────────┐
0x00 │ prev_size (if prev free)│
0x08 │ size | A | M | P │ ← P=PREV_INUSE, M=IS_MMAPPED, A=NON_MAIN_ARENA
├──────────────────────────┤ ← user data starts here (returned pointer)
0x10 │ fd (if free) │ ← forward pointer to next free chunk
0x18 │ bk (if free) │ ← backward pointer to prev free chunk
0x20 │ fd_nextsize (large only)│
0x28 │ bk_nextsize (large only)│
└──────────────────────────┘
Bin Types
Bin
Size Range (64-bit)
Structure
LIFO/FIFO
tcache (per-thread)
≤ 0x410 (7 entries per size)
Singly linked (next pointer)
LIFO
fastbin
≤ 0x80 (default)
Singly linked (fd)
LIFO
unsortedbin
Any freed size
Doubly linked circular
FIFO
smallbin
< 0x400
Doubly linked circular
FIFO
largebin
≥ 0x400
Doubly linked + size-sorted
Sorted
Key Global Structures
Structure
Location
Purpose
main_arena
libc .data segment
Contains bin heads, top chunk, system_mem
mp_
libc .data
malloc parameters (tcache settings, mmap threshold)
tcacheperthread struct
Heap (first allocation)
Per-thread tcache bins and counts
2. LEAK METHODS
Libc Base Leak
Method
Precondition
Technique
Unsortedbin fd/bk
Free a chunk > tcache range (or fill tcache)
fd/bk → main_arena + 0x60 (or +0x70 depending on version) → libc base
Smallbin fd/bk
Chunk moved from unsortedbin to smallbin
Same as unsortedbin leak
stdout FILE leak
Write to IO 21 stdout_
Corrupt IO writebase to leak libc data (see IOFILE)
Heap Base Leak
Method
Precondition
Technique
Tcache fd pointer
Free two tcache chunks, read first's fd
fd → heap address (XOR'd in ≥ 2.32)
Fastbin fd
Free two fastbin chunks
fd → heap address
UAF read
Use-after-free on freed chunk
Read fd/bk directly
Safe-Linking Decode (glibc ≥ 2.32)
# PROTECT_PTR: fd_stored = (chunk_addr >> 12) ^ real_fd
# To decode: real_fd = fd_stored ^ (chunk_addr >> 12)
# To encode: fd_stored = (chunk_addr >> 12) ^ target_addr
def deobfuscate(stored_fd, chunk_addr):
return stored_fd ^ (chunk_addr >> 12)
def obfuscate(target, chunk_addr):
return (chunk_addr >> 12) ^ target
3. ATTACK CATEGORIES BY GLIBC VERSION
glibc < 2.26 (No tcache)
Attack
Primitive Needed
Result
Fastbin dup
Double free
Arbitrary allocation
Unsortedbin attack
Corrupt unsortedbin bk
Write main_arena addr to target (used for __malloc_hook nearby overwrite)
Unlink attack
Heap overflow into prev_size + fd/bk
Arbitrary write (with known heap pointer)
House of Force
Top chunk size overwrite
Arbitrary allocation
House of Spirit
Write fake chunk header
Fastbin allocation at fake chunk
Off-by-one null
Null byte overflow into next chunk size
Overlapping chunks
glibc 2.26–2.28 (tcache, no key)
Attack
Notes
Tcache poisoning
Overwrite tcache fd → arbitrary allocation, no size check
Tcache dup
Double free into tcache (no double-free detection yet)
All previous attacks
Still work, but chunks go to tcache first
glibc 2.29–2.31 (tcache key introduced)
Attack
Bypass for tcache key
Tcache dup
Corrupt key field (at chunk+0x18) before second free
House of Botcake
Double free: one in unsortedbin, one in tcache → overlapping
Tcache stashing unlink
Abuse smallbin→tcache refill to get arbitrary chunk
glibc 2.32–2.33 (safe-linking / PROTECT_PTR)
Attack
Adaptation
Tcache poisoning
Encode target with (chunk_addr >> 12) ^ target
Heap leak required
Need heap addr to decode/encode safe-linked pointers
Fastbin dup
Same encoding required
glibc ≥ 2.34 (hooks removed)
Change
Impact
__malloc_hook removed
Cannot overwrite hook for one_gadget
__free_hook removed
Cannot overwrite hook
__realloc_hook removed
Cannot use realloc trick for one_gadget constraints
Post-2.34 targets : see [arbitrary-write-to-rce](../arbitrary-write-to-rce/SKILL.md) for IO FILE, exitfuncs , TLSdtorlist , dl_fini.
4. COMMON VULNERABILITY PATTERNS
Vulnerability
Description
Exploitation Path
UAF (Use-After-Free)
Access chunk after free
Read: leak fd/bk; Write: corrupt fd for tcache poisoning
Double Free
free() same chunk twice
Tcache dup (bypass key) or fastbin dup
Heap Overflow
Write past chunk boundary
Corrupt next chunk's metadata (size, fd, bk)
Off-by-one
One byte overflow
Null byte → shrink next chunk size → overlapping chunks
Off-by-null
Specifically \x00 overflow
Clear PREV_INUSE → trigger backward consolidation
Uninitialized read
Read heap memory without clearing
Leak fd/bk from recycled chunk
5. TOOLS
# pwndbg heap inspection
pwndbg> heap # display all chunks
pwndbg> bins # show all bin contents
pwndbg> tcachebins # tcache status
pwndbg> fastbins # fastbin status
pwndbg> unsortedbin # unsortedbin content
pwndbg> vis_heap_chunks # visual heap layout
pwndbg> find_fake_fast &__malloc_hook # find nearby fake fastbin chunks
# how2heap — reference implementations
git clone https://github.com/shellphish/how2heap
# heapinspect
pip install heapinspect
heapinspect <pid>
# pwntools helpers
from pwn import *
libc = ELF('./libc.so.6')
print(hex(libc.symbols['__malloc_hook']))
print(hex(libc.symbols['__free_hook']))
6. DECISION TREE
Heap vulnerability identified
├── What is the primitive?
│ ├── UAF (read + write)
│ │ ├── Can read freed chunk? → Leak libc (unsortedbin) or heap (tcache fd)
│ │ └── Can write freed chunk? → Tcache poisoning / fastbin dup
│ ├── Double free
│ │ ├── glibc < 2.29 → direct tcache dup
│ │ ├── glibc 2.29-2.31 → corrupt tcache key first, or House of Botcake
│ │ └── glibc ≥ 2.32 → need heap leak for safe-linking encode
│ ├── Heap overflow (controlled size)
│ │ ├── Overwrite next chunk size → overlapping chunks → UAF
│ │ └── Overwrite fd directly → arbitrary allocation
│ ├── Off-by-one / off-by-null
│ │ ├── Null byte into size → House of Einherjar (backward consolidation)
│ │ └── One byte into size → shrink chunk, create overlap
│ └── Arbitrary write (from overlap or poisoned allocation)
│ ├── glibc < 2.34 → __malloc_hook / __free_hook → one_gadget
│ ├── glibc ≥ 2.34 → _IO_FILE vtable, exit_funcs, TLS_dtor_list
│ └── Partial RELRO → GOT overwrite
│
├── Need libc leak?
│ ├── Free chunk into unsortedbin (size > 0x410 or fill 7 tcache)
│ ├── Read fd/bk → main_arena offset → libc base
│ └── Alternative: stdout FILE partial overwrite for leak
│
└── Need heap leak? (glibc ≥ 2.32)
├── Read tcache fd from freed chunk
└── Decode: real_addr = stored_fd ^ (chunk_addr >> 12)