Windows heap exploitation
TL;DR: Modern Windows user-mode heaps split into LFH (Low Fragmentation Heap) and Segment Heap; both bucket allocations by size, randomise free lists, and use header encoding — exploitation is mostly about groom and choosing the right victim object, not about classic unlink primitives.
What it is
Windows ships two coexisting heap implementations. NT Heap with LFH (default for non-image processes, classic shape: _HEAP, _HEAP_ENTRY, encoded headers). Segment Heap introduced in Windows 10 1703 for store apps, expanded in 1809/Server 2019 to several system processes and DCOM hosts. Both keep small allocations in size-class buckets; LFH activates for a bucket after a few allocations of the same size.
Preconditions / where it applies
- User-mode heap bug (OOB write, UAF, double free, integer underflow on size).
- Ability to control allocation/free pattern (web request loop, COM call loop, script-engine arrays).
- Knowledge of which heap is in use for the target process (
!heap -sin WinDbg).
Technique
Groom basics.
- Pick a bucket: any size class that sees frequent attacker-driven allocations.
- Fill holes: allocate many objects of the target size to defragment, then free every other one to open predictable slots, then trigger the bug so the vulnerable object lands in a chosen slot adjacent to a sprayable victim.
LFH specifics.
- Activation: ~17 allocs of the same size triggers LFH for that bucket.
- Randomised slot selection breaks “predict the next free chunk” — spray many candidates, not one.
- Header encoding XORs with
_HEAP.Encoding, mitigating direct header overwrites.
Segment Heap specifics.
- Three tiers: Variable Size, LFH-style buckets, Large Blocks; metadata lives in separate pages (
_SEGMENT_HEAP,_HEAP_PAGE_RANGE_DESCRIPTOR). - Backend uses commit/decommit on page-aligned segments; large overflows often hit guard pages first.
- Pointer encoding on freelist nodes is per-process and randomised.
Useful victim objects (browser/JS):
- Typed-array buffers — change a length field for OOB read/write inside the renderer.
- String objects — length + data pointer pair.
- DOM/ArrayBuffer pairs — classic primitive in scripting engine bugs.
Classic patterns still relevant.
- UAF with vtable reclaim → call attacker-chosen virtual on freed object.
- Type confusion enabling a length/pointer field overlay onto a buffer.
- Off-by-one over a chunk header → adjacent chunk’s
_HEAP_ENTRYfields manipulate; mostly mitigated but situational.
Detection and defence
- Build with
/GS,/guard:cf,/CETCOMPAT; opt into segment heap (FrontEndHeapTyperegistry). - Enable Application Verifier / page heap in test to surface bugs early.
- EMET-style mitigations and CFG bookkeeping limit what UAF vtable hijacks can reach.
References
- Microsoft: Segment Heap internals — design notes
- Saar Amar — Windows 10 Segment Heap — deep dive
- Mark Yason — LFH internals — earlier reference
See also: heap-exploitation-linux, arbitrary-read-write-primitives, use-after-free-kernel.