Mitigations
A kernel vulnerability gives an attacker a single corruption. Turning that corruption into SYSTEM requires a chain of steps: leaking addresses, shaping memory, constructing read/write primitives, and finally modifying a privilege token or security descriptor. Mitigations work by breaking links in that chain. No single defense stops exploitation on its own. Instead, they compose into a defense-in-depth stack where each layer forces the attacker to solve an additional problem, and each additional problem demands another primitive that may not be available from the original bug.
This philosophy is visible in the corpus. CVE-2024-21338 (appid.sys) gave Lazarus Group a controlled kernel callback, but SMEP blocked the obvious step of jumping to user-mode shellcode, kCFG constrained which functions the callback could target, and KASLR meant the callback address had to be leaked first. The exploit worked because it found data-only paths around every layer. But remove any one of those constraints from the attacker's burden and the chain becomes simpler, faster, more reliable. Defense-in-depth does not prevent exploitation; it taxes it.
The stack is ordered by bypass difficulty. Hardware mitigations at the bottom are relatively straightforward to work around if the attacker already holds a write primitive. VBS-backed protections at the top require defeating the hypervisor, something no public exploit has accomplished through direct assault.
FIG_006 -- Defense-in-Depth Stack
Each layer blocks specific primitive classes. VBS-backed protections at the top are the hardest to bypass.
How the Layers Interact
The real power of this stack is compositional. Consider an attacker who finds a pool overflow in clfs.sys. Pool hardening (Segment Heap randomization, cookies) makes the initial corruption unreliable but not impossible. If the attacker achieves a write primitive, KASLR forces them to find an information leak or corrupt the security descriptor that gates NtQuerySystemInformation access. SMEP and SMAP prevent them from redirecting execution to user-mode shellcode, so they must use data-only techniques like token swapping. kCFG and kCET prevent control flow hijacking even within kernel code. And if HVCI is enabled, there is no writable-and-executable memory anywhere in the kernel address space.
Each mitigation removed from this chain makes the exploit simpler. On a system without HVCI, the attacker regains the ability to allocate executable memory. Without kCET, ROP chains become viable again. Without KASLR restrictions, a simple API call reveals every kernel address. The defense-in-depth model works because these layers are independent: bypassing one does not compromise the others.
Mitigation Catalog
| Mitigation | What It Blocks | Bypass Difficulty |
|---|---|---|
| SMEP / SMAP | Code execution and data access across the user/kernel boundary | Medium |
| kCFG / kCET | Control flow hijacking via function pointer and return address corruption | High |
| VBS / HVCI | Runtime code generation, unsigned driver loading, and code page modification in the kernel | Very High |
| KDP | Modification of security-critical kernel globals and driver configuration data | Very High |
| Pool Hardening | Pool header corruption, deterministic heap layout, and uninitialized data leaks | Medium |
| Secure Pool | Pool overflow, use-after-free, and metadata corruption for VBS-protected allocations | Very High |
| ACG | Dynamic code generation and modification within protected user-mode processes | High |
| KASLR | Exploitation using hardcoded or predictable kernel addresses | Low-Medium |
| KASLR Bypasses | Catalog of techniques that defeat kernel address randomization | -- |
Which Mitigations Block Which Primitives
The table below maps each mitigation to the exploitation primitives it is designed to prevent. A filled cell means the mitigation directly blocks or significantly hinders that primitive class. Empty cells indicate the mitigation is irrelevant to that technique, not that the technique is safe.
| Pool Overflow | Write-What-Where | Token Swap | PTE Manip | Code Exec | Pool Spray | |
|---|---|---|---|---|---|---|
| SMEP / SMAP | ■ | |||||
| kCFG / kCET | ■ | |||||
| VBS / HVCI | ■ | ■ | ■ | ■ | ||
| KDP | ■ | ■ | ||||
| Pool Hardening | ■ | ■ | ||||
| Secure Pool | ■ | ■ | ■ | |||
| ACG | ■ | |||||
| KASLR | ■ | ■ |
The most important takeaway from this table is the empty column for token swapping outside of VBS/KDP/Secure Pool. Token manipulation requires only a read/write primitive and knowledge of the current process address. No hardware enforcement, no control flow integrity check, and no W^X policy touches the token swap itself. This is why token swapping has become the dominant terminal goal for modern kernel exploits, and why VBS-backed protections (which could theoretically move tokens into Secure Pool or KDP-protected memory) represent the most consequential future hardening.
For how these mitigations evolved over time and how each deployment shifted attacker techniques, see the Mitigation Timeline. For how exploit chains navigate through these layers to reach SYSTEM, see Exploit Chain Patterns.