Windows Hardening with VBS and Credential Guard: How It Works and How to Test It

Tools & Defense
Time it takes to read this article 6 minutes.

Disclaimer: This article is for education and authorized testing only. Run these techniques exclusively against systems you own or are explicitly permitted to assess in writing. Dumping credentials or tampering with security controls on systems without authorization is illegal in most jurisdictions.

Introduction

For years, the first move after landing on a Windows host was predictable: drop Mimikatz, run sekurlsa::logonpasswords, and walk away with cleartext passwords and NTLM hashes straight out of LSASS memory. Microsoft's answer to this is Virtualization-Based Security (VBS) and the controls built on top of it — most notably Credential Guard, HVCI (Hypervisor-Protected Code Integrity), and LSA protection (RunAsPPL).

In this article you'll learn how VBS isolates secrets using the hypervisor, why Credential Guard breaks classic credential theft, how HVCI and Device Guard raise the bar for kernel-level attacks, and — crucially — how to verify whether these controls are actually enforced on a target. Misconfiguration is common: many environments enable Credential Guard in "audit" mode or leave it off entirely on legacy hardware.

How It Works / Background

VBS uses the Windows hypervisor (Hyper-V) to create an isolated memory region called the Virtual Secure Mode (VSM), split into Virtual Trust Levels. The normal OS — including the kernel — runs in VTL0. A minimal, hardened secure kernel runs in VTL1. Even a fully compromised VTL0 kernel cannot read VTL1 memory, because access is enforced by the CPU's Second Level Address Translation (SLAT) under hypervisor control.

The relevant components:

  • Credential Guard moves the LSA's secret-handling logic into an isolated LSAIso (lsaiso.exe) trustlet running in VTL1. NTLM hashes and Kerberos TGTs never live in VTL0 LSASS memory in a usable form, so sekurlsa::logonpasswords returns blanks.
  • HVCI / Device Guard uses VTL1 to enforce code integrity: only signed, validated pages can be marked executable in the kernel. This blocks unsigned drivers and many kernel-mode shellcode techniques.
  • LSA protection (RunAsPPL) is a separate, lighter control. It runs LSASS as a Protected Process Light, blocking userland handle opens — but it does not require VBS and can be bypassed by a signed vulnerable driver (BYOVD).

A key consequence for attackers: Credential Guard protects derived secrets (NTLM, TGT). It does not protect cleartext passwords typed at logon in all cases, nor does it stop you from requesting new Kerberos tickets as the logged-on user via the normal API surface.

Prerequisites / Lab Setup

You need:

  • A Windows 10/11 Enterprise or Windows Server 2019+ host with UEFI, Secure Boot, TPM 2.0, and virtualization extensions (VT-x/AMD-V) enabled.
  • Local admin (and, for some checks, SYSTEM).
  • Tooling: Get-ComputerInfo / msinfo32 (built in), Mimikatz, and Sysinternals.

Enable VBS + Credential Guard via Group Policy (Computer Configuration > Administrative Templates > System > Device Guard > Turn On Virtualization Based Security) or by registry, then reboot:

# Enable VBS, Credential Guard, and HVCI via registry
reg add "HKLM\SYSTEM\CurrentControlSet\Control\DeviceGuard" /v EnableVirtualizationBasedSecurity /t REG_DWORD /d 1 /f
reg add "HKLM\SYSTEM\CurrentControlSet\Control\DeviceGuard" /v RequirePlatformSecurityFeatures /t REG_DWORD /d 3 /f
reg add "HKLM\SYSTEM\CurrentControlSet\Control\DeviceGuard\Scenarios\CredentialGuard" /v Enabled /t REG_DWORD /d 1 /f
reg add "HKLM\SYSTEM\CurrentControlSet\Control\DeviceGuard\Scenarios\HypervisorEnforcedCodeIntegrity" /v Enabled /t REG_DWORD /d 1 /f
PowerShell

Attack Walkthrough / PoC

Step 1 — Determine whether the controls are actually running

Always enumerate before acting. Don't assume Credential Guard is on just because policy exists.

# Authoritative runtime state
$di = Get-CimInstance -ClassName Win32_DeviceGuard -Namespace root\Microsoft\Windows\DeviceGuard
$di.SecurityServicesConfigured   # what is configured
$di.SecurityServicesRunning      # what is actually running
$di.VirtualizationBasedSecurityStatus  # 0=off, 1=enabled-not-running, 2=running
PowerShell

In SecurityServicesRunning, a value of 1 = Credential Guard, 2 = HVCI, 3 = System Guard Secure Launch. If 2 (running) doesn't appear for Credential Guard, it's not enforced regardless of what policy claims.

Check LSA protection separately:

reg query "HKLM\SYSTEM\CurrentControlSet\Control\Lsa" /v RunAsPPL
# RunAsPPL = 1 (PPL), 2 (PPL with UEFI lock)
PowerShell

Step 2 — Confirm Credential Guard blocks classic dumping

With Credential Guard running, the standard attack fails as designed:

