VBS / HVCI bypass — walkthrough

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 _EPROCESS address.
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):

  1. Load the driver (signed → HVCI allows; vulnerable → you can exploit it).
  2. Use it to read/write kernel memory.
  3. 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

  1. Find a kernel bug producing arbitrary R/W.
  2. Leak SYSTEM _EPROCESS (via leak primitive, e.g., NtQuerySystemInformation’s leakage).
  3. Compute SYSTEM token field address.
  4. Read SYSTEM token.
  5. Write to current process’s token field.
  6. Exit cleanly; from userland, your process is SYSTEM.

No code injection; HVCI doesn’t trigger.

For Pwn2Own / advanced research:

  1. Find a Hyper-V bug.
  2. Escape VTL0 → VTL1.
  3. From VTL1, disable HVCI.
  4. 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