skills/yaklang/hack-skills/heap-exploitation

heap-exploitation

Installation
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

Advanced References


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)
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)

# 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 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

# 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)
Weekly Installs
20
GitHub Stars
69
First Seen
1 day ago
Installed on
opencode20
gemini-cli20
deepagents20
antigravity20
github-copilot20
codex20