KASLR bypass

KASLR bypass

TL;DR: Kernel ASLR randomises ntoskrnl and HAL load addresses per boot — bypass via low-integrity NT-side syscalls that still leak kernel pointers, uninitialised pool disclosures, or side channels that survive HVCI.

What it is

KASLR randomises the load address of every kernel module by a per-boot offset. Without a leak, an attacker holding a kernel write/call primitive does not know where nt!PsInitialSystemProcess or nt!HalDispatchTable live, so token-swap and ROP chains cannot be constructed. KASLR bypass is therefore the gating step for nearly every modern Windows LPE.

Preconditions / where it applies

  • Windows 8+ with KASLR enabled by default
  • Process at any integrity level — many leaks were closed for low/medium IL but remain in admin/high IL contexts (and a kernel exploit running from admin is still useful — services LPE, sandbox escape)
  • Bypasses split by whether HVCI is on; HVCI changes only what you can do with the leak, not the leak itself

Technique

Common leak primitives:

  • NT system information classes. Historically NtQuerySystemInformation(SystemModuleInformation) returned ImageBase for every kernel module to all callers. Win 10 1607+ requires Medium IL; Win 11 22H2 returns zero for non-admin. From admin, it still works — useful for service LPE.
  • SystemBigPoolInformation, SystemHandleInformation. Leak pool/object addresses; admin-only on modern builds.
  • Uninitialised kernel memory disclosures. Drivers that copy a partially initialised struct back to user mode leak heap/stack KVA — see uninitialised-memory-disclosures. Survives HVCI because HVCI does not zero memory.
  • GDI / Win32k objects. gSharedInfo, HMValidateHandle, tagWND had years of leak primitives via shared sections.
  • Side channels. Meltdown closed by KPTI; Spectre v1/v2/L1TF variants leaked the KVA_SHADOW directory base. EntryBleed (2022) revealed kernel function offsets via prefetch on KPTI hosts.
  • Bring-your-own-driver read. A signed-vulnerable driver providing physical-memory read trivially defeats KASLR.

Workflow:

1
2
3
4
5
// Admin-only legacy approach
NTSTATUS s = NtQuerySystemInformation(
    SystemModuleInformation, buf, len, &ret);
// Walk buf as RTL_PROCESS_MODULE_INFORMATION array;
// the first entry is ntoskrnl, .ImageBase is the leak.

After leak: combine with arbitrary write primitive to corrupt nt!HalDispatchTable[1] (legacy) or nt!PsInitialSystemProcess.Token (token steal) — see token-stealing-payloads.

Detection and defence

  • Microsoft has progressively gated info classes behind SeDebug or admin; track changes via nt!ExGetPreviousMode audits
  • HVCI (hvci-vbs) does not stop the leak but blocks the typical follow-up of marking sprayed pool RX
  • Microsoft Vulnerable Driver Blocklist closes BYOVD leak primitives
  • Enable Kernel CET (cfg-cet-kernel) and SMEP/SMAP (smep-smap-overview) so post-leak chains face additional CFI

References

Related: aslr-bypass, uninitialised-memory-disclosures, kpti-meltdown-implications, token-stealing-payloads