<< All versions
Skill v1.0.0
currentAutomated scan100/100prohao42/aimy-skill/heap-exploitation
──Details
PublishedSeptember 28, 2026 at 08:05 PM
Content Hashsha256:aa73ba2c7b9fd6af...
Git SHA195da56295e4
──Files
Files (1 file, 9.1 KB)
SKILL.md9.1 KBactive
SKILL.md · 219 lines · 9.1 KB
version: "1.0.0" name: heap-exploitation description: >- 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.
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 — when the overflow is on the stack rather than the heap
- format-string-exploitation — leak heap/libc addresses via format string
- arbitrary-write-to-rce — convert heap arbitrary write into code execution
- binary-protection-bypass — bypass ASLR/RELRO to use heap write effectively
Advanced References
- HOUSE_OF_TECHNIQUES.md — House of Force/Spirit/Orange/Einherjar/Roman/Pig/Banana/Cat/Apple and tcache attacks
- IO_FILE_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 chunk0x18 │ bk (if free) │ ← backward pointer to prev free chunk0x20 │ 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) | |
tcache_perthread_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_2_1_stdout_ | Corrupt _IO_write_base to leak libc data (see IO_FILE) |
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)
python
# 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_addrdef 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 for _IO_FILE, exit_funcs, TLS_dtor_list, _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
bash
# pwndbg heap inspectionpwndbg> heap # display all chunkspwndbg> bins # show all bin contentspwndbg> tcachebins # tcache statuspwndbg> fastbins # fastbin statuspwndbg> unsortedbin # unsortedbin contentpwndbg> vis_heap_chunks # visual heap layoutpwndbg> find_fake_fast &__malloc_hook # find nearby fake fastbin chunks# how2heap — reference implementationsgit clone https://github.com/shellphish/how2heap# heapinspectpip install heapinspectheapinspect <pid># pwntools helpersfrom 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)