Infiltr8: Red-Book

Credential Guard bypass

Defeating or circumventing Windows Credential Guard (VBS-isolated LSA)

Theory

What Credential Guard is

Credential Guard (CG) is a Virtualization-based Security (VBS) feature that moves the most sensitive authentication secrets out of the reach of the normal operating system. On a VBS-enabled host, the Windows hypervisor splits execution into two Virtual Trust Levels:

  • VTL0 - the "normal world": the ordinary Windows kernel and every user-mode process, including the lsass.exe you can see in Task Manager.
  • VTL1 - the "secure world" (Isolated User Mode, IUM): a small, separately-signed set of processes called trustlets, isolated from VTL0 by the hypervisor using SLAT/EPT memory partitioning. Even a fully-compromised VTL0 kernel cannot read VTL1 memory.

When Credential Guard is active, LSASS is split in two:

  • lsass.exe in VTL0 - the broker you can see and open a handle to. It still orchestrates authentication, but it no longer holds the derived secrets. A dashed-outline LsaIso.exe placeholder process is visible in VTL0, but it is just a stub - the real code and data live in VTL1.
  • LsaIso.exe in VTL1 (the Isolated LSA) - the trustlet that actually stores and uses the secrets. It communicates with the VTL0 LSASS over a secure, hypervisor-mediated channel.
Credential Guard is a trustlet in VBS - LsaIso.exe has a VTL0 placeholder (dashed) while its real code runs in VTL1 alongside the secure kernel

At the crypto level, when VTL0 lsass.exe receives a user's password, it forwards it to the LsaIso.exe trustlet in VTL1. The trustlet calls EncryptPassword(), then DoCrypto() which uses cryptographic keys sealed to the TPM by the secure kernel. Only an opaque blob - useless outside VTL1 - flows back to VTL0. The NT hash, the Kerberos keys and the plaintext never touch VTL0 memory at rest.

Credential Guard principle - the password enters VTL1 where it is encrypted using TPM-sealed keys, only an opaque blob returns to VTL0 lsass.exe

What Credential Guard does and does not protect

This distinction is the hinge for every technique on this page.

Protected - derived secrets at rest in the isolated store:

  • NTLM password hashes (NT/NtOwfPassword)
  • Kerberos long-term keys and TGT session keys
  • Cached domain logon verifiers (domain-cached credentials)

With CG on, these never materialise in VTL0 lsass.exe memory. A conventional LSASS dump (comsvcs.dll, ProcDump, MiniDumpWriteDump, mimikatz sekurlsa::logonpasswords) therefore comes back with the secret fields blanked - the attacker only recovers encrypted proxy blobs that are useless outside VTL1.

Not protected - because CG was never designed to hide them:

  • Plaintext credentials in transit at authentication time. A Security Support Provider (SSP) loaded into the VTL0 LSASS still sees the cleartext as it flows through the logon path. CG protects the stored, derived secret, not the credential while it is being presented.
  • Secrets for logons that happen while CG is off. Isolation is enforced at the moment the secret is created. Anything created before CG was enabled, or after it is torn down, lives in VTL0.
  • Local SAM secrets, DPAPI-protected material, browser/credential-manager stores, and network authentication exchanges (which can still be relayed, roasted, or captured).

Because of this, "bypassing Credential Guard" splits into two distinct goals: disabling it so the secrets fall back into VTL0, or circumventing it by capturing credentials on a path it does not cover.

The runtime-teardown primitive

Classically, turning Credential Guard off meant changing configuration (LsaCfgFlags, UEFI variables, Device Guard policy) and rebooting - persistent, but slow and loud.

Research published in the CredGuardRuntimeShutdown PoC (Win11 24H2, build 26200) demonstrates a reboot-less, driver-less teardown. Inside the LsaIso.exe trustlet runs a thread, DisableCredGuardWaitThread, that blocks waiting on a named kernel event object:

\LSA_ISO_DISABLE_CREDENTIAL_GUARD

Signalling that event wakes the thread, which tears down the Credential Guard credential provider at runtime. No kernel driver and no reboot are involved - the OS simply stops isolating new credentials for the remainder of the boot.

Two properties make this an attacker primitive rather than a mere curiosity:

Who can signal it. The event's DACL grants EVENT_MODIFY_STATE only to SYSTEM. From a high-integrity administrator process that already holds SeDebugPrivilege, SYSTEM is reachable by stealing and impersonating a SYSTEM token (classically winlogon.exe) via OpenProcessToken → DuplicateTokenEx → ImpersonateLoggedOnUser - see token impersonation.

