Lion Cipher Lab
Exploit a use-after-free with tcache reuse (in your own lab)
- Penetration Testing / Red Team
- Advanced
- ~75 min
- Free · no account required
Why it matters
The first three rungs of this arc all lived on the STACK. This one steps onto the HEAP — the region where `malloc` hands out memory at runtime — and it is where the hardest, highest-impact real-world bugs live: the memory-safety flaws that dominate the critical CVEs in browsers, kernels and every large C/C++ codebase are overwhelmingly heap use-after-free and heap overflow. A use-after-free is deceptively simple: you `free` a pointer, the allocator reclaims that memory, but your code still holds — and later uses — the stale pointer. If an attacker can get their OWN data allocated into that…
What you'll learn
- reading a use-after-free (UAF) on sight: recognising that free(p) does NOT null p, so a pointer used after free is a dangling reference into memory the allocator may have handed to someone else
- how the glibc heap allocator's tcache works: free() pushes a chunk onto a per-size, thread-local, singly-linked LIFO free-list; the next malloc() of the SAME size pops that exact chunk straight back
- turning that predictable reuse into a control primitive: free an object, allocate a same-size buffer that lands on the freed object's chunk, and write attacker data through it that a dangling pointer then reads
- overwriting a FUNCTION POINTER stored inside the reused chunk to redirect control flow into an in-binary win() -- deterministic under -no-pie, with no ASLR bypass and no libc leak
- why glibc 2.29+ tcache double-free detection and 2.32+ safe-linking do NOT interfere with this exploit (you overwrite an application field of an ALREADY-allocated chunk, not the tcache fd of a chunk still in the free-list)
- confirming allocation reuse in a debugger with pwndbg/GEF's `heap`, `bins` and `tcachebins` commands -- while the exploit itself runs from the command line with no plugin
- the judgment: WHEN UAF arises in real code (manual memory management, callbacks, object caches; browsers and kernels are the classic hunting ground) and how to kill the class for good -- AddressSanitizer at test time, hardened allocators, MTE/pointer authentication, and memory-safe languages
Steps in this lab
- Read this first: still your own machine, still authorized-only
- The heap, free(), and what a use-after-free actually is
- The tcache: why reuse is so predictable (LIFO free-list)
- Get Linux and the toolchain
- Write the vulnerable program — an object with a function pointer
- Compile with mitigations off for teaching — and read win()'s address
- Prove the reuse in gdb: watch the chunk go into and out of the tcache
- Fire the exploit: overwrite the dangling function pointer
- The glibc hardening that does NOT save you here — and the one that hints at the bug
- Do it better: how the industry actually kills this class — and where it goes next