Kernel CFG / kCET
TL;DR: Kernel CFG (kCFG) validates indirect call targets against a per-process bitmap; kernel CET shadow stacks validate returns. Together they shrink the gadget budget and push exploitation toward data-only attacks.
What it is
- kCFG — kernel-mode Control Flow Guard. Indirect calls (
call rax,call [rcx+0x10]) are prefixed with__guard_check_icall_fptr-style stubs that consult a sparse bitmap of valid call targets. Calls to mid-function bytes or to non-function pointers crash the kernel via a bug check. - kCET — Control-flow Enforcement Technology in kernel mode. The CPU maintains a shadow stack for the kernel; every
retchecks the shadow value against the regular stack. Tampering =#CPexception → bug check.
Both rely on hardware (CET) or PE metadata (CFG GFIDS table); both are enabled only when hvci-vbs is on (HVCI vouches for the integrity of the bitmap and shadow-stack page tables).
Preconditions / where it applies
- Windows 10 1809+ (kCFG with HVCI) and Windows 11/Server 2022 (kCET on Tiger Lake+, Zen 3+ CPUs).
- Attacker has a kernel write or call-target hijack primitive but must keep the chain within validated targets.
- Only modules compiled with
/guard:cfparticipate; older third-party drivers may be opt-out and become weak links — see hvci-vbs for the driver-blocklist angle.
Technique
Bypass strategies (high-level — all hard, all situational):
- Stay in valid targets. Walk the GFIDS list and chain only addresses that the bitmap accepts. Many useful sinks (
HalpSetSystemInformation,nt!NtAllocateVirtualMemorystyle stubs) are valid CFG targets and still let you reach a primitive. - Data-only. Don’t hijack control flow. With AR/AW (arbitrary-read-write-primitives) you can copy tokens, overwrite ACLs, or patch
_KTHREAD.PreviousModeand callNt*syscalls — noretor indirect call needed. - Find non-CFG modules. Third-party signed drivers loaded into the kernel without
/guard:cfexecute indirect calls without bitmap checks; their function pointers (callbacks, IRP dispatch table) are call gadgets if their image is mapped. - CET caveats. CET shadow-stack pages live in PTEs marked with a special bit checked by the CPU; without an HVCI bypass you cannot make a normal kernel page act as shadow. Therefore most CET bypasses depend first on an HVCI bypass via a vulnerable driver (see hvci-vbs and loldrivers.io).
- Disable from a primitive. If you achieve an early AR/AW before chains are needed, clearing
KeFeatureBits/ patchingcfg_check_icall_fptrto aretis sometimes possible on builds without HVCI — but not on modern enforced configurations.
Detection and defence
- Enable HVCI + MBEC and Microsoft’s Vulnerable Driver Blocklist; that closes the most reliable bypass route.
- Audit third-party drivers for
/guard:cfand/CETCOMPAT; recompile or remove. - Telemetry: bug-check
KERNEL_SECURITY_CHECK_FAILURE(0x139) sub-codes 5 (CFG) and 38/39 (CET) are direct evidence of a thwarted attempt.
References
- Microsoft: kernel CFG — concept doc
- Connor McGarr — CET internals — kCET deep-dive
- Intel CET spec summary — hardware reference
See also: control-flow-guard, xfg, hvci-vbs.