flawopen.com/Simulators/Heap Use-After-Free
Interactive Heap Use-After-Free (UAF) & Re-allocation Visualizer
An interactive visual memory model demonstrating how dangling pointers survive memory deallocation, how heap chunk re-use occurs, and how function pointer hijacking leads to privilege escalation.
💡 Plain English Explainer (ELI5)
Imagine checking out of hotel room #304 and returning your keycard to the front desk, but keeping a secret duplicate key in your pocket. The hotel assigns room #304 to a new guest who unpacks their personal diary onto the desk. Later that night, you use your old duplicate key to unlock room #304 and read the new guest's diary! That duplicate key is a dangling pointer: it still unlocks room #304 even though you no longer own the room.
Core Concepts & Subsystem Terms
- Heap Chunk
- A contiguous block of memory allocated by the memory manager (`kmalloc` / `malloc`) consisting of chunk management headers and user data space.
- Dangling Pointer
- A pointer that continues to reference the memory address of an object after `free()` or `kfree()` has released the memory back to the allocator.
- tcache / Free List
- Fast-path per-thread memory cache that stores recently freed chunks in a singly-linked list to quickly satisfy subsequent allocation requests of the same size.
- Type Confusion via Heap Spray
- Allocating an attacker-crafted structure into a recently freed slot so that legacy code interpreting the old structure executes attacker function pointers.
Step-by-Step Exploit & Execution Mechanics
Initial Object Allocation
A legitimate kernel subsystem allocates an object (e.g. user_session) via kmalloc() at address 0x55a0. The system stores pointer *sess.
Premature Deallocation & Pointer Retention
A cleanup routine calls kfree(sess), pushing chunk 0x55a0 to the tcache freelist, but neglects to set sess = NULL, creating a live dangling pointer.
Targeted Heap Spray / Reallocation
The attacker allocates a crafted payload structure of the exact same size (80 bytes). The allocator reuses the freed chunk at 0x55a0 for the attacker's payload.
Dangling Pointer Dereference
The kernel later calls sess->callback(). Because sess still references 0x55a0, the CPU executes the attacker's supplied function pointer, achieving root code execution.
Source Code Diff: Object Lifetime Management
// Vulnerable driver/kernel cleanup routine
void release_session(struct session_mgr *mgr) {
if (mgr->active_session) {
kfree(mgr->active_session);
// FLAW: Pointer is not zeroed! mgr->active_session remains dangling.
// Any subsequent invocation of mgr->active_session->callback()
// will dereference whatever is re-allocated into this memory slot.
}
}
// Hardened cleanup routine with atomic pointer zeroization
void release_session(struct session_mgr *mgr) {
struct user_session *sess;
// HARDENED: Atomically detach pointer before freeing memory
sess = xchg(&mgr->active_session, NULL);
if (sess) {
// Zero out memory contents before releasing to allocator to thwart re-use
memzero_explicit(sess, sizeof(*sess));
kfree(sess);
}
}
Engineering & System Hardening Checklist
- Always Nullify Pointers on Free: Implement a macro or wrapper like
#define SAFE_FREE(p) do { free(p); (p) = NULL; } while(0). - Use Reference Counting (`refcount_t` / `std::shared_ptr`): Never manually free memory that has more than one active owning reference.
- Enable Kernel SLUB Freelist Hardening: Compile kernels with
CONFIG_SLAB_FREELIST_HARDENED=yandCONFIG_SLAB_FREELIST_RANDOM=yto obfuscate freelist pointers. - Zero Memory Before Deallocation: Clear sensitive function pointers and credentials with
memzero_explicit()before releasing chunk memory.