Linux heap exploitation

Linux heap exploitation

TL;DR: Modern glibc heap exploitation revolves around corrupting tcache, fastbin, or unsorted-bin metadata to forge a write-what-where or leak libc, usually starting from a UAF or single-byte overflow.

What it is

glibc’s ptmalloc2 manages freed chunks in per-size lists (tcache and fastbins for small allocations, unsorted/small/large bins for larger ones). Each list is a singly or doubly linked list whose fd/bk pointers live inside the freed chunk itself. Corrupting those pointers — via UAF, off-by-null, single-byte overflow into chunk size, or double-free — gives an attacker control over the next malloc return address.

Preconditions / where it applies

  • Heap-corruption primitive: UAF, double-free, linear overflow, off-by-one, off-by-null
  • glibc target — version dictates which mitigations apply (tcache key/safe-linking land in 2.32+)
  • Ability to allocate and free chunks of controlled sizes (most CTF menus expose this; real bugs often need a heap groom)

Technique

Pick the cheapest primitive that fits the bug class:

  • tcache poisoning (glibc ≥ 2.26): after a free, overwrite the chunk’s first qword with a target address; the next two allocations of that size hand it back.
  • fastbin dup: double-free a fastbin chunk, then redirect fd to a near-arbitrary location whose fake-size field matches the bin.
  • unsorted-bin attack / leak: a chunk freed into the unsorted bin has libc main_arena pointers in fd/bk — reading it back leaks libc base, the standard step before a one-gadget ret2libc.
  • House of Force / Spirit / Botcake: classical large-bin and top-chunk corruption recipes; how2heap catalogues each.

Safe-linking (glibc 2.32+) XORs fd with (pos >> 12), so tcache/fastbin poisoning now needs a heap-base leak first:

1
2
// safe-linking obfuscation
#define PROTECT_PTR(pos, ptr) ((__typeof(ptr))((((size_t)pos) >> 12) ^ (size_t)ptr))

Typical chain: heap leak → libc leak via unsorted bin → tcache poison overwriting __free_hook or __malloc_hook (≤ 2.33) or an exit handler / FILE vtable (2.34+).

Detection and defence

  • Compile with MALLOC_CHECK_=3 or GLIBC_TUNABLES=glibc.malloc.check=3 to assert on bad chunk metadata during fuzzing
  • AddressSanitizer / HWASan catches UAF and overflows at allocation granularity
  • Keep glibc current — safe-linking, tcache double-free keys (tcache_key), and removal of __malloc_hook (2.34) close most legacy paths
  • Use mallopt(M_MXFAST, 0) to disable fastbins where compatibility allows

References

Related: ret2libc, srop, ret2csu, format-string-bugs