mimikatz # privilege::debug
mimikatz # sekurlsa::logonpasswords
# Username : Administrator
# NTLM     : (LSA Isolated Data: NtlmHash)   <-- isolated, no usable hash
Plaintext

The LSA Isolated Data marker confirms VTL1 isolation. The same applies to WDigest cleartext — Credential Guard also forces WDigest credential caching off.

Step 3 — Adapt: techniques that still work

Credential Guard is not a silver bullet. Viable paths remain:

  • Tickets, not hashes. You can still request and export Kerberos tickets for the current user. Credential Guard isolates the long-term key, but service tickets are usable for Pass-the-Ticket. Use Rubeus:
# Triage and export usable tickets from the current session
Rubeus.exe triage
Rubeus.exe dump /nowrap
# Request a TGT using a known password/hash (overpass-the-hash style still possible
# when you already possess the secret)
Rubeus.exe asktgt /user:svc_sql /rc4:<ntlmhash> /nowrap
PowerShell
  • Keylogging / credential capture at the UI layer. Credential Guard does not protect what a user types into a fake prompt or a phishing-style credential dialog. Roasting also remains fully viable — see Kerberoasting.
  • Bypassing LSA protection only (not Credential Guard). If only RunAsPPL is set and Credential Guard is off, a signed vulnerable driver can strip the PPL flag. PPLKiller / RTCore64.sys (CVE-2019-16098) class drivers are the classic example. This does not defeat VTL1 isolation — it only helps where VBS is absent.
# Verify whether the easy path (RunAsPPL only, no Credential Guard) exists
if (((Get-CimInstance -Namespace root\Microsoft\Windows\DeviceGuard -ClassName Win32_DeviceGuard).SecurityServicesRunning) -notcontains 1) {
    Write-Host "Credential Guard NOT running - LSASS memory may be reachable"
}
PowerShell

The decision logic an operator follows:

Windows Hardening with VBS and Credential Guard: How It Works and How to Test It diagram 1

Diagram: if Credential Guard runs, attackers abandon memory dumping and pivot to ticket abuse, UI capture, or roasting instead.

Detection & Defense (Blue Team)

Defenders should treat these as layered controls, not a single switch. Equal-weight guidance:

1. Enforce VBS + Credential Guard with a UEFI lock. Set LsaCfgFlags/Device Guard policy to enabled with UEFI lock so an attacker with admin can't simply flip a registry key and reboot. Verify enforcement fleet-wide rather than trusting policy:

Get-CimInstance -Namespace root\Microsoft\Windows\DeviceGuard -ClassName Win32_DeviceGuard |
  Select VirtualizationBasedSecurityStatus, SecurityServicesRunning
PowerShell

2. Enable HVCI and the Microsoft Vulnerable Driver Blocklist. Because BYOVD is the standard way to defeat PPL and tamper with the kernel, turning on the blocklist removes the easiest signed drivers. On Windows 11 it is on by default; verify and enforce:

# Verify the vulnerable driver blocklist is enabled
reg query "HKLM\SYSTEM\CurrentControlSet\Control\CI\Config" /v VulnerableDriverBlocklistEnable
PowerShell

3. Keep RunAsPPL as defense-in-depth even with Credential Guard, and prefer the UEFI-locked variant (RunAsPPL = 2).

4. Detection. Map to MITRE ATT&CK T1003.001 (LSASS Memory) and T1558 (Kerberos ticket abuse):

  • Microsoft Defender for Endpoint and Sysmon Event ID 10 (process access) flag handle opens to lsass.exe with PROCESS_VM_READ/PROCESS_QUERY_INFORMATION.
  • Watch Event ID 6 (driver load) for unsigned or known-vulnerable drivers (RTCore64.sys, dbutil_2_3.sys, etc.).
  • Monitor Kernel-Boot/Device Guard operational logs for VBS state changes — a sudden VBS disable before reboot is a strong tamper signal.
  • Audit Kerberos Event ID 4769 for anomalous service ticket requests indicating roasting or PtT.

5. Reduce the secrets that exist at all. Credential Guard does not protect cached domain logons on non-domain paths perfectly, so deploy LAPS, disable WDigest explicitly (UseLogonCredential = 0), and use Protected Users + Authentication Policy Silos for tier-0 accounts. See Pass-the-Hash and lateral movement for why removing reusable secrets matters more than any single memory control.

Conclusion

VBS-backed Credential Guard genuinely kills the decades-old "dump LSASS, get the hash" workflow — when it is actually running, UEFI-locked, and paired with HVCI and the vulnerable driver blocklist. The recurring failure mode is configuration: audit-mode deployments, legacy hardware without TPM/Secure Boot, and registry-only enablement that admins can revert. For red teamers, the lesson is to enumerate first and pivot to ticket abuse and roasting; for blue teamers, the lesson is to verify runtime enforcement at scale and reduce the long-term secrets that exist on every host. For broader context, see Active Directory attack paths.

References

Comments

Copied title and URL