The Empty Hash: Credential Guard, the LsaIso Trustlet, and the Eleven-Year LSASS Extraction Tradition
Why a 2026 Mimikatz dump returns [LSA Isolated Data] instead of an NTLM hash, what LsaIso.exe really computes, and the five things Credential Guard was never going to close.
Permalink1. The 3:14 a.m. Mimikatz that returned an empty hash
It is 3:14 a.m. on a 2026 Windows 11 24H2 box. The operator has SYSTEM. The operator has SeDebugPrivilege. The operator has bypassed Protected Process Light the way PPLdump did in 2021, has dumped lsass.exe with sekurlsa::logonpasswords from Mimikatz, and is staring at the screen.
For the nine years before mid-2015, the next line on that screen would have been the user's NTLM hash. Tonight, the next line is something else entirely.
The literal string [LSA Isolated Data] sits where the NTLM hash used to sit. The hex prefix a000000000000000 is the same prefix on every Credential-Guard-protected box on the planet. The trailing ASCII tag 4e746c6d48617368 decodes to NtlmHash: the field name survives, the value does not.
This article is the deep look at the canonical VBS trustlet that is responsible for that empty hash. It is the companion piece to the broader VBS trustlets treatment in this series, which uses LsaIso.exe as its running example without unfolding the four things that matter most about it: the eleven-year extraction history that motivated the design; what LsaIso.exe actually computes and what every field of the encrypted blob means; Pass-the-Challenge -- the residual class Credential Guard was never going to close; and the honest, Microsoft-documented limits, enumerated.
A note on intent and verification: this is defensive research. Every primary source was verified live on 2026-05-11, against the public web; every command and tool named is in the open-source security canon, used today by Microsoft's own product teams, by enterprise red teams, and by every blue team that takes the storage-versus-use distinction seriously.
The hash is not in the dump because the hash is no longer in the process. Where it went, and why Microsoft moved it, is twenty-two years of lsass.exe history.
2. Why LSASS became the single highest-value memory dump on Windows (1993--2014)
Twenty-two years before the empty hash, lsass.exe shipped in Windows NT 3.1. It was not, at first, the most-attacked process on Windows. It became that, slowly, over the course of eleven years and one tool. This is the tradition the trustlet was built to break.
The user-mode Windows service that handles interactive logon, NTLM challenge-response, Kerberos AS/TGS exchanges, security-policy enforcement, password changes, and the loading of every Security Support Provider DLL the system uses for authentication. Until Credential Guard, it also held every long-lived authentication secret for every signed-in user in its own process memory, because the protocols it implemented required the secret to be present when the network talked to it. See the canonical LSA Authentication reference.
The architectural reason lsass.exe had to hold the secret is structural to the protocols it speaks. NTLM and Kerberos are challenge-response protocols. The server sends a challenge; the client encrypts the challenge with a key derived from the password; the server compares. The key the client uses is not the password itself but the NT one-way function output (NTOWF) -- the MD4 of the UTF-16-LE password. For Kerberos the client uses a long-term key (DES, RC4, or AES) derived from the password under a protocol-defined string-to-key function. In both cases the server expects the client to prove possession of a value that is functionally equivalent to the password, every time the client authenticates.
The MD4 hash of the UTF-16-LE encoded password. Despite the name, NTOWF is one-way only with respect to the original password. With respect to the network, the NTOWF is the credential: any process that holds it can compute the response to any NTLM challenge any server will ever issue, with no further information about the user.
For single-sign-on to work -- the user types the password once, the OS uses it transparently for every later authentication that day -- something has to remember that derived value, in clear, in a process that wakes up whenever a remote service asks the kernel to authenticate. That something is lsass.exe. Until 2015, "remembers" meant "holds the bytes in process memory."
DES(NTOWF, challenge) accepts the NTOWF directly. An attacker who holds the NTOWF and can reach a server that speaks NTLM does not need to know the password at all. This is the structural reason Pass-the-Hash works on every NTLM-speaking service in the network.
The eight inflection points
In 1997, Paul Ashton published the original Pass-the-Hash technique on Bugtraq -- a modified Samba SMB client that accepted user password hashes instead of cleartext passwords. The conceptual claim landed: if the client only proves possession of the hash, the hash is the credential. The implementation claim took another eleven years to land.
In 2001, Sir Dystic of Cult of the Dead Cow disclosed SMBRelay at lanta.con on March 31 (not March 21 as some Wikipedia revisions claim, per the project's own page). SMBRelay was the use-class breakthrough: rather than crack the hash, intercept the protocol exchange and let the victim's own client do the cryptography against the attacker's chosen target.
In 2008, Hernan Ochoa shipped the Pass-the-Hash Toolkit -- the load-bearing 2008 contribution -- and introduced "dump the hash from lsass.exe memory" as a public, repeatable post-exploitation technique. The toolkit was later superseded by Windows Credential Editor. For the first time, an attacker did not need to crack anything. The attacker needed OpenProcess(VM_READ) on lsass.exe and a parser.
In May 2011, Benjamin Delpy released Mimikatz, closed-source, and added one feature on top of WCE that turned the field upside down: sekurlsa::logonpasswords returned not just NTLM hashes but plaintext WDigest passwords. WDigest -- a digest-authentication SSP that Microsoft had shipped in Windows XP and Server 2003 to support HTTP digest -- stored the encrypted password blob and the encryption key in lsass.exe memory, simultaneously, so that the SSP could re-derive the digest response on demand. Delpy called the result, accurately, "like storing a password-protected secret in an email with the password in the same email".
"It's like storing a password-protected secret in an email with the password in the same email." -- Benjamin Delpy, on the WDigest plaintext-cache architecture
In September 2011, Mimikatz was used in the DigiNotar breach -- the certificate-authority compromise that issued forged Google, Microsoft, and Twitter certificates to roughly 300,000 Iranian Gmail users. Mimikatz crossed from researcher curio to nation-state-grade tradecraft in a single news cycle.
Wired's profile recounts an early-2012 Positive Hack Days incident in Moscow in which, immediately after Delpy's Mimikatz talk, a man in a dark suit demanded that Delpy put his slides and a copy of Mimikatz on a USB drive. Delpy complied and then -- before leaving Russia -- published the code as open source on GitHub. It is the moment Delpy realised he had built something that nation-state services were now travelling to obtain in person.On April 6, 2014, at 22:02:03, Delpy committed Mimikatz 2.0 to GitHub as open source. The compile timestamp is in the README banner, verbatim. Microsoft's lead time on every WDigest-class disclosure dropped from "months" to "the next minute any attacker reads the README."
On May 13, 2014, Microsoft shipped KB2871997 / MSA 2871997. On Windows 8.1 and Server 2012 R2 and later, the registry value WDigest\UseLogonCredential defaults to 0 and WDigest no longer caches plaintext credentials in lsass.exe memory. The plaintext leg closed. The hash leg could not, because the protocol required it.
Diagram source
timeline
title LSASS as the highest-value Windows process, 1993-2014
1993 : NT 3.1 ships : lsass.exe holds NTOWF + Kerberos keys
1997 : Paul Ashton : Pass-the-Hash on Bugtraq
2001 : Sir Dystic : SMBRelay at lanta.con
2008 : Hernan Ochoa : Pass-the-Hash Toolkit (later WCE)
2011 : Benjamin Delpy : Mimikatz closed-source release (May)
2011 : DigiNotar breach : Mimikatz used in the wild (September)
2014 : Mimikatz 2.0 : GitHub open-source (April 6, 22:02:03)
2014 : KB2871997 : WDigest cache disabled by default (May 13) The class of attack in which an authenticated client proves possession of an NTOWF (the NT one-way function output, MD4 of the UTF-16-LE password) directly, without ever knowing the cleartext password. The technique was originally published by Paul Ashton in 1997 and was made native to Windows by Hernan Ochoa's 2008 Pass-the-Hash Toolkit. It is structural to the NTLM protocol; closing the class requires either eliminating the protocol or moving the hash out of any process the attacker can read.
By May 2014, Microsoft had patched what could be patched. Mimikatz 2.0 was on GitHub. The hash was still in the process, because it had to be. The next move had to be architectural. But before Microsoft made that move, they tried four other things.
3. What Microsoft tried before trustlets (2007--2014)
If you cannot move the secret, what can you do? Microsoft tried four answers between 2007 and 2014. Each is in production today. None of them moves the secret.
Generation 2: Vista's Protected Process (2007)
In Windows Vista, Microsoft introduced the Protected Process primitive: a binary signed under a designated Microsoft media-protection certificate could run in a process whose memory other Windows processes -- including processes running as administrator -- could not read or modify. The reason was DRM. Audio and video pipelines wanted a way to keep AACS and PlayReady decryption keys out of debuggers. The Protected Process primitive was not, in 2007, applied to lsass.exe. Six years passed before Microsoft generalised it.
Generation 3: LSA Protection / RunAsPPL (2013)
In Windows 8.1, Microsoft generalised Protected Process into Protected Process Light (PPL), a signer-level lattice that allowed multiple signer "kinds" to live alongside the original DRM kind, and the RunAsPPL registry value lit up lsass.exe as a PPL.
A Windows process that runs at a signer-level higher than ordinary administrator processes, such that ordinary administrators cannot open it for memory read or for code injection. Created in Windows 8.1 as a generalisation of the Vista Protected Process primitive. Enforcement is done by the NT kernel: OpenProcess with PROCESS_VM_READ from a non-PPL caller returns ERROR_ACCESS_DENIED (0x5) regardless of the caller's token privileges.
itm4n's reference write-up of RunAsPPL reproduces what Mimikatz sees on a PPL-protected lsass.exe: the call to OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, lsass_pid) -- the verbatim opener of kuhl_m_sekurlsa_acquireLSA() -- fails with 0x00000005, ERROR_ACCESS_DENIED. The hash extraction routine never runs, because the attacker cannot read the page.
itm4n's writeup is also the canonical source for what RunAsPPL is not. The same NT kernel that enforces PPL is the kernel the attacker is trying to subvert. Two bypass classes exist in the public record. The first is kernel-mode: an attacker who loads a signed driver -- including Delpy's own mimidrv.sys -- can suspend PPL enforcement from kernel-space because the kernel is the enforcement mechanism. This is the bring your own vulnerable driver bypass class.
A privilege-escalation pattern in which an attacker with administrator privilege loads a signed-but-vulnerable third-party driver, then exploits a known vulnerability in the driver to run arbitrary code at kernel mode. Because the driver is signed, the kernel loads it; because the kernel loaded the driver, the driver can disable any defence the kernel enforces, including PPL. Microsoft's recommended vulnerable-driver block-list shrinks the BYOVD inventory; it does not eliminate the class. Delpy's own mimidrv.sys is the canonical reference exploit driver for this class against lsass.exe.
The second is userland: itm4n's PPLdump (April 2021) exploited a structural weakness in the PPL section-validation logic. A new Windows process loads NTDLL, then asks the image loader to load other DLLs. PPLs are allowed to load DLLs from the \KnownDlls directory, and -- crucially -- the digital signature of a \KnownDlls entry is checked when the section is created, not when it is mapped into the address space of a PPL process. PPLdump used DefineDosDevice to swap the symbolic link of a \KnownDlls entry under a transactional NTFS, and the PPL lsass.exe mapped the swapped-in attacker DLL into its own address space, with PPL enforcement intact. The SCRT writeup is the canonical 2021 reference. Microsoft closed the userland weakness in build 19044.1826, the July 2022 update, with an LdrpInitializeProcess patch in NTDLL gated by a Feature_Servicing_2206c_38427506__private_IsEnabled feature flag. On Windows 8.1 and Server 2012 R2, PPLdump's behaviour is unstable per the project README: itm4n notes the exploit fails on fully updated machines for an unidentified earlier patch. The userland weakness is therefore closed across the modern estate; legacy boxes that have lapsed on cumulative updates remain the practical exposure.
Generation 4: KB2871997 + the compensating-control playbook (2014)
KB2871997 shipped on May 13, 2014 and rolled up three behavioural changes: WDigest cache disabled by default in Windows 8.1 / Server 2012 R2 and later (UseLogonCredential = 0); the TokenLeakDetectDelaySecs registry default; and a follow-on October 14, 2014 update that added Restricted Admin mode for Remote Desktop Connection on Windows 7 / Server 2008 R2. The same broader 2013--2014 credential-protection initiative also delivered the Protected Users group (an Active Directory feature shipped in Windows 8.1 / Server 2012 R2, October 2013). Protected Users is the device-side mitigation: members cannot use credential delegation (CredSSP), Windows Digest, NTLM cached credentials or NTOWFs, DES or RC4 in Kerberos preauthentication, or offline cached verifiers; their TGT lifetime is capped at four hours.
Generation 4.5: Tier 0 isolation, jump-server architecture, AdminSDHolder hygiene
The Mitigating Pass-the-Hash v1 (2012) and v2 (2014) playbooks layered organisational changes on top of the per-host technical changes: tier the administrative model so that Tier 0 credentials never log on to Tier 1 or Tier 2 hosts; require every Tier 0 administrative session to traverse a dedicated jump server; clean up AdminSDHolder so that orphaned high-privilege accounts cannot be re-used. The playbooks are still cited in 2026 deployment guides because the underlying recommendations remain correct.
Diagram source
flowchart TD
G0["Gen 0: NT 3.1 lsass.exe (1993)
NTOWF + Kerberos keys in process memory"]
G1["Gen 1: WDigest plaintext cache (XP/2003)
Plaintext + key both in lsass.exe"]
G2["Gen 2: Vista Protected Process (2007)
For DRM; not applied to lsass.exe"]
G3["Gen 3: LSA Protection / RunAsPPL (2013)
NT-kernel-enforced; mimidrv + PPLdump bypassable"]
G4["Gen 4: KB2871997 + Protected Users (2014)
WDigest off; AES-only Kerberos; 4hr TGT"]
G5["Gen 5: Credential Guard / LsaIso.exe (2015)
Hypervisor-enforced; NT kernel out of TCB"]
G6["Gen 6: Default-on (Win 11 22H2 / Server 2025)
No-UEFI-lock"]
G0 --> G1 --> G2 --> G3 --> G4
G4 -->|"NT kernel still in TCB"| G5
G5 --> G6 As long as the secret lives in a process whose address space is governed by the same NT kernel that the attacker can compromise, the secret is extractable. Generations 0--4 add layers inside the NT-kernel TCB. The 2014 conclusion -- that you cannot patch your way out of the storage problem -- is structural to that TCB argument; the chain Gen 0 -> Gen 4 above traces it explicitly.
Each of these layers shrinks the attack surface. None of them changes where the hash physically lives. The 2014 conclusion was unavoidable: the only fix is to move the hash out of the kernel that the attacker can compromise. So Microsoft did.
4. Credential Guard lands, then hardens, then defaults on (May 2015 -- November 2024)
On May 4, 2015, Brad Anderson stood at Microsoft Ignite and said "more than 75 percent of all these attacks come down to weak credentials or compromised identities." Eighty-six days later, Windows 10 Enterprise RTM shipped with LsaIso.exe running in VTL1.
The eight-event chronology
On May 4, 2015, the Anderson Ignite keynote announced Virtualization-Based Security, Device Guard, and Credential Guard alongside the Hello and Microsoft Passport identity story. On July 29, 2015, Windows 10 RTM shipped with LsaIso.exe as Trustlet ID 1 on Enterprise and Education SKUs. On August 5--6, 2015, Alex Ionescu reverse-engineered the trustlet model at Black Hat USA and published the slide deck that documents the dual-EKU + Signature Level 12 constraint and names LSAISO.EXE as Trustlet ID 1 verbatim.
Through 2016--2020, Server 2016 brought Credential Guard to server installs, and the VSM master key + TPM 2.0 binding hardened the persistent-state path. On December 26, 2022, Oliver Lyak published Pass-the-Challenge: the trustlet itself was faithful, but its RPC output became the new attack surface.
On September 20, 2022, Windows 11 22H2 became generally available with Credential Guard default-on for domain-joined non-DC hardware-eligible boxes, shipped without UEFI Lock. On November 1, 2024, Windows Server 2025 became generally available and extended the default-on stance to server with the same domain-controller carve-out: "Enabling Credential Guard on domain controllers isn't recommended. Credential Guard doesn't provide any added security to domain controllers, and can cause application compatibility issues on domain controllers."
A binary signed at Signature Level 12 with both the Windows System Component Verification EKU (1.3.6.1.4.1.311.10.3.6) and the Isolated User Mode EKU (1.3.6.1.4.1.311.10.3.37), exporting an s_IumPolicyMetadata structure from a .tpolicy PE section, loaded by the Secure Kernel into VTL1 user mode at boot via NtCreateUserProcess with the PsAttributeSecureProcess attribute. Documented verbatim in Alex Ionescu's Black Hat USA 2015 deck, which is still the load-bearing reverse-engineering primary on the trustlet model.
Two privilege levels enforced by the Hyper-V hypervisor on top of the host CPU's existing ring 0 / ring 3 split. VTL0 is the Normal World: Ring 3 user mode and Ring 0 NT kernel mode. VTL1 is the Secure World: Ring 3 user mode runs trustlets like LsaIso.exe, Ring 0 runs the Secure Kernel (securekernel.exe). The hypervisor uses Second-Level Address Translation (SLAT) to ensure VTL0 page tables cannot map physical pages that VTL1 has marked private. The Hypervisor TLFS Virtual Secure Mode reference defines #define HV_NUM_VTLS 2 and notes that "Architecturally, up to 16 levels of VTLs are supported; however a hypervisor may choose to implement fewer than 16 VTLs. Currently, only two VTLs are implemented."
The Ring-3 user mode component of VTL1. IUM hosts trustlets (signed user-mode binaries) that the Secure Kernel loads at boot. IUM processes have no device drivers, no third-party modules, and no normal-world IPC except via the explicitly-marshalled secure-call interface that the Secure Kernel mediates. Quarkslab's IUM debugging walkthrough names "the isolated version of LSASS (LSAIso.exe) when Credential Guard is enabled" as the canonical IUM example.
LSAISO.EXE (Credential Guard); Trustlet ID 2 is vmsp.exe (the Hyper-V virtual TPM host side); Trustlet ID 3 is the vTPM provisioning trustlet. Eleven years later, that list is still exactly four, with ID 1 still the most-discussed.
Every domain-joined Windows 11 box ships with LsaIso.exe running today. What that small binary actually is, what it computes, and what an attacker who has SYSTEM on the box now sees is the load-bearing technical question of the next section.
5. What LsaIso.exe actually is
The trustlet is a small binary that sits inside a separate kernel from the one your shell is running under. Its identity is precise, its API is small, and its memory is unreadable from the side of the boundary you are on. Microsoft's documentation gives the one-sentence shape:
"With Credential Guard enabled, the LSA process in the operating system talks to a component called the isolated LSA process that stores and protects those secrets, LSAIso.exe. Data stored by the isolated LSA process is protected using VBS and isn't accessible to the rest of the operating system." -- Microsoft Learn, How Credential Guard works
That sentence hides everything interesting. The next six subsections unfold it.
5.1 Identity in the trustlet model
LsaIso.exe passes the five-gate trustlet definition by construction: Trustlet ID 1; signed at Signature Level 12; carries both the Windows System Component Verification EKU (1.3.6.1.4.1.311.10.3.6) and the Isolated User Mode EKU (1.3.6.1.4.1.311.10.3.37); exports the s_IumPolicyMetadata structure from a .tpolicy PE section; and is loaded by SMSS / wininit at boot through NtCreateUserProcess with the PsAttributeSecureProcess attribute, which routes through the Secure Kernel rather than the NT kernel.
An Extended Key Usage object identifier embedded in an Authenticode signature that constrains what the signed binary is allowed to do. The Windows kernel and Secure Kernel inspect EKUs at load time. The dual-EKU requirement on trustlets means a signature legitimate for ordinary kernel-mode driver loading is not sufficient to load a binary as a trustlet; both the WSCV and the IUM EKU must be present, both signed by Microsoft.
The two EKUs together are the identity gate. A binary that has only the WSCV EKU is a normal Microsoft-signed component. The IUM EKU is not a publicly issuable Authenticode EKU; only Microsoft can mint it -- per the Trustlet identity model documented verbatim in Ionescu's Black Hat USA 2015 deck. A binary that has only the IUM EKU does not exist in the wild. A binary that has both, and is signed by Microsoft, is admissible as a trustlet. The IUM EKU is not issued by any commercial CA; it is a Microsoft-internal OID with a Microsoft-internal issuance policy.
5.2 The agent / trustlet split
Credential Guard splits lsass.exe (the historical agent) into two cooperating processes:
lsass.exein VTL0 holds protocol state, network I/O, and every Security Support Provider DLL the system loads:msv1_0.dll(NTLM),kerberos.dll(Kerberos),negoexts.dll(SPNEGO extensions),cloudap.dll(the Microsoft Entra cloud authentication package),wdigest.dll(Digest, with caching disabled),tspkg.dll(Terminal Services / CredSSP),livessp.dll(Microsoft account / Live),pku2u.dll(peer-to-peer Kerberos), andschannel.dll(TLS). The core SSP/AP set (Negotiate, Kerberos, NTLM, Digest, CredSSP, Schannel) is enumerated in Microsoft's SSP Packages Provided by Microsoft reference; CloudAP, NegoExts, TSPkg, LiveSSP, and PKU2U are documented under the broader LSA Authentication reference.lsass.exedoes not hold the long-lived NTOWF or Kerberos long-term keys.LsaIso.exein VTL1 holds only the long-lived NTOWF and the Kerberos long-term keys, plus a small fixed RPC API that lets the agent compute responses against those keys without ever seeing the keys.
Diagram source
flowchart LR
subgraph VTL0NT["VTL0 -- NT kernel governs the entire user-mode process space"]
L["lsass.exe
NTOWF, Kerberos keys,
SSP DLLs, network I/O"]
M["mimikatz
SeDebugPrivilege"]
end
M -->|"OpenProcess(VM_READ) + memory dump"| L Diagram source
flowchart LR
subgraph V0["VTL0 (Normal World)"]
L["lsass.exe
SSP DLLs, network I/O,
protocol state
(NO long-term key)"]
M["mimikatz
SeDebugPrivilege"]
end
subgraph V1["VTL1 (Secure World)"]
I["LsaIso.exe
NTOWF + Kerberos keys"]
SK["securekernel.exe
(secure kernel)"]
end
M -->|"OpenProcess(VM_READ)"| L
L -->|"LSA_ISO_RPC_SERVER ALPC
NtlmIumCalculateNtResponse(...)"| SK
SK -->|"validated secure call"| I
I -->|"derived response"| SK
SK -->|"return value"| L The architectural pivot is that the mimikatz-style memory dump still reaches lsass.exe, but it no longer reaches the long-term key. The key has moved across a boundary the hypervisor enforces with hardware page-table-permission bits, and no VTL0 process -- regardless of token, regardless of privilege -- can map the page.
5.3 The encrypted-blob format and the IUM API
The visible artefact of the move is the [LSA Isolated Data] block in the Pypykatz dump from §1. The structure of that block is documented byte-by-byte in the PassTheChallenge README: an opaque encrypted payload, a Context Handle (an opaque RPC handle that identifies the per-logon session inside the trustlet), a Proxy Info field that points to the protocol-side session metadata in lsass.exe, and a DPAPI GUID that ties the encrypted blob to the per-user DPAPI master-key chain.
The Windows API for protecting per-user secrets at rest. The DPAPI master-key chain is keyed off the user's password (or NTOWF for Pass-the-Hash-resistant variants), and is the canonical persistence layer for credentials and certificates that need to survive process restarts. In the Credential Guard architecture, the per-user DPAPI keys are themselves derived from material the trustlet has access to; the GUID in the [LSA Isolated Data] block links the in-memory trustlet record to the on-disk DPAPI chain.
The four IUM-side methods that matter for NTLM authentication, as documented by Lyak's Pass-the-Challenge writeup:
EncryptData/DecryptData: the trustlet's general-purpose AES-GCM wrap and unwrap on opaque blobs, used by every other Credential Guard code path that needs to round-trip a secret throughlsass.exememory withoutlsass.exeever seeing the cleartext.NtlmIumProtectCredential: the trustlet entry point that converts an NTOWF supplied bylsass.exeimmediately after a logon (when the user typed the password andmsv1_0.dllderived the NTOWF in VTL0 memory) into the isolated form. After this call returns, the only copy of the NTOWF that survives is inside the trustlet.NtlmIumCalculateNtResponse: the trustlet entry point that computes an NTLMv1 response from the protected NTOWF and a server-supplied challenge. This is the function that gets called every time the user authenticates to an SMB share, an MS-SQL server, an Exchange front-end, or any other NTLM endpoint.NtlmIumLm20GetNtlm3ChallengeResponse: the equivalent for NTLMv2.
The Pypykatz fork output structure carries the exact byte layout for all of this: Is NT Present, Context Handle, Proxy Info, Encrypted blob, DPAPI. The verbatim hex prefix a000000000000000080000006400000001000000010100000100000036 is a length-prefixed serialisation header. The literal string 4e746c6d48617368 -- which decodes from hex to the ASCII string NtlmHash -- is the field-name tag inside the ciphertext. The ciphertext itself is the AES-GCM-wrapped NTOWF; the tag tells you what the cleartext used to be called.
// The verbatim hex prefix from the PassTheChallenge README dump example.
// (Full blob is longer; this prefix is the load-bearing identifying header.)
const blobPrefix = 'a000000000000000080000006400000001000000010100000100000036';
// Inferred field decomposition from the byte pattern of the verbatim
// PassTheChallenge README dump example. The README documents the hex-dump
// shape and the embedded NtlmHash ASCII tag, but does not name the per-byte
// fields; the decomposition below is illustrative.
// [ProtectionLevel | StructLen | Version | Cipher | TagLen | EncryptedPayload]
// The encrypted payload itself contains an embedded ASCII tag identifying
// the field that was wrapped.
function parseHeader(hex) {
const bytes = hex.match(/.{2}/g).map(b => parseInt(b, 16));
// Little-endian 64-bit length-like fields; the trustlet uses fixed widths.
const protectionLevel = bytes[0]; // 0xa0 in this dump
const structLen = bytes.slice(8, 16); // 8 bytes (LE)
const version = bytes[16]; // 0x01
const cipher = bytes[20]; // 0x01 = AES-GCM
const tagLen = bytes[24]; // 0x01
return { protectionLevel, structLen, version, cipher, tagLen };
}
const fields = parseHeader(blobPrefix);
console.log('ProtectionLevel:', '0x' + fields.protectionLevel.toString(16));
console.log('Version :', fields.version);
console.log('Cipher :', fields.cipher === 1 ? 'AES-GCM (per spec)' : 'unknown');
console.log('TagLen :', fields.tagLen);
// The literal '4e746c6d48617368' (= ASCII 'NtlmHash') sits inside the ciphertext
// further into the blob. Its presence is the verifiable 'this really is the hash'
// signal in the PassTheChallenge dumps.
const ntlmHashTag = Buffer.from('4e746c6d48617368', 'hex').toString('ascii');
console.log('Embedded tag :', ntlmHashTag); // -> 'NtlmHash' Press Run to execute.
5.4 The LSA_ISO_RPC_SERVER ALPC port
The agent reaches the trustlet through a single secure-call endpoint named LSA_ISO_RPC_SERVER (terminology per Lyak's writeup). The marshalling layer is the IUM Base API. The actual VTL boundary crossing is a hypercall: when a VTL0 thread invokes the secure call, the hypervisor switches the CPU to VTL1, the Secure Kernel inspects the call ordinal, copies the input buffer across the boundary into a VTL1-owned page, and dispatches to the trustlet's entry point. The reverse path mirrors that step for the return value.
The undocumented Windows IPC primitive that succeeds the older LPC. ALPC ports support multiple message-passing modes, fast handles, and direct shared-memory regions. In Credential Guard, the agent talks to the trustlet via an ALPC port whose server side is implemented inside the Secure Kernel, so that the IPC delivery path itself crosses the VTL boundary without exposing any VTL1 memory to VTL0. Lyak's Pass-the-Challenge writeup names the channel verbatim.
This single endpoint is the entire externally-reachable surface of the trustlet. There is no debugger interface, no driver-load path, no shared-memory region, and no second ALPC port. The trustlet's code runs only when the agent calls it, and the agent can only call it through one specific channel that the Secure Kernel mediates.
Diagram source
sequenceDiagram
participant SRV as Remote SMB server
participant LSASS as "lsass.exe (VTL0 -- msv1_0.dll)"
participant SK as "securekernel.exe (VTL1 ring 0)"
participant ISO as "LsaIso.exe (VTL1 trustlet)"
SRV->>LSASS: NTLM challenge (8-byte server challenge)
LSASS->>SK: Secure call: NtlmIumCalculateNtResponse(ctxHandle, challenge)
SK->>SK: validate ordinal, copy input across VTL boundary
SK->>ISO: dispatch (NTOWF retrieved from sealed in-process state)
ISO->>ISO: Three-DES against the isolated NTOWF -- NTLMv1 DESL per MS-NLMP 3.3.1
ISO->>SK: derived 24-byte NTLMv1 response
SK->>LSASS: response (no NTOWF returned)
LSASS->>SRV: NTLMv1 response on the wire 5.5 The MSV1_0\IsolatedCredentialsRootSecret registry sentinel
Microsoft documents one verifiable artefact of default-on Credential Guard activation: the registry value Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0\IsolatedCredentialsRootSecret. Its presence on a Windows 11 22H2+ Pro / Pro Education box is the evidence that default-on activated the feature. A Pro Edu deployment that does not show this value either has Credential Guard explicitly disabled by policy, or sits on hardware that does not meet the requirements (no IOMMU, Secure Boot off, no virtualization extensions in firmware).
5.6 TPM binding and the VSM master key
Persistent state in Credential Guard is rare. The trustlet does not normally persist the NTOWF or TGT material across reboots; the next user logon re-derives both. When persistence is needed, the data is sealed under what Microsoft calls the VSM master key:
A symmetric key, generated and stored only in VTL1, that wraps any persistent state the trustlets need to survive reboots. The VSM master key is itself sealed by the TPM under PCR-bound policy, so an attacker who pulls the disk and reboots into a different OS cannot unseal the VSM master key without also reproducing the platform's pristine measured boot state. See the companion TPM in Windows article for the full seal / unseal primitive treatment.
Credential Guard removes the NT kernel from the TCB for the long-lived NTOWF and the Kerberos long-term keys, by moving them into a process whose pages no other VTL can map. The trustlet still answers queries about the keys; what changed is who can touch the bytes.
Where the hash physically lives, in 2026, is in pages of LsaIso.exe that the VTL0 NT kernel cannot map. What an attacker on a default-on Credential Guard box actually sees, what the verification surface for defenders is, and what the operational reality looks like in production is the next question.
6. The operational reality of default-on Credential Guard
Default-on means specifics. Specifically: every domain-joined Windows 11 22H2+ Enterprise / Education box that meets the hardware requirements has Virtualization-Based Security up, has LsaIso.exe running, has the registry sentinel at HKLM\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0\IsolatedCredentialsRootSecret written, and reports "Credential Guard" in the running-services bitmask of Win32_DeviceGuard. Pro and Pro Education boxes are not default-on targets; the special case where a Pro/Pro Edu device previously ran Credential Guard on Enterprise is the one path that lights it up there, and the registry sentinel from §5.5 is precisely how you detect that carry-over case.
Default-on scope and the no-UEFI-lock choice
Microsoft's Credential Guard overview page is precise about scope: Windows 11 22H2 and later (Enterprise, Education), Windows Server 2025, domain-joined non-DC, hardware-eligible (Hyper-V Generation 2 VM with IOMMU on virtual hardware; UEFI Secure Boot, virtualization extensions, IOMMU, and TPM 2.0 on physical hardware). Pro and Pro Education hold the licence entitlement only via the Enterprise-to-Pro carry-over case. The default-on policy ships "without UEFI Lock", which is a deliberate trade-off.
"Without UEFI Lock" means an administrator can disable Credential Guard remotely (via Group Policy, Intune, or a registry change) without first sending someone to the box's UEFI menu. The trade-off: an attacker who has already obtained the level of privilege required to write the registry can also undo the same setting. Microsoft chose remote-disable convenience over the in-principle attacker-disable hardening because compatibility incidents -- a rolled-out third-party SSP that breaks under CG -- are an operational reality, and not being able to disable the feature remotely turns an SSP regression into a desk-side support ticket. The overview page documents the rationale verbatim.The three supported verification surfaces
Microsoft's configuration guide names three supported ways to verify Credential Guard is running, and explicitly disrecommends a fourth:
msinfo32: opens the System Information UI; the line "Virtualization-based Security Services Running" includes "Credential Guard" when the trustlet is up.- PowerShell
Get-CimInstance Win32_DeviceGuard: returns aSecurityServicesRunningarray whose values are a bitmask. - WinInit Event ID 13 in the System log: "Credential Guard (LsaIso.exe) was started and will protect LSA credentials."
The disrecommended approach is "look for LsaIso.exe in Task Manager." Microsoft's words: "Checking Task Manager if LsaIso.exe is running isn't a recommended method for determining whether Credential Guard is running." Task Manager runs in VTL0 and queries an enumeration that an attacker who controls VTL0 can hide; the three supported surfaces all consult the hypervisor or the boot-time event log, neither of which a VTL0 attacker can edit.
// Mirrors what (Get-CimInstance Win32_DeviceGuard).SecurityServicesRunning returns.
// Microsoft's Win32_DeviceGuard documentation enumerates the values:
// 1 = Credential Guard
// 2 = Hypervisor-enforced Code Integrity (HVCI / Memory Integrity)
// 3 = System Guard Secure Launch
// 4 = SMM Firmware Measurement
// 5 = Kernel-mode Hardware-enforced Stack Protection
// 6 = Kernel-mode Hardware-enforced Stack Protection (Audit mode)
// 7 = Hypervisor-Enforced Paging Translation
// Note: MBEC (Mode-Based Execution Control) is a CPU capability advertised
// in the SEPARATE AvailableSecurityProperties array, not here.
const SECURITY_SERVICES = {
1: 'Credential Guard',
2: 'Hypervisor-enforced Code Integrity (HVCI)',
3: 'System Guard Secure Launch',
4: 'SMM Firmware Measurement',
5: 'Kernel-mode Hardware-enforced Stack Protection',
6: 'Kernel-mode Hardware-enforced Stack Protection (Audit mode)',
7: 'Hypervisor-Enforced Paging Translation'
};
function describe(running) {
if (!running.length) return 'No VBS services running';
return running.map(v => SECURITY_SERVICES[v] || ('Unknown service id ' + v)).join(', ');
}
// On a default-on Windows 11 22H2+ domain-joined Pro/Enterprise box this returns:
console.log(describe([1, 2]));
// => "Credential Guard, Hypervisor-enforced Code Integrity (HVCI)"
// On a Windows 10 box without VBS enabled:
console.log(describe([]));
// => "No VBS services running" Press Run to execute.
What changes for the protocols
When Credential Guard is enabled, four SSPs lose the ability to use signed-in credentials: "NTLMv1, MS-CHAPv2, Digest, and CredSSP can't use the signed-in credentials". For NTLMv1 and Digest the practical effect is small (NTLMv1 is end-of-life; Digest is essentially unused outside legacy HTTP digest authentication). For MS-CHAPv2 and CredSSP the effect is real: any single-sign-on path that depended on those protocols breaks with Credential Guard on. The considerations page calls out PEAP-MSCHAPv2 / EAP-MSCHAPv2 WiFi and VPN configurations explicitly: "If you're using WiFi and VPN endpoints that are based on MS-CHAPv2, they're subject to similar attacks as for NTLMv1." The recommended remediation is to migrate the endpoints to PEAP-TLS / EAP-TLS (certificate-based authentication).
For Kerberos, Credential Guard "doesn't allow unconstrained Kerberos delegation or DES encryption, not only for signed-in credentials, but also prompted or saved credentials". Constrained Delegation and Resource-Based Constrained Delegation continue to work. The remaining Kerberos etype choices on the wire on a Credential Guard box are AES-128 and AES-256.
What doesn't change
The agent surface still exposes every SSP that loads inside lsass.exe. The trustlet isolates the secret the SSP uses; it does not isolate the parser that the SSP runs against an attacker-controlled wire format. A bug in msv1_0.dll's NTLM parser is exactly as exploitable on a 2026 Credential-Guard-on box as it was on a 2015 Credential-Guard-off box. The trustlet does not guard the agent; the trustlet guards the key.
A VBS-based feature that uses the hypervisor's SLAT enforcement to ensure that any kernel-mode page that is executable is also signed and immutable, and any writable kernel-mode page is non-executable. HVCI closes the kernel-driver-loader leg of the BYOVD / PPL bypass class for unsigned drivers, but it does not close BYOVD against a signed-but-vulnerable driver. HVCI is orthogonal to Credential Guard; the overview page recommends running both.
Credential Guard is on; the surface is documented; the verification is one PowerShell line. So what other things claim to "protect LSASS," and how do they fit together with Credential Guard?
7. The other things that "protect LSASS"
Six other things in the Microsoft security stack get called "LSASS protection" in someone's marketing. None of them is a substitute for Credential Guard. Most of them are complements. The difference matters because the choice between them is not a choice; the answer is all of them, layered.
| Feature | Enforcement TCB | Attacker bar to defeat | Residual class it leaves open |
|---|---|---|---|
LSA Protection (RunAsPPL) | NT kernel (signer-level lattice) | Signed kernel driver (BYOVD via mimidrv.sys); userland on legacy via PPLdump | Trustlet RPC outputs; non-LSA process credentials |
Credential Guard / LsaIso.exe | Hypervisor + Secure Kernel + VTL1 trustlet | Hypervisor escape; VTL1 code-execution bug | Pass-the-Challenge; credential use; tokens; supplied creds |
| HVCI / Memory Integrity | Hypervisor-enforced kernel page W^X | Signed-and-vulnerable driver that does not load arbitrary unsigned code | Kernel-mode logic bugs in signed drivers |
| Defender for Identity LSASS read-monitoring | Behavioural detection (no TCB) | Stealth tradecraft that does not trip the canonical signatures | Anything not yet patterned |
| Hello for Business | Per-device TPM-bound asymmetric key (no shared secret on the wire) | TPM compromise; on-device keylogger before sign-in | Not a substitute -- it is what CG protects on cloud-joined boxes |
| Restricted Admin / Protected Users | Protocol-level credential-delegation suppression | Per-protocol; does not move where the secret lives | Everything Credential Guard already covers, plus the four-hour TGT cap |
LSA Protection's kernel-driver-loader bypass class is closed by HVCI for unsigned drivers but not for signed-and-vulnerable ones. Defender for Identity is a detection layer, not a TCB boundary. Hello for Business replaces the password with a TPM-bound asymmetric key: the Hello for Business overview row in the Security comparison table reads "It uses key-based or certificate-based authentication. There's no symmetric secret (password) which can be stolen from a server or phished from a user and used remotely." The Microsoft Entra ID Primary Refresh Token (PRT) inside cloudap.dll is the cloud-joined analogue of the on-prem trustlet model: the PRT itself is protected by the trustlet on Credential-Guard-enabled boxes, with Hello as the per-device long-term key chain. Restricted Admin and Protected Users suppress credential delegation at the protocol layer; on a Credential-Guard-on box they are additionally effective because they remove the prompt path, but they are not a substitute for the storage-isolation primitive.
Credential Guard closes the storage class. Layering closes the adjacent classes. But there are five classes the layers cannot close -- five things Credential Guard was never going to close, by documented design. The next section enumerates each one.
8. The five things Credential Guard was never going to close
Microsoft's own How Credential Guard works page lists what Credential Guard does not protect, in plain English. The list has five classes. Each class has a publicly disclosed worked example. Each worked example is in 2026 production attacker tradecraft. This is the honest accounting.
8.1 Pass-the-Challenge: the trustlet's RPC output as the new attack surface
On December 26, 2022, Oliver Lyak published Pass-the-Challenge. The technique is exactly the lesson of §5: the trustlet's pages are unreadable, but the trustlet's RPC output is exactly the response the attacker wants, and the attacker can ask for it.
The attack flow, end to end:
- The attacker has SYSTEM and
SeDebugPrivilegeon a Credential-Guard-on box (any of the bypass paths from §3 still apply for getting to that point; Credential Guard does not change them). - The attacker injects a security-package DLL named
SecurityPackage.dll(per the PassTheChallenge tool's source) intolsass.exe. Insidelsass.exe, that DLL inherits the established ALPC channel to the trustlet, because it is now part of the agent. - The attacker uses the Pypykatz fork to extract the per-logon
Context HandleandProxy Infofrom the[LSA Isolated Data]block of an existing user session. - The attacker calls the trustlet's
NtlmIumCalculateNtResponsemethod through the established ALPC channel, supplying theContext Handleand "the static challenge1122334455667788", the value historically used in pre-computed NTLMv1 rainbow tables and accepted by thecrack.shcracking service. - The trustlet faithfully returns the NTLMv1 response. No memory of the trustlet is read. No bug in the trustlet is exploited. The trustlet does what it was built to do.
- The attacker submits the response to
crack.sh. "In less than a minute, I received an email from crack.sh stating that the NTLM hash was successfully recovered in 30 seconds:65A13AB2FAEB5B700DE1A938AE5621CA."
There is also a v2 variant. Lyak: "Another interesting option is to compute an NTLMv2 response using the LSAIso method NtlmIumLm20GetNtlm3ChallengeResponse." The v2 variant uses an Impacket modification plus an AD CS Web Enrollment relay to obtain a certificate for the target user (Certipy's Administrator certificate-based authentication path) without needing the cleartext NT hash at all.
Diagram source
sequenceDiagram
participant ATT as Attacker (SYSTEM)
participant LSASS as "lsass.exe (VTL0) -- SecurityPackage.dll injected"
participant SK as "securekernel.exe (VTL1 ring 0)"
participant ISO as "LsaIso.exe (VTL1 trustlet)"
participant CRACK as crack.sh
ATT->>LSASS: Inject SecurityPackage.dll
ATT->>LSASS: Extract Context Handle from Pypykatz dump
LSASS->>SK: NtlmIumCalculateNtResponse(ctxHandle, 1122334455667788)
SK->>ISO: dispatch (signed-and-attested call)
ISO->>SK: 24-byte NTLMv1 response
SK->>LSASS: response
LSASS->>ATT: response (no NTOWF, just the ciphertext)
ATT->>CRACK: submit NTLMv1 ciphertext for 1122334455667788
CRACK->>ATT: NT hash recovered in ~30 seconds Microsoft's response landed in two phases. First, NTLMv1 was deprecated and disabled by default in Windows 11 24H2 / Server 2025, which removes the crack.sh rainbow-table leg specifically. Second, the trustlet stopped accepting NTLMv1 calls on the same builds. The class -- "use the trustlet to mint derived material" -- remains structural to the agent / trustlet split, because closing it requires removing either the agent's ability to call the trustlet (which would defeat single-sign-on) or the attacker's ability to compromise the agent (which is the point of every other layer in the stack).
8.2 Credential use without theft
Three named techniques in 2026 production tradecraft do not require reading the memory of any Credential-Guard-protected machine. They request derived material from the network and do offline cryptography on the response.
Kerberoasting. Tim Medin disclosed Kerberoasting at DerbyCon 4 in September 2014 under the talk title Attacking Microsoft Kerberos: Kicking the Guard Dog of Hades. The mechanism, per the MITRE ATT&CK technique page: any authenticated domain user requests a TGS-REP ticket for any registered Service Principal Name. "Portions of these tickets may be encrypted with the RC4 algorithm, meaning the Kerberos 5 TGS-REP etype 23 hash of the service account associated with the SPN is used as the private key and is thus vulnerable to offline Brute Force attacks that may expose plaintext credentials." The ticket arrives on the attacker's machine; the cracking happens on the attacker's GPUs; no memory of any Credential-Guard-protected box is ever read.
The class of attack in which any authenticated domain user requests a Kerberos TGS-REP ticket for any registered Service Principal Name and submits the encrypted portion of the response to offline cracking, recovering the service-account password if it is weak. Documented as MITRE ATT&CK T1558.003. Kerberoasting reads no memory of the targeted host; it consumes only network responses to entirely-legitimate Kerberos requests.
AS-REP Roasting. The same class for accounts with DONT_REQ_PREAUTH set: the attacker requests a Kerberos AS-REP without sending preauthentication, the KDC returns a ticket portion encrypted with the user's long-term key, and the attacker cracks offline.
Resource-Based Constrained Delegation (RBCD). Originally described by Elad Shamir in Wagging the Dog (January 2019); refined by James Forshaw's "Exploiting RBCD using a normal user" (May 2022); turned into a turnkey LPE by Dec0ne's KrbRelayUp (2022), which the README describes -- accurately -- as "essentially a universal no-fix local privilege escalation in windows domain environments where LDAP signing is not enforced (the default settings)." The attack abuses the msDS-AllowedToActOnBehalfOfOtherIdentity LDAP attribute: if the attacker can write that attribute on a target computer object, they can mint a Kerberos service ticket as anyone against the target. Forshaw's 2022 contribution removed the precondition that the attacker must control a computer account (it used to require a MachineAccountQuota-bypass); after Forshaw, any authenticated domain user with write access to the attribute is enough.
A Kerberos delegation feature in which the resource (server) lists which principals are allowed to delegate to it via the msDS-AllowedToActOnBehalfOfOtherIdentity LDAP attribute on the resource's computer object. RBCD enables S4U2Self and S4U2Proxy chains where the configured principal can request a service ticket as any user against the resource, including Domain Administrators. Abuse documented in Wagging the Dog, refined in tiraniddo.dev, and weaponised in KrbRelayUp.
8.3 The SeImpersonatePrivilege Potato chain
The Potato family is a chain of escalations from a low-privilege service user (anyone with SeImpersonatePrivilege or SeAssignPrimaryTokenPrivilege) to NT AUTHORITY\SYSTEM. The chain starts with Hot Potato (Stephen Breen, January 16, 2016): NBNS spoofing plus WPAD plus HTTP-to-SMB NTLM relay. The breenmachine writeup is verbatim: "Hot Potato (aka: Potato) takes advantage of known issues in Windows to gain local privilege escalation in default configurations, namely NTLM relay (specifically HTTP->SMB relay) and NBNS spoofing."
Rotten Potato (Breen + Chris Mallz, September 26, 2016) replaced the NBNS / WPAD / WSUS triggering with a synthesised DCOM round-trip via CoGetInstanceFromIStorage against the BITS CLSID 4991d34b-80a1-4291-83b6-3328366b9097 over a local TCP port, achieving 100% reliability across Windows versions. Juicy Potato (Andrea Pierini + Antonio Cocomazzi, November 2018) made the CLSID a parameter, dropping the BITS-on-port-6666 hardcoding. PrintSpoofer (itm4n, May 2, 2020) replaced the DCOM coercion with a Print Spooler named-pipe coercion, surviving Microsoft's Server 2019 / Windows 10 19H1 mitigations against the DCOM-based predecessors.
The Windows token privilege that allows a process to call ImpersonateLoggedOnUser against a token obtained from another security context. Service accounts (NT AUTHORITY\NETWORK SERVICE, IIS app pool identities, MSSQL service accounts) hold this privilege by default. As decoder_it first observed, if you have SeAssignPrimaryToken or SeImpersonate privilege, you are SYSTEM: combine it with a coerced inbound NTLM authentication from NT AUTHORITY\SYSTEM to a local listener, and CreateProcessWithToken finishes the chain.
The Potato chain exploits tokens, not credentials. The chain of Hot / Rotten / Juicy / PrintSpoofer / RoguePotato / GodPotato has been continuous since January 2016 because every link in the chain abuses a Windows OS feature (DCOM marshalling, RPC, named-pipe impersonation, Print Spooler, COM activation through alternative interfaces) that has a legitimate use case Microsoft cannot remove. Credential Guard does not protect tokens; Credential Guard protects credentials.
8.4 Plaintext-secret protocols and supplied credentials
"When Credential Guard is enabled, NTLMv1, MS-CHAPv2, Digest, and CredSSP can't use the signed-in credentials", but they can still be used with prompted or saved credentials. In every such case the cleartext password (or a symmetric secret derived from it) is supplied to lsass.exe from outside the trustlet, so the trustlet has nothing to protect at the moment of use.
The considerations page names PEAP-MSCHAPv2 / EAP-MSCHAPv2 WiFi and VPN configurations as the most consequential remaining surface in 2026: a corporate WiFi or VPN endpoint that authenticates users with MS-CHAPv2 still cracks under the same offline tradecraft as the original NTLMv1 attacks, because the protocol itself uses MD4 + DES against the user's NT hash. The recommendation: "organizations move away from passwords to other authentication methods, such as Windows Hello for Business, FIDO 2 security keys, or smart cards", or migrate the WiFi / VPN endpoint to certificate-based PEAP-TLS / EAP-TLS.
8.5 Out-of-LSA credential storage
Four storage locations are out of scope for Credential Guard by Microsoft's own design:
- Generic Credential Manager entries -- web passwords, browser-stored credentials, the Windows Credential Manager's "Web Credentials" tab. "Generic credentials, such as user names and passwords that you use to sign in websites, aren't protected since the applications require your clear-text password."
- Non-Microsoft Security Support Providers. "Some non-Microsoft Security Support Providers (SSPs and APs) might not be compatible with Credential Guard because it doesn't allow non-Microsoft SSPs to ask for password hashes from LSA. ... For example, using the KerbQuerySupplementalCredentialsMessage API isn't supported." Third-party SSPs that depend on hash retrieval through that API simply break under Credential Guard.
- The Active Directory database on domain controllers. "Credential Guard doesn't protect the Active Directory database running on Windows Server domain controllers." The most-attacked LSASS on the network --
lsass.exeon the domain controller, holdingNTDS.ditand thekrbtgtlong-term key -- is explicitly out of Credential Guard's scope. Microsoft's stated rationale is that domain controllers do not benefit from the same isolation, because the entire AD database is, by design, available to the LSA process on a DC. - Credential-input pipelines such as Remote Desktop Gateway and Just-In-Time admin access tooling, where the typed cleartext is supplied to
lsass.exeover an inbound network protocol and is in clear at the moment of arrival.
"Doesn't prevent an attacker with malware on the PC from using the privileges associated with any credential. We recommend using dedicated PCs for high value accounts." -- Microsoft Learn, How Credential Guard works
Diagram source
flowchart LR
CG["What CG closes:
Long-term key in lsass.exe memory"]
R1["Pass-the-Challenge:
trustlet RPC output
(Lyak, Dec 2022)"]
R2["Credential use without theft:
Kerberoast, AS-REP Roast,
RBCD / KrbRelayUp"]
R3["Token impersonation:
Hot/Rotten/Juicy/PrintSpoofer
SeImpersonatePrivilege"]
R4["Plaintext protocols:
NTLMv1, MS-CHAPv2, Digest,
CredSSP"]
R5["Out-of-LSA storage:
Web creds, non-MS SSPs,
NTDS.dit on DCs"]
CG -.does not close.-> R1
CG -.does not close.-> R2
CG -.does not close.-> R3
CG -.does not close.-> R4
CG -.does not close.-> R5 The trustlet is the storage layer; the agent is the use layer; an attacker who controls the agent can request derived material the trustlet was never going to refuse. This is the structural reason Credential Guard was never going to close the use surface.
Five classes documented; five worked examples named. What is not yet documented -- the open problems where the research is still in progress -- is what the next section walks.
9. Open problems
Five things the Credential Guard architecture has not yet closed. One of them is structural; four are deployment frontiers.
9.1 Trustlet IUM API surface fuzzing. Pass-the-Challenge proved one corner of the agent-callable RPC surface is exploitable when fed inputs the developer did not anticipate (the static 1122334455667788 challenge whose responses are pre-computed in commercial cracking tables). The systematic audit of every IUM API entry point -- there are not many; the trustlet is small -- has not been published. A blue-team-friendly fuzzer that exercises the channel from a controlled VTL0 agent against a controlled VTL1 target is on the public to-do list of several research groups.
9.2 Domain-controller LSASS / NTDS.dit / krbtgt protection. Microsoft documents the DC carve-out as out of scope. An architectural fix would require a DC-resident trustlet model that can answer Kerberos AS-REP and TGS-REP queries against the entire NTDS.dit without compromising AD replication semantics. That model is not on the public roadmap, and the practical recommendation -- the dedicated-Tier-0-PAW model from the Mitigating Pass-the-Hash v2 playbook -- still applies in 2026.
9.3 TGT and service-ticket lifetime in lsass.exe after the trustlet mints them. Pass-the-Ticket on the agent recovers the current TGT or service ticket from lsass.exe memory. Credential Guard isolates the long-term key; it does not isolate the per-session derived material that the agent has to hold to send on the wire. The trustlet's TGT protection is verbatim: the long-term-key path is closed, the service-ticket path is not. A 2026 attacker with SeDebugPrivilege who dumps lsass.exe recovers the Kerberos service tickets even though they cannot recover the underlying NTOWF.
9.5 Compatibility and observability frontier. The third-party SSP / MS-CHAPv2 / CredSSP behaviour-change surface keeps showing up in real-estate compatibility reports. Microsoft's Considerations page is updated routinely; the practical operational pattern in 2026 is "enable Credential Guard via Intune in audit mode for 30 days, harvest the compatibility errors, fix or replace the affected SSPs, then promote to enforce." That pattern is now well-trodden but the per-estate inventory is real work.
Open problems are interesting; daily practice is more interesting. What does a 2026 administrator, researcher, red-team operator, and detection engineer actually do with Credential Guard?
10. Practical guide
Four audiences; four operational checklists. Each is short because each builds on a section we have already walked.
For an administrator or platform engineer
Verify Credential Guard is running using the three supported surfaces: (Get-CimInstance -ClassName Win32_DeviceGuard -Namespace root\Microsoft\Windows\DeviceGuard).SecurityServicesRunning should contain 1; msinfo32 should list "Credential Guard" under Virtualization-based Security Services Running; the System event log should show WinInit Event 13. Deploy via Intune Settings Catalog or GPO with "Enabled without lock". Inventory NTLMv1, MS-CHAPv2, Digest, CredSSP, and non-Microsoft SSP usage before enabling, because those are the protocols that will lose SSO under Credential Guard.
Lab-only: how to verify Credential Guard is currently running
On a Credential-Guard-on box, the following one-liner returns True:
(Get-CimInstance -ClassName Win32_DeviceGuard -Namespace root\Microsoft\Windows\DeviceGuard).SecurityServicesRunning -contains 1The 1 corresponds to Credential Guard in the SecurityServicesRunning bitmask. Pair with the System event log filter EventID=13, Source=Wininit to confirm the boot-time launch event. Use these to verify, not Task Manager: Microsoft explicitly disrecommends the Task Manager check.
For a security researcher
The verifiable trustlet artefacts are: the .tpolicy PE section in LsaIso.exe; the s_IumPolicyMetadata export; the dual-EKU signature with the IUM EKU 1.3.6.1.4.1.311.10.3.37 visible in the certificate chain. The IUM-side enumeration approach is NtQuerySystemInformation with the SystemIsolatedUserModeInformation class. Quarkslab's IUM-debugging walkthrough documents the nested-virt setup (VMware L1 + Hyper-V L2), the GDB-stub attach on hvix64.exe, the patch on SecureKernel!SkpsIsProcessDebuggingEnabled to force-return 1, and the walk to SecureKernel.exe from HvCallVtlReturn at hypercall ID 0x12. Lyak's PassTheChallenge methodology is the canonical worked example for the agent-side trustlet RPC interaction.
For a red-team operator
Assume the long-term hash and TGT are not in lsass.exe. Assume the trustlet's RPC output is. The 2026 LPE / credential playbook focuses on credential use (Kerberoast against weak service-account passwords; AS-REP Roast against accounts with DONT_REQ_PREAUTH; RBCD via KrbRelayUp; AD CS misconfigurations -- the ESC1-ESC11 enumeration), token impersonation (the PrintSpoofer / Potato chain), and supplied-credential capture (keylogger on the prompt path). The companion NTLMless article in this series covers the protocol-removal frontier that closes the Pass-the-Challenge NTLMv1 leg specifically.
For a detection engineer
WinInit Events 15, 16, and 17 ("Credential Guard configured but did not run") are a high-fidelity "attacker disabled Credential Guard" detection -- if the box is supposed to be Credential-Guard-on and the boot-time event logs show one of those IDs, something blocked the trustlet from launching. ETW Microsoft-Antimalware-Engine plus AMSI on lsass.exe security-package load is the high-fidelity detection surface for Pass-the-Challenge-style injection (the attacker has to load a security-package DLL into lsass.exe to get the established ALPC channel). On the network side, a crack.sh submission carrying the static 1122334455667788 challenge is an indicator of Pass-the-Challenge cracking activity by an internal user.
Three misconceptions about Credential Guard get asked in every defensive-architecture review. The FAQ that follows resolves them, with primary citations for each answer.
11. Frequently asked questions
These are the seven questions that come up in every Credential Guard architectural review. Each answer is grounded in a primary source.
Credential Guard frequently asked questions
Credential Guard means credentials are unstealable, right?
No. The long-lived NTLM hash and the Kerberos long-term key are unstealable from VTL0 memory; the per-session Kerberos service tickets are not protected, though the TGT is. Pass-the-Ticket on the agent recovers the current session's tickets even on a Credential-Guard-on box. The architectural pivot is "long-lived secret out of the agent's memory," not "no secret in the agent's memory."
Can Mimikatz still dump LSASS on a Credential-Guard system?
Yes. The dump succeeds; the contents are different. Where the NT hash field used to hold the bytes of the hash, the field now holds the literal string [LSA Isolated Data] followed by an opaque ciphertext, with embedded Context Handle, Proxy Info, and DPAPI GUID fields. The encrypted blob is AES-GCM-wrapped by the trustlet under a key the agent does not hold. The dump is a statement of architecture, not a statement of failure.
Does Credential Guard stop Kerberoasting?
No. Kerberoasting cracks the service account's NT hash from a TGS-REP delivered over the wire by the KDC. No memory of the Credential-Guard-protected box is ever read. The mitigation for Kerberoasting is strong service-account passwords (or moving to managed service accounts with auto-rotated 240-character passwords), not Credential Guard.
Does Credential Guard stop SeImpersonatePrivilege Potato attacks?
No. The Potato chain (Hot, Rotten, Juicy, PrintSpoofer, RoguePotato, GodPotato) escalates from a service user with SeImpersonatePrivilege to NT AUTHORITY\SYSTEM by impersonating a coerced inbound SYSTEM authentication. The chain operates on tokens, not credentials. Credential Guard protects credentials.
Does Credential Guard protect domain controllers?
No, by design. Microsoft documents the carve-out verbatim: "Enabling Credential Guard on domain controllers isn't recommended. Credential Guard doesn't provide any added security to domain controllers, and can cause application compatibility issues on domain controllers." The most-attacked LSASS on the network -- on the domain controller, holding NTDS.dit and the krbtgt long-term key -- is explicitly out of scope. The mitigations for DC LSASS are physical and procedural: dedicated Tier-0 Privileged Access Workstations, no general-purpose interactive logon, and the Mitigating Pass-the-Hash v2 playbook.
Is Credential Guard the same as LSA Protection (RunAsPPL)?
No. PPL is kernel-enforced inside the NT TCB; Credential Guard is a VTL1 trustlet outside it. itm4n's writeup is explicit: "LSA Protection tends to be confused with Credential Guard, which is completely different ... Credential Guard and LSA Protection are actually complementary." Both should be enabled. PPL raises the bar for opportunistic attackers; Credential Guard moves the secret across a TCB boundary that an NT-kernel-mode attacker cannot cross.
Why does my SSO break after I enable Credential Guard?
Because the application chains through a protocol that cannot use Credential-Guard-protected credentials. "When Credential Guard is enabled, NTLMv1, MS-CHAPv2, Digest, and CredSSP can't use the signed-in credentials"; third-party SSPs that depend on KerbQuerySupplementalCredentialsMessage simply break under Credential Guard. The remediation is to migrate the application to a supported protocol (Kerberos with AES, certificate-based EAP-TLS / PEAP-TLS, or Hello-for-Business per-application keys).
The empty hash from §1 is, in 2026, a property of every domain-joined Windows 11 22H2+ box on the planet. Eleven years of lsass.exe extraction history made the architectural pivot inevitable; eight years of trustlet maturation have made the pivot the default. What remains -- the use surface, the protocol surface, the token surface, the typed-credential surface, the third-party-SSP surface -- is the next eleven years of work.
Study guide
Key terms
- lsass.exe
- The user-mode Windows service that handles authentication and (until Credential Guard) held every long-lived credential in process memory. The agent in the agent / trustlet split.
- LsaIso.exe
- The Credential Guard trustlet (Trustlet ID 1) running in VTL1, holding the NTOWF and Kerberos long-term keys behind a hypervisor boundary.
- NTOWF
- The MD4 of the UTF-16-LE password. Functionally equivalent to the password for any NTLM-speaking service; the canonical Pass-the-Hash credential.
- Pass-the-Hash
- An attack class in which the client proves possession of the NTOWF without knowing the cleartext password. Originally published by Paul Ashton in 1997.
- Pass-the-Challenge
- Lyak's December 2022 attack class against Credential Guard: inject into lsass.exe, call NtlmIumCalculateNtResponse against the static challenge 1122334455667788, submit to crack.sh, recover the NT hash in ~30 seconds.
- PPL (Protected Process Light)
- A signer-level NT-kernel-enforced isolation mechanism that prevents non-PPL callers from opening lsass.exe for memory read. Bypassable from kernel via mimidrv.sys and from userland (on legacy Windows) via PPLdump.
- Trustlet
- A Microsoft-signed binary loaded by the Secure Kernel into VTL1 user mode at boot. Identified by Trustlet ID; constrained by Signature Level 12 and the dual-EKU (WSCV + IUM) signature.
- VTL0 / VTL1
- Virtual Trust Levels enforced by the Hyper-V hypervisor. VTL0 = Normal World (NT kernel + user-mode); VTL1 = Secure World (Secure Kernel + IUM trustlets).
- IUM (Isolated User Mode)
- The Ring-3 user mode component of VTL1; the address space in which trustlets execute.
- ALPC
- Advanced Local Procedure Call: the Windows IPC primitive used to carry the LSA_ISO_RPC_SERVER channel between lsass.exe in VTL0 and LsaIso.exe in VTL1.
- Kerberoasting
- An attack on Kerberos service-account passwords by requesting TGS-REP tickets for arbitrary SPNs and cracking the etype-23 RC4-encrypted portion offline. Disclosed by Tim Medin at DerbyCon 4 (September 2014).
- RBCD (Resource-Based Constrained Delegation)
- A Kerberos delegation feature abused via the msDS-AllowedToActOnBehalfOfOtherIdentity LDAP attribute to mint service tickets as any user against a target. Refined by Forshaw 2022; weaponised in KrbRelayUp.
- SeImpersonatePrivilege
- The Windows token privilege held by service accounts that allows ImpersonateLoggedOnUser. The basis of the entire Potato escalation family.
- DPAPI
- The Windows per-user secret-protection API. The DPAPI GUID in the [LSA Isolated Data] block ties the trustlet record to the on-disk per-user master-key chain.
- VSM master key
- A symmetric key generated and stored only in VTL1, sealed by the TPM under PCR-bound policy, that wraps any persistent state the trustlets need to survive reboots.
Comprehension questions
Why did Microsoft conclude in 2014 that no patch could fix the LSASS-extraction class?
Because the secret is in a process whose memory is governed by the same NT kernel an attacker with administrator can subvert. Generations 0-4 add layers (PPL, WDigest disable, Protected Users, Tier-0 isolation) inside the NT-kernel TCB; only changing the TCB (moving the secret to a kernel the attacker cannot reach) addresses the structural problem.
Distinguish LSA Protection (RunAsPPL) from Credential Guard.
PPL is NT-kernel-enforced; the same kernel an attacker is trying to subvert. Credential Guard is hypervisor-enforced; the secret moves to a separate kernel (the Secure Kernel / VTL1) the NT-kernel attacker cannot cross. They are complementary, not substitutes.
What is in the encrypted blob field of a Pypykatz [LSA Isolated Data] dump on a Credential-Guard-on box?
An AES-GCM-wrapped serialised record containing (among other fields) the NTOWF, with a length-prefixed header (verbatim hex prefix a000000000000000080000006400000001000000010100000100000036) and an embedded ASCII tag 4e746c6d48617368 = NtlmHash that names the wrapped field. The wrap key is held only in VTL1 by LsaIso.exe.
Walk the Pass-the-Challenge attack flow end to end.
Inject SecurityPackage.dll into lsass.exe; extract Context Handle from the Pypykatz dump; call NtlmIumCalculateNtResponse over the established ALPC channel with the static challenge 1122334455667788; receive the trustlet-computed NTLMv1 response; submit to crack.sh; receive the NT hash in approximately 30 seconds. The trustlet is faithful; the agent's request is the attack surface.
Why is Pass-the-Challenge a class property of the agent / trustlet split rather than a Microsoft bug?
If lsass.exe could not call the trustlet, the trustlet would be useless (no path from wire challenge to response). If lsass.exe can call the trustlet, an attacker who compromises lsass.exe inherits the channel. Closing the gap structurally requires moving protocol code into the trustlet, which would dramatically expand the trustlet TCB and is not on Microsoft's roadmap.
Name three things Credential Guard explicitly does not protect.
Domain controllers (NTDS.dit, krbtgt long-term key); credential use without theft (Kerberoasting, AS-REP Roasting, RBCD); SeImpersonatePrivilege Potato chain (token, not credential); plaintext-secret protocols (NTLMv1, MS-CHAPv2, Digest, CredSSP); out-of-LSA storage (web credentials, non-Microsoft SSPs, Remote Desktop Gateway prompt path).
Why was default-on Credential Guard shipped without UEFI Lock?
To allow administrators to disable the feature remotely if a third-party SSP or MS-CHAPv2-dependent workflow breaks. The trade-off is that an attacker who has already obtained the privilege required to flip the registry value can also disable Credential Guard. Microsoft chose the operational reality of remote-disable convenience over the in-principle attacker-disable hardening.
---WRITER METRICS---
Word count: 12306
Citations: 131
Mermaid diagrams: 7
Definitions: 16
Sidenotes: 8
FAQ questions: 7
---END WRITER METRICS--- References
- Credential Guard overview. https://learn.microsoft.com/en-us/windows/security/identity-protection/credential-guard/ ↩
- How Credential Guard works. https://learn.microsoft.com/en-us/windows/security/identity-protection/credential-guard/how-it-works ↩
- Configure Credential Guard. https://learn.microsoft.com/en-us/windows/security/identity-protection/credential-guard/configure ↩
- Credential Guard considerations and known issues. https://learn.microsoft.com/en-us/windows/security/identity-protection/credential-guard/considerations-known-issues ↩
- Configuring additional LSA protection. https://learn.microsoft.com/en-us/windows-server/security/credentials-protection-and-management/configuring-additional-lsa-protection ↩
- Protected Users security group. https://learn.microsoft.com/en-us/windows-server/security/credentials-protection-and-management/protected-users-security-group ↩
- Virtual Secure Mode (TLFS). https://learn.microsoft.com/en-us/virtualization/hyper-v-on-windows/tlfs/vsm ↩
- LSA Authentication. https://learn.microsoft.com/en-us/windows/win32/secauthn/lsa-authentication ↩
- Microsoft Security Advisory: Update to improve credentials protection and management (May 13, 2014). https://support.microsoft.com/en-us/topic/microsoft-security-advisory-update-to-improve-credentials-protection-and-management-may-13-2014-93434251-04ac-b7f3-52aa-9f951c14b649 ↩
- Windows Hello for Business overview. https://learn.microsoft.com/en-us/windows/security/identity-protection/hello-for-business/ ↩
- Brad Anderson, Microsoft Ignite 2015 keynote (May 4, 2015). https://news.microsoft.com/speeches/brad-anderson-ignite-2015/ ↩
- Microsoft Ignite: The day-one wrap-up (Wayback Machine snapshot, February 2025). https://web.archive.org/web/2025/https://www.itprotoday.com/unified-communications/microsoft-ignite-the-day-one-wrap-up ↩
- How Mimikatz became the go-to hacker tool. https://www.wired.com/story/how-mimikatz-became-go-to-hacker-tool/ ↩
- gentilkiwi/mimikatz. https://github.com/gentilkiwi/mimikatz ↩
- SMBRelay (Cult of the Dead Cow). https://www.cultdeadcow.com/tools/smbrelay.html ↩
- Do You Really Know About LSA Protection (RunAsPPL)?. https://itm4n.github.io/lsass-runasppl/ ↩
- The End of PPLdump. https://itm4n.github.io/the-end-of-ppldump/ ↩
- itm4n/PPLdump. https://github.com/itm4n/PPLdump ↩
- Bypassing LSA protection in userland. https://blog.scrt.ch/2021/04/22/bypassing-lsa-protection-in-userland/ ↩
- Battle of SKM and IUM: How Windows 10 Rewrites OS Architecture. https://github.com/tpn/pdfs/blob/master/Battle%20of%20SKM%20and%20IUM%20-%20How%20Windows%2010%20Rewrites%20OS%20Architecture%20-%20Alex%20Ionescu%20-%202015%20%28blackhat2015%29.pdf ↩
- Pass-the-Challenge: Defeating Credential Guard (Wayback). https://web.archive.org/web/20240203005631/https://research.ifcr.dk/pass-the-challenge-defeating-credential-guard-31a892eee22 ↩
- ly4k/PassTheChallenge. https://github.com/ly4k/PassTheChallenge ↩
- ly4k/Pypykatz (LSA Isolated Data fork). https://github.com/ly4k/Pypykatz ↩
- Debugging Windows Isolated User Mode (IUM) Processes. https://blog.quarkslab.com/debugging-windows-isolated-user-mode-ium-processes.html ↩
- Attacking Microsoft Kerberos: Kicking the Guard Dog of Hades (Tim Medin, DerbyCon 4). https://www.irongeek.com/i.php?page=videos/derbycon4/t120-attacking-microsoft-kerberos-kicking-the-guard-dog-of-hades-tim-medin ↩
- MITRE ATT&CK T1558.003 -- Kerberoasting. https://attack.mitre.org/techniques/T1558/003/ ↩
- MITRE ATT&CK T1558.004 -- AS-REP Roasting. https://attack.mitre.org/techniques/T1558/004/ ↩
- Exploiting RBCD using a normal user. https://www.tiraniddo.dev/2022/05/exploiting-rbcd-using-normal-user.html ↩
- Wagging the Dog: Abusing Resource-Based Constrained Delegation. https://shenaniganslabs.io/2019/01/28/Wagging-the-Dog.html ↩
- Dec0ne/KrbRelayUp. https://github.com/Dec0ne/KrbRelayUp ↩
- Hot Potato. https://foxglovesecurity.com/2016/01/16/hot-potato/ ↩
- Rotten Potato: Privilege Escalation From Service Accounts To SYSTEM. https://foxglovesecurity.com/2016/09/26/rotten-potato-privilege-escalation-from-service-accounts-to-system/ ↩
- ohpe/juicy-potato. https://github.com/ohpe/juicy-potato ↩
- PrintSpoofer: Abusing Impersonation Privileges on Windows 10 and Server 2019. https://itm4n.github.io/printspoofer-abusing-impersonate-privileges/ ↩
- Pass the hash (Wikipedia). https://en.wikipedia.org/wiki/Pass_the_hash ↩
- Mimikatz (Wikipedia). https://en.wikipedia.org/wiki/Mimikatz ↩
- DigiNotar (Wikipedia). https://en.wikipedia.org/wiki/DigiNotar ↩
- NTLMless: The Death of NTLM in Windows. https://paragmali.com/blog/ntlmless-the-death-of-ntlm-in-windows ↩
- The TPM in Windows: One primitive, twenty-five years, and the case for layered trust. https://paragmali.com/blog/the-tpm-in-windows-one-primitive-twenty-five-years-and-the-c ↩
- SSP Packages Provided by Microsoft. https://learn.microsoft.com/en-us/windows/win32/secauthn/ssp-packages-provided-by-microsoft ↩
- What's new in Windows Server 2016. https://learn.microsoft.com/en-us/windows-server/get-started/whats-new-in-windows-server-2016 ↩
- Microsoft Defender for Identity overview. https://learn.microsoft.com/en-us/defender-for-identity/ ↩
- What is a Primary Refresh Token?. https://learn.microsoft.com/en-us/entra/identity/devices/concept-primary-refresh-token ↩
- Antimalware Scan Interface (AMSI). https://learn.microsoft.com/en-us/windows/win32/amsi/antimalware-scan-interface-portal ↩
- The Secure Enclave (Apple Platform Security). https://support.apple.com/guide/security/secure-enclave-sec59b0b31ff/web ↩
- sssd-kcm(8) -- SSSD Kerberos Cache Manager. https://man.archlinux.org/man/sssd-kcm.8.en ↩
- Protecting Cached User Data (ChromiumOS design doc). https://www.chromium.org/chromium-os/chromiumos-design-docs/protecting-cached-user-data/ ↩
- Windows 8.1 (Wikipedia). https://en.wikipedia.org/wiki/Windows_8.1 ↩
- Windows Server 2012 R2 (Wikipedia). https://en.wikipedia.org/wiki/Windows_Server_2012_R2 ↩