Only new sessions are exposed. Teardown does not reach back into VTL1 and surface credentials that were isolated earlier. Sessions that existed before the shutdown stay protected in VTL1. To obtain a usable secret, the attacker must force a fresh logon after the teardown - that session's NT hash then materialises in plaintext in ordinary VTL0 lsass.exe memory.

Practice

Enumeration

Before attempting any bypass, verify whether Credential Guard is actually active on the target.

# Check VBS and Credential Guard status
Get-CimInstance -ClassName Win32_DeviceGuard -Namespace root\Microsoft\Windows\DeviceGuard | Select-Object -Property SecurityServicesRunning, VirtualizationBasedSecurityStatus

SecurityServicesRunning contains 1 if Credential Guard is active, 2 if HVCI is active.

Runtime teardown (reboot-less)

The runtime teardown disables Credential Guard on the fly by signaling the \LSA_ISO_DISABLE_CREDENTIAL_GUARD kernel event as SYSTEM. No driver, no reboot. Credentials from sessions created after the teardown materialise in plain VTL0 LSASS memory and can be dumped normally.

CredGuardRuntimeShutdown (C) performs the full chain: impersonate SYSTEM via winlogon.exe, signal the disable event, wait for teardown, create a test logon session, then scan LSASS for the NT hash.

# Compile (MinGW)
gcc -o credguard_poc.exe credguard_poc.c -lntdll -lwincrypt -ldbghelp

# Run from a high-integrity admin shell
# <user> <domain> <password> - account must exist on the target
credguard_poc.exe sshuser . password

After a successful teardown, SecurityServicesRunning drops from [1, 2] to [2]. The named event is consumed: a second run on the same boot returns STATUS_OBJECT_NAME_NOT_FOUND (0xC0000034), meaning CG is already off.

The +0x1F6 NT-hash offset inside MSV1_0_PRIMARY_CREDENTIAL is specific to Win11 24H2 build 26200. Verify the struct layout with a kernel debugger on other builds, or fall back to the minidump written at C:\Windows\Temp\lsass_post.dmp.

Once Credential Guard is torn down, credentials from new logon sessions can be recovered with any standard LSASS dumping technique:

# Offline analysis of the minidump
pypykatz lsa minidump C:\Windows\Temp\lsass_post.dmp

# Or with Mimikatz on the live process
sekurlsa::logonpasswords

Persistent disable (reboot required)

The classic approach removes the Credential Guard configuration so it does not start on the next boot. This requires a reboot, which is louder but persistent across boots.

Disable Credential Guard via registry, then reboot.

# Disable Credential Guard
reg add "HKLM\SYSTEM\CurrentControlSet\Control\LSA" /v LsaCfgFlags /t REG_DWORD /d 0 /f
reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows\DeviceGuard" /v EnableVirtualizationBasedSecurity /t REG_DWORD /d 0 /f
reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows\DeviceGuard" /v LsaCfgFlags /t REG_DWORD /d 0 /f

# Reboot
shutdown /r /t 0

Circumventing Credential Guard (without disabling it)

Credential Guard only protects derived secrets at rest in VTL1. Credentials can still be captured on paths it was never designed to cover.

In-memory SSP injection

A malicious Security Support Provider loaded into the VTL0 lsass.exe sees plaintext credentials as they flow through the logon path, before they ever reach VTL1.

Mimikatz can inject a memory-only SSP into LSASS that logs all future authentications to C:\Windows\System32\mimilsa.log.

privilege::debug
misc::memssp

Any subsequent interactive logon on the host writes the cleartext password to mimilsa.log, regardless of Credential Guard.

Other credential capture paths

Credential Guard does not protect these vectors, which can be used to harvest credentials even while VTL1 isolation is fully active:

Detection

IndicatorSource
NtOpenEvent on \LSA_ISO_DISABLE_CREDENTIAL_GUARDETW Security Auditing event 4656 (Audit Kernel Object)
OpenProcess(winlogon, …) from a non-SYSTEM processSysmon event 10 (ProcessAccess)
Win32_DeviceGuard.SecurityServicesRunning drops from [1, 2] to [2]WMI polling
LogonUserA followed by OpenProcess(lsass, VM_READ) in the same processEDR behavioural correlation

Resources

github.comgithub.com learn.microsoft.comlearn.microsoft.com learn.microsoft.comlearn.microsoft.com

On this page