VBS / HVCI bypass — walkthrough
TL;DR: Virtualization-Based Security (VBS) + Hypervisor-protected Code Integrity (HVCI) make traditional Windows kernel exploits much harder: kernel pages are W^X from the hypervisor’s point of view, unsigned drivers can’t load, and even kernel code can’t easily write to executable pages. Bypasses with HVCI on: (1) data-only attacks (modify kernel data without code), (2) overwrite tokens / DACLs / process membership directly, (3) abuse Bring-Your-Own-Vulnerable-Driver (BYOVD), (4) attack the hypervisor itself. Companion to hvci-vbs and hevd-stack-overflow-walkthrough.
What VBS/HVCI does
- VBS uses Hyper-V to isolate “Virtual Trust Levels” (VTLs). VTL0 = normal kernel/user. VTL1 = secure kernel.
- HVCI runs in VTL1 and enforces code integrity on VTL0’s kernel:
- Kernel pages are either writable OR executable, never both at once.
- Unsigned / un-attested kernel modules can’t load.
- Patches to executable kernel pages require VTL1 approval.
Effect on traditional exploit chains:
- ROP/JOP still works (existing code reused).
- But injecting new kernel-mode shellcode is rejected.
- SMEP disabled via CR4 write? CR4 is also protected via VTL1.
- Even kernel-mode code can’t modify kernel code segment.
Bypass strategy 1 — data-only attacks
Skip the “execute code” step. Instead, modify kernel data to achieve privilege gain.
Token swap as data attack
The token-stealing primitive is already a data-only attack: write the SYSTEM token pointer into your process’s EPROCESS.Token field. No code execution required.
Required primitives:
- Arbitrary kernel write (via UAF, BOF, etc.).
- Leak SYSTEM’s
_EPROCESSaddress.
1
2
3
4
// pseudo
target = current_eprocess + EPROCESS_TOKEN_OFFSET;
arb_write(target, system_token);
// now your process is SYSTEM
HVCI doesn’t block this because no executable page was modified.
DACL modification
Modify a kernel object’s DACL to grant your process access. Useful for privilege escalation in specific scenarios.
Disable security flags
Some kernel data fields (security cookies, EDR-loaded flags) are checked at runtime. Modify the data → bypass the check.
Bypass strategy 2 — ROP-only payloads
Instead of injecting shellcode, build a ROP chain entirely from existing kernel code:
- Use ROP gadgets to call
nt!PsLookupProcessByProcessId,nt!ZwOpenProcess, etc. - Set up arguments in registers/stack.
- Call existing kernel functions to do legitimate operations under your control.
This requires more gadgets and more setup than shellcode but stays within HVCI’s allowed envelope.
Bypass strategy 3 — BYOVD (Bring Your Own Vulnerable Driver)
If you can load a signed-but-vulnerable driver (one signed by a legitimate vendor, with known kernel bugs):
- Load the driver (signed → HVCI allows; vulnerable → you can exploit it).
- Use it to read/write kernel memory.
- Achieve token swap or similar data-only privilege gain.
Examples of vulnerable but signed drivers from real attacks:
RTCore64.sys(MSI Afterburner) — arbitrary MSR / phys-mem access.dbutil_2_3.sys(Dell) — physical memory access.iqvw64.sys(Intel) — physical memory.gdrv.sys(Gigabyte) — kernel memory.
Microsoft maintains a “Vulnerable Driver Blocklist” via WDAC for Windows 11. Bypass requires:
- Finding a driver not on the blocklist.
- Driver still signed.
- Defender for Endpoint not blocking it.
Bypass strategy 4 — attack the hypervisor
The hypervisor (Hyper-V) is itself code. Bugs in Hyper-V have produced VM escapes:
- CVE-2018-0959 — Hyper-V VMSwitch heap overflow.
- CVE-2020-0904 — Hyper-V denial-of-service.
- Various follow-ups.
These are sophisticated bugs requiring Pwn2Own-tier research, not OSEE-day-job.
Bypass strategy 5 — disable VBS via legitimate config
VBS/HVCI must be enabled to enforce. If the attacker can:
- Write to
HKLM\System\CurrentControlSet\Control\DeviceGuard\Scenarios\HypervisorEnforcedCodeIntegrity\Enabled = 0. - Reboot.
→ next boot HVCI is off. Requires admin to set the registry — but you’re already trying to become admin/SYSTEM, so this is circular unless you have a foothold with that registry-write capability.
More practically: if attacker controls the early-boot stage (UEFI), they disable HVCI before it engages. See pkfail-uefi-secureboot-bypass.
Practical OSEE workflow with HVCI on
- Find a kernel bug producing arbitrary R/W.
- Leak SYSTEM
_EPROCESS(via leak primitive, e.g.,NtQuerySystemInformation’s leakage). - Compute SYSTEM token field address.
- Read SYSTEM token.
- Write to current process’s token field.
- Exit cleanly; from userland, your process is SYSTEM.
No code injection; HVCI doesn’t trigger.
For Pwn2Own / advanced research:
- Find a Hyper-V bug.
- Escape VTL0 → VTL1.
- From VTL1, disable HVCI.
- Run any payload.
Detection (defender side)
- Driver Verifier with HVCI awareness.
- Kernel-mode integrity checks (PatchGuard).
- Microsoft Defender for Endpoint — flags BYOVD by hash.
- Memory protections logged via WDAG events.
- Sysmon for driver-load events.
Mitigations vendor adds over time
- HVCI on by default (Win11 22H2 on supported hardware).
- Driver blocklist expansion.
- Kernel CFG (kCFG) extends CFG to kernel-mode.
- Kernel CET (kCET) protects RET chains.
- Pool isolation prevents cross-driver grooming.
The trend: data-only attacks remain feasible; code injection effectively dead on modern, fully-hardened Windows.
Practice
- VM with HVCI off → write a code-injection exploit.
- VM with HVCI on → adapt the exploit to data-only.
- Compare reliability.
References
- Microsoft — VBS and HVCI overview
- Connor McGarr — HVCI bypass research
- Eclypsium — driver vulnerabilities database
- BloodHound’s “loldrivers” project
- Saar Amar — Hyper-V research
- See also: hvci-vbs, hevd-stack-overflow-walkthrough, arbitrary-read-write-primitives, pkfail-uefi-secureboot-bypass, hyperv-attack-surface