# NTLMless: The Death of NTLM in Windows

> Thirty years of pass-the-hash, NTLM relay, PetitPotam, and ESC8 -- and the Kerberos engineering that finally lets Microsoft turn NTLM off by default.

*Published: 2026-05-10*
*Canonical: https://paragmali.com/blog/ntlmless-the-death-of-ntlm-in-windows*
*License: CC BY 4.0 - https://creativecommons.org/licenses/by/4.0/*

---
<TLDR>
**NTLM is the 30-year-old fallback authentication protocol that Active Directory still rests on whenever Kerberos cannot do the job -- and every consequential modern AD attack (pass-the-hash, NTLM relay, PetitPotam, ESC8) lives in that fallback path.** Microsoft's exit plan (IAKerb, Local KDC, NEGOEX, the Negotiate-everywhere refactor) closes the four reasons NTLM survived, and the January 2026 roadmap names "disabled by default in the next major Windows release" as Phase 3. This article tells the whole arc as one story: how NTLM works on the wire, every attack class against it, exactly what is being removed -- and what is not.
</TLDR>

## 1. Eight Minutes

A defender has done every retrofit Microsoft has shipped over twenty years. SMB signing enforced on every member server. EPA enabled on every IIS endpoint. [Credential Guard](https://paragmali.com/blog/when-system-isnt-enough-the-windows-secure-kernel-and-the-en/) on. Restrict NTLM in audit mode. KB 5005413 applied to AD CS. An attacker with no credentials joins their network, runs `Coercer` against a domain controller, and a handful of seconds later holds a Kerberos ticket-granting ticket for the Domain Admin account [@gh-coercer, @specterops-cert-preowned-blog]. Total elapsed time: less than the time it took you to read this paragraph. Total prerequisites for the chain: that NTLM still exists as a fallback path on Windows.

The chain has a name. ESC8, from Will Schroeder and Lee Christensen's "Certified Pre-Owned" whitepaper, published June 17, 2021 [@specterops-cert-preowned-blog, @specterops-cert-preowned-pdf]. Its coercion primitive has another name. PetitPotam, from Lionel Gilles, published the next month [@gh-petitpotam, @nvd-cve-2021-36942]. Together they take a fully retrofitted Active Directory environment to Domain Admin in four steps.

> **Note:** 1. **Coerce.** Call `EfsRpcOpenFileRaw` against any Windows server -- including a DC -- over LSARPC. The service, running as SYSTEM, NTLM-authenticates back to an attacker-controlled UNC path. No credentials required [@gh-petitpotam, @nvd-cve-2021-36942]. 2. **Relay.** `ntlmrelayx.py` from Impacket sits on the listening side and forwards the live NTLM exchange to the AD CS Web Enrollment endpoint at `/certsrv/certfnsh.asp` [@gh-impacket]. 3. **Enroll.** The relayed authentication enrolls the DC's machine account for a client certificate against the `Machine` template (or any default-enabled template that allows enrollment) [@specterops-cert-preowned-pdf]. 4. **Forge.** The attacker uses the certificate to perform PKINIT against the KDC, obtains a TGT for the DC's machine account, and then asks for any service ticket they want -- including the krbtgt account. Domain Admin in under ten minutes [@specterops-cert-preowned-blog].

Pause on what is and is not true here. SMB signing did not fail; SMB signing was not in the chain. EPA failed because it was deployed on IIS authentication endpoints generally but the `/certsrv/` deployment lagged [@ms-kb5005413]. Credential Guard did not fail; Credential Guard protects the NT-hash, and the attacker never touched a hash. Restrict NTLM in audit mode worked exactly as labelled: it audited.

The retrofits are not wrong. They patch the named primitives. The chain exploits the *existence* of the fallback path, not a primitive. Every protective control is honest about what it does and silent about what it does not.

<Mermaid caption="The ESC8 + PetitPotam chain in four steps. The attacker has no credentials at step 1 and holds a Domain Admin Kerberos TGT at step 4.">
sequenceDiagram
    autonumber
    actor A as Attacker (no creds)
    participant DC as Domain Controller
    participant R as ntlmrelayx listener
    participant CA as AD CS /certsrv/
    participant KDC as KDC (PKINIT)
    A->>DC: EfsRpcOpenFileRaw(UNC=\\attacker\share)
    DC->>R: NTLM AUTHENTICATE (SYSTEM = DC$ machine account)
    R->>CA: Relay NTLM, enroll Machine cert as DC$
    CA-->>R: Client certificate for DC$
    R->>KDC: PKINIT AS-REQ with DC$ cert
    KDC-->>A: TGT for DC$ -> request service tickets at will
</Mermaid>

This is the question that drives the rest of the article: *how did Windows arrive at a state where the most catastrophic modern Active Directory attack chain depends on a thirty-year-old fallback nobody wants?*

## 2. Origins: Why NTLM Existed at All

Rewind to 1987. IBM and Microsoft ship LAN Manager 1.0 for OS/2. PCs are still mostly file-and-print islands on Token Ring or 10BASE-2 coax; networking exists, but "domain" is a word for what a single server controls. LAN Manager needs an authentication scheme that can run on hardware with 640 KB of RAM, no DES export licence, and roughly zero institutional knowledge about cryptography. What it produces, the LM hash, is a near-perfect snapshot of every constraint and assumption of its moment [@wp-lan-manager].

The construction is short enough to write out. Take the password. Uppercase it. Pad or truncate to exactly fourteen ASCII characters. Split into two seven-byte halves. Convert each half into a 56-bit DES key (the eighth bit of each byte is a parity bit). Use each key to DES-encrypt the eight-byte constant `KGS!@#$%`. Concatenate the two eight-byte ciphertexts. That is the LM hash [@wp-lan-manager, @wp-nt-lan-manager].

<Definition term="LM hash">
The LAN Manager password hash from 1987. Constructed by uppercasing the password, truncating or padding to 14 characters, splitting into two 7-byte halves, and DES-encrypting the constant `KGS!@#$%` with each half as a key. The two halves are independent, the password is case-insensitive, and there is no salt. Every property of this construction enables an attack class that survives into NTLMv2 [@wp-lan-manager].
</Definition>

<Sidenote>The eight-byte constant `KGS!@#$%` is what you get when somebody types "KGS" and then mashes shift-1, shift-2, shift-3, shift-4, shift-5 on a 1980s American IBM keyboard. The constant is in the protocol because the protocol predates the cryptographic-engineering norm that constants should look random. It would not survive a 2026 design review; in 1987 nobody asked.</Sidenote>

Every choice tells a story about 1987. Uppercase, because some clients normalised case anyway and the developers wanted authentication to "just work" across mixed locale settings. Fourteen characters, because that was the field width DOS dictated. Two halves, because a 56-bit DES key already maxed out the practical computation; nobody was going to chain two DES operations through a feedback function with that much per-keystroke latency. No salt, because the deployment model was one server, one user database, and identical-password collisions were a feature for the help desk, not a leak.

The result is password-equivalent: anyone who possesses the LM hash *is* the user, forever, regardless of how the wire protocol presents the credential.

Six years later, July 27, 1993, Windows NT 3.1 ships. NTLM(v1) arrives with it [@wp-nt-lan-manager]. The NT-hash is what you would design if you started over with mid-1990s assumptions but were not yet willing to abandon DES at the response layer. It is simpler than the LM hash and stronger in exactly one place: `NT-hash = MD4(UTF-16LE(password))` [@ms-microsoft-ntlm, @wp-nt-lan-manager]. No truncation. No case folding. Sixteen bytes of output. The hash is still password-equivalent; what changes is that the *input* to the hash is now whatever Unicode string the user typed, in full.

The wire protocol around the NT-hash is the famous three-message handshake. NEGOTIATE from the client. CHALLENGE from the server (an eight-byte random nonce). AUTHENTICATE from the client, carrying a DES-based response computed from the NT-hash and the server challenge. The whole exchange is self-contained: nothing in the three messages binds the authentication to a particular transport, a particular client, a particular server, or a particular service [@ms-nlmp]. That property -- the absence of *binding* -- is the property NTLM relay will eat for the next twenty-five years.

<Definition term="NT-hash">
`MD4(UTF-16LE(password))`. Sixteen bytes. The single long-term secret that every NTLM authentication ever performed for a given user derives from. Possession of the NT-hash is mathematically equivalent to possession of the password for every authentication purpose. NTLMv2 changes the response computation but not the hash [@ms-microsoft-ntlm, @wp-nt-lan-manager].
</Definition>

<Mermaid caption="Thirty years of NTLM, from LAN Manager (1987) through Kerberos default (Windows 2000) and the retrofit cadence to the announced Phase 3 disablement in the next major Windows release.">
timeline
    title NTLM and Windows authentication, 1987-2027
    1987 : LAN Manager 1.0 ships : LM hash construction
    1993 : Windows NT 3.1 : NTLMv1 + NT-hash MD4(UTF-16LE(pwd))
    1998 : NT 4.0 SP4 : NTLMv2 with HMAC-MD5 and AV_PAIRS
    2000 : Windows 2000 : Kerberos is the default; NTLM demoted to fallback
    2008 : MS08-068 patches SMB self-relay (CVE-2008-4037)
    2015 : Windows 10 RTM ships Credential Guard
    2019 : CVE-2019-1040 Drop the MIC (Simakov/Zinar)
    2021 : PetitPotam (Gilles) + ESC8 (Schroeder/Christensen)
    2023 : Palko commits to removing NTLM (October 11)
    2024 : NTLM marked deprecated (June); NTLMv1 removed in 24H2/Server 2025
    2025 : KB 5064479 enhanced NTLM auditing
    2026 : Phase 1 (audit) + IAKerb/Local KDC pre-release (Phase 2)
    2027 : Phase 3 -- NTLM disabled by default (next major Windows release)
</Mermaid>

The third revision arrives with NT 4.0 Service Pack 4, October 1998. NTLMv2 throws away DES at the response layer and replaces it with HMAC-MD5. It introduces a *client* challenge (so the response is no longer purely a function of the server's choice). It introduces AV_PAIRS, a small TLV structure carrying the target name, a timestamp, and -- in much later retrofits -- the channel binding hash and message integrity field [@ms-nlmp, @wp-nt-lan-manager]. NTLMv2 defeats pre-computation attacks against the response. It does not change the long-term secret. The NT-hash is still the NT-hash; possession is still authority.

<Sidenote>An intermediate variant, NTLM2 Session Security, shipped in NT 4.0 SP4 alongside NTLMv2 and is the dead end most often confused for v2. It added an 8-byte client challenge to the NTLMv1 DES envelope without touching the long-term hash, hoping to defeat pre-computation while preserving wire compatibility. It survived only as a transitional `LMCompatibilityLevel` setting; nothing in the modern attack catalogue treats NTLM2 SS as a distinct target [@ms-nlmp, @ms-lan-mgr-auth-level].</Sidenote>

| Property | LM hash (1987) | NTLMv1 (1993) | NTLMv2 (1998) |
|---|---|---|---|
| Hash function for the long-term secret | DES of constant with password halves | MD4(UTF-16LE(password)) | MD4(UTF-16LE(password)) |
| Case-sensitive | No (uppercase only) | Yes | Yes |
| Max input length | 14 characters (truncated) | Unlimited Unicode | Unlimited Unicode |
| Salted | No | No | Per-exchange client challenge + timestamp |
| Response keyed MAC | DES (3 keys, 56-bit each) | DES (3 keys, 56-bit each) | HMAC-MD5 |
| Binds to target server name | No | No | AV_PAIR `MsvAvTargetName` (retrofit) |
| Binds to TLS endpoint | No | No | AV_PAIR `MsvAvChannelBindings` (retrofit) |
| Possession of hash = authority | Yes | Yes | Yes |

<Definition term="NTLMv1 / NTLMv2">
The two production response constructions on top of the same NT-hash. NTLMv1 chains three 56-bit DES operations across `K1 = NT-hash[0:7]`, `K2 = NT-hash[7:14]`, `K3 = NT-hash[14:16] || \x00\x00\x00\x00\x00`, encrypting the eight-byte server challenge under each. The third sub-key has only 16 bits of real entropy. NTLMv2 replaces all three DES operations with one HMAC-MD5 over `server_challenge || client_challenge || timestamp || av_pairs`, keyed by `NTOWFv2 = HMAC_MD5(NT-hash, UNICODE(Upper(user) || domain))` [@ms-nlmp, @wp-nt-lan-manager].
</Definition>

Then comes Windows 2000, and Kerberos. Microsoft's plan was simple: in a domain, Kerberos handles everything; NTLM stays around as a compatibility blanket for the cases Kerberos cannot cover yet [@microsoft-ntlm-overview]. The trouble was that "the cases Kerberos cannot cover yet" turned out to be a permanent set, not a transitional one. Twenty-three years later, the same four cases would be the table-of-contents of Microsoft's NTLM-removal plan [@palko-2023-evolution]:

1. **No domain-controller line-of-sight.** A laptop on a hotel Wi-Fi authenticating to a corporate file share through a VPN tunnel terminator has no Kerberos KDC to talk to. NTLM does not need one.
2. **Local accounts.** A user signing into a workgroup machine or a domain-joined machine's local SAM has no domain at all; Kerberos has nothing to authenticate against.
3. **No service principal name.** Kerberos requires a known SPN for the target service. Connect to a server by raw IP, by an alias DNS name not yet in the SPN database, or by a CNAME the operator forgot to register -- there is no SPN, so Kerberos cannot run.
4. **Hard-coded NTLM.** Application code that calls `AcquireCredentialsHandleW(..., "Ntlm", ...)` or RPC code that asks for `RPC_C_AUTHN_WINNT` directly bypasses the negotiator and forces NTLM regardless of what is available.

<Definition term="SPNEGO / Negotiate">
The Simple and Protected GSS-API Negotiation Mechanism. When two parties want to authenticate but do not know which security mechanism they share, SPNEGO offers a list and picks the best one both support. On Windows the SSPI provider is called `Negotiate`, and it has historically chosen Kerberos when possible and NTLM otherwise [@ms-microsoft-ntlm, @microsoft-ntlm-overview]. The "otherwise" path is where every modern NTLM attack lives.
</Definition>

Each fallback case is one shutter through which NTLM continues to leak into a Kerberos-by-default world. *The demotion was supposed to be terminal. Why did the four fallback cases turn out to cover most of the real-world authentication surface, and what does that look like on the wire?*

## 3. The Wire: Three Messages and One Hash

Most defenders have never read an NTLM authentication off the wire. The cryptography is short enough to fit on one screen, and the structural property that drives the next 28 years of attacks is visible inside those three messages. The point of this section is to make that property impossible to miss.

### NEGOTIATE, CHALLENGE, AUTHENTICATE

The client opens with `NEGOTIATE`, advertising its capability flags: which signing modes it supports, whether it is willing to do session security, whether it is asking for extended session keys, and so on. The server replies with `CHALLENGE`. The body of `CHALLENGE` contains a single 64-bit nonce (the server challenge) and a TLV blob called `TargetInfo`: a list of attribute-value pairs the server wants to bind into the authentication [@ms-nlmp].

The client computes its response and sends `AUTHENTICATE`. That message contains the user name, the workstation name, the response itself, the AV_PAIRS the client wants to echo back, a Message Integrity Code field (HMAC-MD5 of the concatenation of all three NTLM messages), and -- in EPA-enforced deployments -- a hash of the TLS endpoint certificate placed in the `MsvAvChannelBindings` AV_PAIR [@ms-nlmp, @ms-epa-wcf].

<Mermaid caption="The three-message NTLMv2 exchange. The NTProofStr is a deterministic function of the NT-hash plus values both parties already share or send in the clear.">
sequenceDiagram
    autonumber
    participant C as Client
    participant S as Server
    C->>S: NEGOTIATE (capability flags)
    S->>C: CHALLENGE (server nonce 8B, TargetInfo AV_PAIRS)
    Note over C: NTOWFv2 = HMAC_MD5(NT-hash, UNICODE(Upper(user) plus domain))
    Note over C: NTProofStr = HMAC_MD5(NTOWFv2, ServerChallenge plus temp) where temp = version plus Z(6) plus Time plus ClientChallenge plus Z(4) plus ServerName plus Z(4)
    C->>S: AUTHENTICATE (user, NTProofStr, temp, MIC, CBT)
    Note over S: Server replays the same HMAC_MD5 with its copy of the NT-hash to verify
</Mermaid>

### The NTLMv2 response, verbatim

`[MS-NLMP]` §3.3.2 gives the response algorithm in three lines of pseudocode [@ms-nlmp]:

$$\text{NTOWFv2} = \text{HMAC-MD5}\big(\text{NT-hash},\ \text{UNICODE}(\text{Upper(user)} \mathbin{\|} \text{domain})\big)$$

$$\text{temp} = \text{Responserversion} \mathbin{\|} \text{HiResponserversion} \mathbin{\|} Z(6) \mathbin{\|} \text{Time} \mathbin{\|} \text{ClientChallenge} \mathbin{\|} Z(4) \mathbin{\|} \text{ServerName} \mathbin{\|} Z(4)$$

$$\text{NTProofStr} = \text{HMAC-MD5}\big(\text{NTOWFv2},\ \text{ServerChallenge} \mathbin{\|} \text{temp}\big)$$

The `temp` byte string carries two version bytes, six zero bytes, the 8-byte FILETIME, the 8-byte client challenge, four zero bytes, the AV_PAIR list the spec calls `ServerName`, and a final four zero bytes. The client sends `NTProofStr || temp` as the response. The server, which holds its own copy of `NT-hash` for the user (cached or fetched from the domain controller), recomputes the same three lines and checks equality. That is the entire response protocol.

Notice what `NTOWFv2` is. It is a function of two inputs: the NT-hash, and a normalised user/domain string. Both inputs are static once the user logs in. *Knowing the NT-hash is sufficient to compute every NTLMv2 response forever, against every server, for every challenge, until the password changes* [@wp-pass-the-hash, @ms-microsoft-ntlm].

<Sidenote>Why is HMAC-MD5 considered fine for the response side but considered weak for the *key* side? The response side is being asked: given a known key, can a verifier check a freshly computed tag? HMAC-MD5 still answers that without a known break. The key side is being asked: given a stolen 16-byte value, how hard is it to mount a precomputation attack on candidate passwords? MD4 of UTF-16LE is so cheap on modern GPUs that an 8-character password is in the minutes-to-hours range. Hashcat lists NetNTLMv2 (mode 5600) as the practical attack format and benchmarks NTLM cracking accordingly [@hashcat-wiki, @gh-hashcat].</Sidenote>

### AV_PAIRS, MIC, and channel binding -- retrofits all the way down

AV_PAIRS is a TLV structure. The server places target NetBIOS, target DNS, a timestamp, and various flags into the `TargetInfo` of `CHALLENGE`. The client echoes the structure into `AUTHENTICATE` and adds two retrofit fields when both ends agree to use them [@ms-nlmp]:

- **`MsvAvFlags`** is a bit field signalling that the client has computed a MIC and is therefore willing to bind all three NTLM messages together.
- **`MsvAvChannelBindings`** holds a hash of the server's TLS endpoint certificate when the authentication is happening over an HTTPS-style transport that the client can see. This is the Extended Protection for Authentication (EPA) channel-binding-token mechanism [@ms-epa-wcf].

The MIC field itself is added to `AUTHENTICATE`. It is `HMAC_MD5(ExportedSessionKey, NEGOTIATE || CHALLENGE || AUTHENTICATE)`. `ExportedSessionKey` coincides with `SessionBaseKey` in the common case; when `NTLMSSP_NEGOTIATE_KEY_EXCH` is set, the client generates a random session key, encrypts it under `KeyExchangeKey`, and `ExportedSessionKey` is the random key. The MIC always uses `ExportedSessionKey`, and it is intended to make tampering with any of the three messages detectable [@ms-nlmp].

<Definition term="AV_PAIRS">
A length-prefixed TLV list carried inside the `TargetInfo` byte string of NTLM `CHALLENGE` and the AV-list byte string of `AUTHENTICATE`. AV_PAIRS hold the target server names, a timestamp, the `MsvAvFlags`, the `MsvAvChannelBindings` (EPA), and the optional `MsvAvTargetName` (SPN). NTLMv2 reserved AV_PAIRS in 1998 but most of the fields are 2009-2019-era retrofits onto the original wire format [@ms-nlmp].
</Definition>

<Definition term="Message Integrity Code (MIC)">
A 16-byte HMAC-MD5, keyed by `ExportedSessionKey`, computed over the concatenation of the NTLM `NEGOTIATE`, `CHALLENGE`, and `AUTHENTICATE` messages and embedded in `AUTHENTICATE`. (`ExportedSessionKey` equals `SessionBaseKey` unless `NTLMSSP_NEGOTIATE_KEY_EXCH` is negotiated; the MIC always uses the exported key.) Introduced as a retrofit so that a man-in-the-middle relay could not silently strip the signing-required flags from the negotiate phase. Drop-the-MIC (CVE-2019-1040) demonstrated that the *presence* of the MIC was itself a negotiated property and could be stripped [@ms-nlmp, @nvd-cve-2019-1040].
</Definition>

<Definition term="Channel Binding Token (CBT)">
A hash of the server's TLS endpoint certificate placed in `MsvAvChannelBindings` so the authentication is bound to the specific TLS channel the client believed it was talking over. When both ends enforce CBT, an attacker who terminates one TLS channel and opens a different TLS channel to the real server cannot reuse the captured NTLM response. Microsoft documents three enforcement modes: None, Partial, and Full [@ms-epa-wcf].
</Definition>

### Run it

The whole thing fits in a few dozen lines of JavaScript. The point of the runnable demo is not to teach you to crack hashes; it is to make the password-equivalence claim land as code rather than as an assertion.

<RunnableCode lang="js" title="Compute the NTLMv2 response from a known NT-hash">{`
// Demonstrates the [MS-NLMP] NTLMv2 response algorithm.
//
// The point: NTProofStr is a deterministic function of the NT-hash plus
// values that travel in the clear or that the attacker controls. If you
// possess the NT-hash, you can compute NTProofStr for any (challenge,
// client_challenge, timestamp, av_pairs). That is the protocol-level
// proof of password-equivalence.
//
// In a real client, NT-hash = MD4(UTF-16LE(password)). MD4 is removed from
// most modern browser/Node crypto providers, so we use a precomputed
// NT-hash for password "Summer2026!" and focus on the structural property
// that matters: knowledge of those 16 bytes is sufficient forever.

const crypto = require("crypto");

// Precomputed NT-hash for password "Summer2026!" (16 bytes, hex):
//   reference value verified against impacket's NTOWFv1() helper offline.
const ntHash = Buffer.from("41aed72cec76816423703d8e545eea31", "hex");

const user = "alice", domain = "CONTOSO";

// NTOWFv2 = HMAC-MD5(NT-hash, UNICODE(Upper(user) || domain))
const userDomain = Buffer.from((user.toUpperCase() + domain), "utf16le");
const ntowfv2 = crypto.createHmac("md5", ntHash).update(userDomain).digest();

// NTProofStr = HMAC-MD5(NTOWFv2, ServerChallenge || temp)
// where temp = ResponserVersion(0x01) || HiResponserVersion(0x01) || Z(6) ||
//              Time(8) || ClientChallenge(8) || Z(4) || ServerName || Z(4)
const serverChal = Buffer.from("0123456789abcdef", "hex");
const clientChal = Buffer.from("fedcba9876543210", "hex");
const ts = Buffer.alloc(8);                       // any 8-byte FILETIME
const serverName = Buffer.from("00000000", "hex"); // empty AV_PAIR list
const tempBuf = Buffer.concat([
  Buffer.from("01010000000000000000", "hex"),     // version 1.1 || Z(6)
  ts, clientChal,
  Buffer.from("00000000", "hex"),                 // Z(4)
  serverName,
  Buffer.from("00000000", "hex"),                 // Z(4)
]);
const ntProofStr = crypto.createHmac("md5", ntowfv2)
  .update(Buffer.concat([serverChal, tempBuf])).digest();

console.log("NT-hash    :", ntHash.toString("hex"));
console.log("NTOWFv2    :", ntowfv2.toString("hex"));
console.log("NTProofStr :", ntProofStr.toString("hex"));
console.log("");
console.log("Now change serverChal/clientChal/ts and rerun: NTProofStr changes,");
console.log("but only the *first* line of input (the NT-hash) is a secret. The");
console.log("rest travels in the clear inside the three NTLM messages. Possessing");
console.log("ntHash IS possessing the credential -- forever, on every server.");
`}</RunnableCode>

The demo prints three lines, then a punchline. The lines are not impressive; the punchline is.

> **Key idea:** The NT-hash is not a credential; it *is* the credential. Knowing the hash IS authentication. Every pass-the-hash tool ever written, from Paul Ashton's modified Samba in 1997 to the present, is a different packaging of the same realisation: an authentication that is a deterministic function of a static secret turns possession of that secret into permanent authority [@wp-pass-the-hash].

If possession of the hash is the protocol, the last 28 years of attacks are not surprises -- they are obvious next steps. What are those steps?

## 4. The Three-Decade Attack Cascade

Five generations of attacks. Each one is named, each one is dated, each one took Microsoft years to respond to, and each Microsoft response always closed the *primitive* and left the *class* alive. They are not five surprises; they are five logical consequences of the wire protocol you just read.

### Generation 1 -- 1997: Pass-the-Hash (Paul Ashton)

The first published exploit of password-equivalence comes from Paul Ashton, posted to the Bugtraq mailing list in 1997. Ashton ships a patch against the Samba SMB client that takes a 16-byte NT-hash directly on the command line, *instead* of asking for a cleartext password [@wp-pass-the-hash]. The patch is a one-paragraph change against an open-source codebase, and that fact -- the brevity of the change -- is the lesson.

The NTLM response function has no input that depends on knowing the plaintext password. Replacing the plaintext-password input with a literal NT-hash input does not change the bytes that go on the wire. The server cannot tell the difference.

Microsoft's response, for more than a decade, is *do not lose your hashes*. There is no protocol fix because there is no protocol bug to fix; the design is doing exactly what it was designed to do. The response is operational guidance: tier your admins, scrub LSASS, do not run privileged sessions on workstations.

### Generation 2 -- 2001: NTLM Relay (Sir Dystic / SMBRelay)

If you do not have to *steal* the hash to use the credential, you also do not have to *steal* the live exchange. You can simply *relay* it. On March 31, 2001, at the @lanta.con conference, Sir Dystic of the Cult of the Dead Cow (Josh Buchbinder) releases SMBRelay: a small program that accepts an SMB connection on port 139, opens a second SMB connection back to *another* server, and shuttles the NEGOTIATE / CHALLENGE / AUTHENTICATE messages between the two sides [@cdc-smbrelay, @wp-smbrelay].

The attack works because the three NTLM messages are not bound to a particular client, server, or service. Whoever sits between them can replay the credential against whatever destination the attacker chooses, as that user, for the duration of the exchange.

<Sidenote>The colourful provenance matters. The Cult of the Dead Cow released SMBRelay alongside Back Orifice 2000; "Sir Dystic" is the same Josh Buchbinder who later wrote the SMBProxy authentication-relay framework. The point is not the chrome -- it is that the relay class was disclosed publicly *at a conference* in 2001, with working code on the cDc website, and Microsoft did not ship a fix for the trivial case (self-relay) until November 2008 [@cdc-smbrelay, @wp-smbrelay].</Sidenote>

Microsoft's response is incomplete and slow. SMB signing exists from Windows 2000 onward, but it is off by default on member servers for more than a decade [@ms-smb-signing]. MS08-068, in November 2008, finally patches the *self-relay* case (CVE-2008-4037): the SMB server now refuses to accept an authentication that the client itself just generated against the same server [@ms-ms08-068, @nvd-cve-2008-4037]. NVD's record for CVE-2008-4037 explicitly calls the original fix "insufficient for CVE-2000-0834" -- meaning the patch closed exactly the self-relay case and nothing else [@nvd-cve-2008-4037]. Seven years to fix the simplest variant; the *cross-server* relay class is still wide open.

### Generation 3 -- 2008-2014: Credential Theft as a Service

By 2008, the operational guidance "do not lose your hashes" stops being defensible. On February 29, 2008, Hernan Ochoa releases the Pass-the-Hash Toolkit v1.3, two native Windows binaries called `iam.exe` and `whosthere.exe` that read the NT-hash out of LSASS memory and inject it into a new logon session [@hexale-pth-toolkit-v13, @coresec-ochoa-pth-pdf]. PtH stops being a Linux-and-Samba trick and becomes a Windows-everywhere reality.

Three years later, Benjamin Delpy publishes [Mimikatz](https://paragmali.com/blog/can-this-code-do-this----twenty-five-years-of-attacks-on-the/). The first version is closed-source, released in May 2011 [@wired-greenberg-mimikatz, @wp-mimikatz]. By April 6, 2014, the GitHub repository goes public with the version string "mimikatz 2.0 alpha (x86) release 'Kiwi en C' (Apr 6 2014 22:02:03)" [@gh-mimikatz]. The repo description is a near-perfect summary of what LSASS is to an attacker: "extract plaintexts passwords, hash, PIN code and kerberos tickets from memory. mimikatz can also perform pass-the-hash, pass-the-ticket or build Golden tickets" [@gh-mimikatz]. LSASS becomes the universal credential oracle.

<Sidenote>Delpy did not intend Mimikatz to be a weapon. Wired's Andy Greenberg documents the trajectory in detail: Delpy "released it publicly in May 2011, but as a closed source program," and "in mid-2011, he learned for the first time... that Mimikatz had been used in an intru" -- the DigiNotar breach. Police raided his Moscow conference hotel room. He went open-source partly because closed-source was no longer protecting anyone and partly to make the security industry confront what was in LSASS [@wired-greenberg-mimikatz].</Sidenote>

Microsoft's response is structural and specific. Credential Guard ships in Windows 10 RTM (Enterprise and Education editions), July 29, 2015 [@ms-credential-guard]. It uses Virtualization-Based Security to isolate `lsaiso.exe` in a separate VTL1 partition; the kernel can no longer read NTLM hashes or Kerberos TGTs even at SYSTEM-level privilege. Protected Users and Restricted Admin in Server 2012 R2 / Windows 8.1 narrow the surface further. LSASS-as-PPL adds a process-protection layer between user-mode debuggers and the LSASS address space [@ms-credential-guard].

Credential Guard works -- against the credential-*theft* class. It does nothing against credential-*use*. An attacker who never extracts a hash, because they never need to, sails right past it. Relay does not need the hash. Coercion does not need the hash. ESC8 does not need the hash. That is the next generation.

### Generation 4 -- 2018-2021: Forced-Authentication Coercion

In 2018 at DerbyCon 8, Lee Christensen releases SpoolSample, known publicly as "PrinterBug." The GitHub description is exact: "PoC tool to coerce Windows hosts authenticate to other machines via the MS-RPRN RPC interface" [@gh-spoolsample]. The trick is that the Print Spooler service runs as SYSTEM, accepts a remote RPC call (`RpcRemoteFindFirstPrinterChangeNotificationEx`) that takes a UNC path, and dutifully NTLM-authenticates back to whatever path the caller named -- on behalf of the machine account. Any Windows service running as SYSTEM that accepts a UNC path is a confused deputy that will authenticate on demand.

<Aside label="Why 'PrinterBug' was 'by design' for three years">
Microsoft's initial classification of SpoolSample was *authenticated-only / by design*: a caller needed valid domain credentials to reach the spooler endpoint, and authenticated callers triggering machine-account authentications was deemed within spec. The classification held through 2018, 2019, and most of 2020. PetitPotam broke it, because PetitPotam used MS-EFSRPC over LSARPC, which accepts *unauthenticated* binds on a domain controller's named-pipe interface. With the authentication requirement gone, "by design" stopped being a coherent defence. Microsoft started shipping fixes [@gh-petitpotam, @nvd-cve-2021-36942].
</Aside>

Marina Simakov and Yaron Zinar of Preempt (now CrowdStrike) publish "Drop the MIC" on June 11, 2019. The vulnerability is CVE-2019-1040: a tampering bug where "a man-in-the-middle attacker is able to successfully bypass the NTLM MIC (Message Integrity Check) protection" [@crowdstrike-drop-the-mic, @nvd-cve-2019-1040]. The bypass works by stripping the `NTLMSSP_NEGOTIATE_SIGN` and `NTLMSSP_NEGOTIATE_ALWAYS_SIGN` flags from the initial `NEGOTIATE`, removing the MIC field from `AUTHENTICATE`, and removing the `Version` field that drives MIC detection.

Servers that should have required a MIC silently accept the modified message. The MIC -- the retrofit integrity layer that was supposed to make tampering detectable -- turns out to be itself untethered to the negotiation [@crowdstrike-drop-the-mic].

Lionel Gilles (topotam77) publishes PetitPotam in July 2021, CVE-2021-36942. The GitHub repository description reads: "PoC tool to coerce Windows hosts to authenticate to other machines via MS-EFSRPC EfsRpcOpenFileRaw or other functions" [@gh-petitpotam, @nvd-cve-2021-36942]. The decisive new property compared to SpoolSample is that PetitPotam needs *no credentials* against a domain controller: LSARPC accepts unauthenticated binds, so the coercion can be triggered by an attacker who has merely joined the network.

In 2022, Remi Gascou (p0dalirius) publishes Coercer, a Python script that consolidates the coercion class across MS-RPRN, MS-EFSR, MS-DFSNM, MS-FSRVP, and many more RPC interfaces. The README describes it succinctly: "A python script to automatically coerce a Windows server to authenticate on an arbitrary machine through many methods" [@gh-coercer].

### Generation 5 -- 2021: ADCS Web-Enrollment Relay (ESC8)

On June 17, 2021, Will Schroeder and Lee Christensen of SpecterOps publish "Certified Pre-Owned," a whitepaper and matching blog post that maps eight new attack classes against Active Directory Certificate Services [@specterops-cert-preowned-blog, @specterops-cert-preowned-pdf]. ESC1 through ESC7 are template and configuration weaknesses. ESC8 is the keystone of this article.

ESC8 says: AD CS Web Enrollment endpoints (`/certsrv/`) accept NTLM authentication. Coerce a server's machine account to authenticate to your relay listener; relay the authentication to `/certsrv/`; enroll the relayed identity for a machine-template certificate; use that certificate to perform PKINIT against the KDC and request a TGT [@specterops-cert-preowned-blog]. The NTLM-vs-Kerberos boundary stops being a meaningful one. NTLM is the protocol on the front side of the attack; Kerberos is the trust token on the back side; the certificate is the conduit between them.

The point of ESC8 is not just that it works. The point is that it works against a perfectly retrofitted environment. SMB signing did not enter the chain. LDAP signing did not enter the chain. EPA was supposed to enter the chain on the `/certsrv/` side but was unevenly deployed. Credential Guard never had a hash to protect.

<Mermaid caption="Five generations of NTLM attacks. Each Microsoft response closes a primitive; each next generation defeats it with an unanchored cousin.">
flowchart TD
    A[Gen 1 -- 1997 Pass-the-Hash<br/>Paul Ashton, modified Samba]
    A --> A1[Response: operational guidance<br/>Do not lose your hashes]
    A1 --> B[Gen 2 -- 2001 SMBRelay<br/>Sir Dystic, atlanta.con]
    B --> B1[Response: MS08-068 2008<br/>Patches self-relay only]
    B1 --> C[Gen 3 -- 2008-2014 LSASS extraction<br/>Ochoa PtH Toolkit, Delpy Mimikatz]
    C --> C1[Response: Credential Guard 2015<br/>Closes theft; not use]
    C1 --> D[Gen 4 -- 2018-2021 Coercion<br/>SpoolSample, Drop-the-MIC, PetitPotam, Coercer]
    D --> D1[Response: KB 5005413, EPA<br/>Closes primitive; not class]
    D1 --> E[Gen 5 -- 2021 ESC8<br/>Schroeder/Christensen Certified Pre-Owned]
    E --> E1[Response: remove NTLM]
</Mermaid>

<Mermaid caption="The coercion-and-relay flow common to PrinterBug, PetitPotam, and Coercer. The SYSTEM service is the confused deputy; the attacker controls neither the credential nor the destination, only the *triggering*.">
sequenceDiagram
    autonumber
    actor A as Attacker
    participant V as "Victim SYSTEM service (Spooler, EFSR, DFSNM)"
    participant R as Attacker NTLM relay
    participant T as "Target service (LDAP, SMB, certsrv)"
    A->>V: RPC call with UNC path \\attacker\share
    V->>R: NTLM NEGOTIATE (as machine account)
    R->>T: Open new authenticated session
    T->>R: NTLM CHALLENGE
    R->>V: Forward CHALLENGE
    V->>R: NTLM AUTHENTICATE (signed by machine account)
    R->>T: Forward AUTHENTICATE -- T treats attacker session as the victim
</Mermaid>

| Generation | Primitive | Public date | Microsoft response | What survived |
|---|---|---|---|---|
| 1. Pass-the-Hash | Use the hash directly | 1997, Paul Ashton, Bugtraq [@wp-pass-the-hash] | Operational guidance | Hash is still password-equivalent on the wire |
| 2. NTLM relay (SMB) | Forward live exchange | March 31, 2001, Sir Dystic, @lanta.con [@cdc-smbrelay] | MS08-068 (Nov 2008) -- self-relay only [@ms-ms08-068, @nvd-cve-2008-4037] | Cross-server, cross-protocol relay |
| 3. LSASS extraction | Steal hashes from memory | Feb 2008 (Ochoa); May 2011 closed / Apr 2014 open (Delpy) [@hexale-pth-toolkit-v13, @gh-mimikatz, @wired-greenberg-mimikatz] | Credential Guard (Jul 29, 2015) [@ms-credential-guard] | Hash *use* outside LSASS path; SYSTEM-level Mimikatz on the SAM |
| 4. Coercion | Make SYSTEM authenticate on demand | 2018 SpoolSample [@gh-spoolsample]; 2019 Drop-the-MIC [@crowdstrike-drop-the-mic, @nvd-cve-2019-1040]; 2021 PetitPotam [@gh-petitpotam, @nvd-cve-2021-36942]; 2022 Coercer [@gh-coercer] | Per-interface patches; KB 5005413 EPA recipe [@ms-kb5005413] | The pattern of "SYSTEM holds an unanchored credential" |
| 5. ESC8 ADCS Web Enrollment relay | NTLM coerce -> /certsrv/ -> TGT via PKINIT | June 17, 2021, Schroeder/Christensen, "Certified Pre-Owned" [@specterops-cert-preowned-blog, @specterops-cert-preowned-pdf] | KB 5005413; AD CS hardening; eventually Phase 3 of NTLM removal | Kerberos relay class on the other side (KrbRelay/KrbRelayUp) [@gh-krbrelayup] |

<PullQuote>
"KrbRelayUp -- a universal no-fix local privilege escalation in windows domain environments where LDAP signing is not enforced (the default settings)." -- Dec0ne, KrbRelayUp README [@gh-krbrelayup]
</PullQuote>

The reader who started Section 4 believing "if I patch each named NTLM attack, the protocol is safe" finishes Section 4 believing something else. Every retrofit patches a *primitive*; none addresses the *existence* of the fallback path. The next attack is always one cross-protocol step away. The retrofit strategy is structurally incapable of closing the class.

By the end of 2021, NTLM-the-protocol cannot be removed because four use cases require it, and NTLM-the-fallback cannot be kept because ESC8 turned it into a domain-takeover oracle. Something has to change. What?

## 5. The Retrofit Strategy and Its Funeral

Before naming the answer, name the strategy that failed. Microsoft's defensive cadence between 2001 and 2021 splits into three families, each effective against a named primitive, each defeated by an unanchored cousin of that primitive.

### Family A -- Per-protocol message authentication

SMB signing. LDAP signing and sealing. The idea is to anchor the *content* of each authenticated request inside a per-session signature derived from the authentication. SMB signing introduces an HMAC over every SMB message keyed by a per-session `SigningKey`; LDAP signing and sealing do the equivalent for LDAP operations [@ms-smb-signing].

Family A works when the *target* protocol enforces it. SMB-to-SMB relay against an SMB server with required signing fails; LDAP-to-LDAP relay against an LDAP server with required signing fails. The strategy assumes the attacker stays in the same protocol family. Cross-protocol relay -- SMB authentication relayed to LDAP, or SMB authentication relayed to `/certsrv/` -- defeats it. The MS-EFSR coercion can produce an authentication that originates "as if from SMB" and gets accepted by an unrelated HTTPS service that ignores the SMB signing flag entirely [@nvd-cve-2019-1040, @specterops-cert-preowned-blog].

### Family B -- Per-channel binding tokens and the MIC

EPA (channel binding) and the NTLMv2 MIC are the response to cross-protocol relay. Both try to tie the authentication to *the specific channel* the client believes it is using. EPA places a hash of the TLS endpoint certificate into the `MsvAvChannelBindings` AV_PAIR; an HTTPS server with EPA required compares it to its own certificate's hash and rejects the authentication if they do not match [@ms-epa-wcf]. The MIC binds all three NTLM messages together so a relay cannot strip the signing-required flags from `NEGOTIATE` after the client sets them [@ms-nlmp].

Family B works when both ends agree to enforce. Drop-the-MIC (CVE-2019-1040) demonstrated that the *presence* of the MIC was negotiated and could be stripped, so a server that supported MIC-less clients silently accepted MIC-less messages from a relay [@crowdstrike-drop-the-mic, @nvd-cve-2019-1040]. EPA suffers from the same enforcement-asymmetry: when an IIS endpoint runs with `policyEnforcement="None"` or `"Partial"`, the binding is not checked. KB 5005413 published the explicit `<extendedProtectionPolicy policyEnforcement="Always" />` recipe for `/certsrv/` because field deployments had been running with weaker settings [@ms-kb5005413].

### Family C -- Credential isolation

Credential Guard. LSASS-as-PPL. Protected Users. Restricted Admin. These attack the *theft* surface. Credential Guard moves the NT-hash into `lsaiso.exe` inside VTL1; the kernel can no longer read it. Microsoft now ships it enabled by default on Windows 11 22H2 and Server 2025 on hardware that meets the requirements [@ms-credential-guard].

Family C is honest about what it covers. It does nothing about coercion flows that never touch the NT-hash. PetitPotam and ESC8 do not need a hash; the relay session uses the live NTLM exchange and is never persisted. Credential Guard cannot help.

| Family | What it closes | What it does not close | Defeating attack |
|---|---|---|---|
| A. Per-protocol message auth (SMB/LDAP signing) | Same-protocol relay against the target | Cross-protocol relay; targets that do not enforce | LDAP relay from SMB coercion [@nvd-cve-2019-1040]; ESC8 relay to /certsrv/ |
| B. Channel binding (EPA) + MIC | Same-channel relay through TLS termination | MIC stripping in negotiation; EPA at None/Partial; non-TLS targets | Drop-the-MIC [@nvd-cve-2019-1040]; under-enforced EPA [@ms-kb5005413] |
| C. Credential isolation (Credential Guard, LSASS-PPL) | Hash theft from running LSASS | Hash *use* in live relay; SAM extraction from disk; coercion | ESC8 + PetitPotam [@gh-petitpotam, @specterops-cert-preowned-blog]; SAM hive offline [@ms-credential-guard] |

> **Key idea:** Every retrofit Microsoft has shipped against NTLM attacks one *primitive* of NTLM. None address the *existence* of NTLM as a fallback path. ESC8 was the funeral of the retrofit strategy because ESC8 turned a fully retrofitted environment into a domain takeover without defeating any retrofit.

> **Note:** "Certified Pre-Owned" did not break a Microsoft fix; it composed the existing infrastructure. The chain assumes SMB signing is on, EPA is on (somewhere), and Credential Guard is on. It still works, because none of those controls cover the path that goes Coercer -> NTLM relay -> AD CS Web Enrollment -> PKINIT. After 2021, the question stopped being "what's the next retrofit?" and became "what does it take to remove the fallback?" [@specterops-cert-preowned-blog, @ms-kb5005413].

To remove ESC8 without rebuilding AD CS, Microsoft has to remove NTLM. To remove NTLM, Microsoft has to remove the four reasons NTLM existed as a fallback in the first place. What does that look like in shippable form?

## 6. The Breakthrough: Closing the Fallback

October 11, 2023. Matthew Palko, Windows IT Pro Blog. "The evolution of Windows authentication." For the first time in twenty-three years, Microsoft publicly commits to *removing* NTLM, not restricting it, and names the three load-bearing features that make removal possible [@palko-2023-evolution].

The plan starts where every honest plan starts -- by stating the problem in its own words. There are four fallback reasons NTLM persisted: no DC line-of-sight, no domain at all (local accounts), no SPN for the target, and hard-coded NTLM in application code [@palko-2023-evolution]. Each gets an engineered answer. The four-to-three correspondence (three protocols plus one refactor) is the new architecture.

<PullQuote>
"Our end goal is eliminating the need to use NTLM at all to help improve the security bar of authentication for all Windows users." -- Matthew Palko, Microsoft Windows IT Pro Blog, October 11, 2023 [@palko-2023-evolution]
</PullQuote>

### IAKerb -- closing "no DC line-of-sight"

IAKerb stands for *Initial and Pass Through Authentication Using Kerberos V5 and the GSS-API*. The IETF draft has a four-author list -- Benjamin Kaduk, Jim Schaad, Larry Zhu, and Jeffrey E. Altman -- and a quiet history [@draft-ietf-kitten-iakerb].

The premise is simple. A client wants to authenticate to an application server with Kerberos but cannot reach a KDC -- maybe the client is behind a firewall, maybe the KDC is only reachable from the server's side of a VPN. IAKerb wraps the Kerberos `AS-REQ` and `TGS-REQ` messages inside GSS-API tokens and asks the application server to proxy them to a KDC that the server *can* reach. The client never opens a direct TCP/UDP connection to a KDC; the application server acts as the carrier.

<Aside label="Why the IETF marked IAKerb dead in 2019">
The honesty duty: IAKerb's IETF draft (`draft-ietf-kitten-iakerb`) was marked "Dead WG Document" on August 29, 2019, by Robbie Harwood [@draft-ietf-kitten-iakerb]. Harwood's note read, roughly, that IAKerb was historical at that point and the working group had no interest left. The last revision (`-03`) is from March 30, 2017, by Benjamin Kaduk. Microsoft is now reviving the protocol in 2023-2026 for Windows 11 and Windows Server 2025 -- without acknowledging the dead-WG status in its own blog posts. This is the gap between an IETF standards-track document and what a vendor ships; the article reports both [@draft-ietf-kitten-iakerb, @palko-2023-evolution].
</Aside>

<Definition term="IAKerb">
Initial and Pass Through Authentication Using Kerberos V5 and the GSS-API. A GSS-API-wrapped Kerberos exchange in which the client cannot reach a KDC directly and the application server proxies `AS-REQ` / `TGS-REQ` on the client's behalf. Defined by `draft-ietf-kitten-iakerb` (IETF kitten WG, currently a Dead WG Document). MIT Kerberos has shipped IAKerb since 1.9 (2010); Apple ships `GSS_IAKERB_MECHANISM` since macOS 10.14. Microsoft is implementing IAKerb in Windows 11 / Server 2025 [@draft-ietf-kitten-iakerb, @palko-2023-evolution, @ms-cuomo-ad2025].
</Definition>

### Local KDC -- closing "no domain at all"

Local accounts in the machine SAM have never had a KDC. Workgroup machines have no domain at all. Both cases force NTLM today. The fix is conceptually trivial: run a tiny Kerberos KDC against the local SAM, exposed only through IAKerb-wrapped exchanges so the wire protocol is the same as the trust-traversing case [@palko-2023-evolution, @ms-cuomo-ad2025].

This is the late-adopter move that surprises Linux-side practitioners. MIT Kerberos has had IAKerb since 1.9 (released in 2010). Samba has been working on a `localkdc` for years. At FOSDEM 2025 (February 2, 2025), Alexander Bokovoy and Andreas Schneider gave a talk explicitly framed as "localkdc -- a general local authentication hub" [@fosdem-2025-localkdc-schedule, @cryptomilk-localkdc]. Schneider's companion blog post the next week summarised the work: a parallel local-authentication hub for Linux that interoperates with the IAKerb wire format Windows is now adopting [@cryptomilk-localkdc].

<Definition term="Local KDC">
A small Kerberos Key Distribution Center process that runs against a machine's local user database (the SAM on Windows; a file or sssd on Linux) and is exposed only through IAKerb. It lets local-account authentications use Kerberos under the same Negotiate / NEGOEX wire envelope used by domain authentications -- removing one of the four reasons NTLM persisted. Shipping in Windows 11 / Server 2025 [@palko-2023-evolution, @ms-cuomo-ad2025]; parallel Linux/Samba work coordinated under the FOSDEM 2025 `localkdc` umbrella [@fosdem-2025-localkdc-schedule, @cryptomilk-localkdc].
</Definition>

### NEGOEX -- carrying IAKerb under the existing `Negotiate` API

You do not want to teach every application a new SSPI provider. Existing code calls `AcquireCredentialsHandle("Negotiate", ...)`; that should keep working, and IAKerb should be one of the mechanisms `Negotiate` is willing to pick. The piece of plumbing that makes this possible is NEGOEX: SPNEGO Extended Negotiation [@ms-negoex, @draft-zhu-negoex].

NEGOEX adds a pair of meta-data messages on top of the standard SPNEGO `NegTokenInit` / `NegTokenResp` exchange, so that mechanisms (like IAKerb) that need a richer negotiation can ride inside the `Negotiate` envelope. The Microsoft Open Specification `[MS-NEGOEX]` is currently at revision 4.0 (April 23, 2024), with the original revision dated July 9, 2020 [@ms-negoex]. The expired Microsoft IETF draft `draft-zhu-negoex` from January 2011 is the historical anchor; four Microsoft authors -- Michiko Short, Larry Zhu, Kevin Damour, and Dave McPherson -- are listed verbatim in the draft metadata [@draft-zhu-negoex].

A correction is owed here. Scope notes inherited from earlier in this project cited "RFC 8143" as the NEGOEX standard. RFC 8143 is actually titled "Using Transport Layer Security (TLS) with Network News Transfer Protocol (NNTP)" and updates RFC 4642; it has nothing to do with NEGOEX [@rfc-8143]. The correct primary references for NEGOEX are `[MS-NEGOEX]` and `draft-zhu-negoex`, both used consistently throughout this article [@ms-negoex, @draft-zhu-negoex].

<Definition term="NEGOEX">
The SPNEGO Extended Negotiation security mechanism. Adds a meta-data exchange inside the SPNEGO envelope so that richer mechanisms (like IAKerb) can be negotiated without changing the SSPI surface. Primary sources: Microsoft Open Specification `[MS-NEGOEX]` revision 4.0 (April 2024); expired IETF draft `draft-zhu-negoex` (January 2011). Despite a common scope-doc error, RFC 8143 is *not* NEGOEX; RFC 8143 is "Using TLS with NNTP" [@ms-negoex, @draft-zhu-negoex, @rfc-8143].
</Definition>

### Negotiate-everywhere refactor -- closing "hard-coded NTLM"

The last fallback case is the most prosaic: application code that calls `AcquireCredentialsHandleW(..., "Ntlm", ...)` or RPC code that asks for `RPC_C_AUTHN_WINNT`. Both bypass `Negotiate` and force NTLM no matter what is on the wire. The fix is editorial -- audit Windows internals, replace each hard-coded `Ntlm` call with `Negotiate` -- and very large in surface area. Dan Cuomo's "Active Directory improvements in Windows Server 2025" post summarises the Windows Server Summit 2024 session in one sentence: "we have created completely new Kerberos features to minimize use of NTLM in your environments. This session explains and demonstrates IAKerb, Local KDC, IP SPN, and the roadmap to the end of NTLM" [@ms-cuomo-ad2025].

| Fallback reason | Closure mechanism | Primary source | Ship target |
|---|---|---|---|
| No DC line-of-sight | IAKerb (GSS-wrapped Kerberos through the app server) | `draft-ietf-kitten-iakerb` (Dead WG, revived by Microsoft) [@draft-ietf-kitten-iakerb] | Windows 11 / Server 2025 [@palko-2023-evolution, @ms-cuomo-ad2025] |
| No domain at all (local accounts) | Local KDC over IAKerb | Palko 2023; Samba `localkdc` parallel [@palko-2023-evolution, @fosdem-2025-localkdc-schedule] | Windows 11 / Server 2025 |
| No SPN | IP-SPN policy under Negotiate | `[MS-NEGOEX]`; Cuomo 2024 session [@ms-negoex, @ms-cuomo-ad2025] | Windows Server 2025 |
| Hard-coded NTLM | Audit + replace `AcquireCredentialsHandle("Ntlm")` with `Negotiate` | Palko 2023 [@palko-2023-evolution] | Editorial, ongoing through Phase 2 |

<Mermaid caption="The four fallback reasons NTLM persisted, mapped to the engineered closures Microsoft committed to in October 2023. Three protocol-level mechanisms plus one refactor.">
flowchart LR
    R1[No DC line-of-sight] --> M1[IAKerb<br/>draft-ietf-kitten-iakerb]
    R2[No domain at all<br/>local accounts] --> M2[Local KDC<br/>over IAKerb]
    R3[No SPN for target] --> M3[IP-SPN policy<br/>under Negotiate]
    R4[Hard-coded NTLM<br/>in app code] --> M4[Negotiate-everywhere<br/>refactor]
    M1 --> N[NEGOEX<br/>SPNEGO extension]
    M2 --> N
    M3 --> N
    N --> P[Negotiate SSPI<br/>same call sites]
</Mermaid>

<Mermaid caption="An IAKerb exchange. The client never touches the KDC; the application server is the carrier. The wire envelope is the existing Negotiate / NEGOEX SPNEGO surface, so application code does not change.">
sequenceDiagram
    autonumber
    participant C as Client (no KDC reach)
    participant S as Application server (KDC reach)
    participant K as KDC
    C->>S: SPNEGO NegTokenInit with NEGOEX MetaData, mechs=[Kerberos, IAKerb]
    S-->>C: NegTokenResp, server picks IAKerb
    C->>S: IAKerb token wrapping AS-REQ
    S->>K: AS-REQ
    K-->>S: AS-REP
    S-->>C: IAKerb token wrapping AS-REP -> client now has TGT
    C->>S: IAKerb token wrapping TGS-REQ for service ticket
    S->>K: TGS-REQ
    K-->>S: TGS-REP (service ticket)
    S-->>C: IAKerb token wrapping TGS-REP
    Note over C,S: From now on, ordinary AP-REQ / AP-REP over Kerberos -- no NTLM needed
</Mermaid>

<Sidenote>What does this mean for Linux and macOS clients in a Windows domain? IAKerb is a GSS-API mechanism, and MIT's `krb5` library shipped IAKerb in 1.9 (released December 2010) -- well before Microsoft. Apple's Heimdal-derived GSS framework has shipped `GSS_IAKERB_MECHANISM` since macOS 10.14 (Mojave, 2018). The cross-platform interoperability story is therefore *better* in 2026 than it has been in years: a Linux client using MIT 1.9+ or an Apple client using macOS 10.14+ can already speak IAKerb to a Windows Server 2025 Local KDC. The parallel Samba `localkdc` effort closes the symmetric case: a Linux machine acting as the IAKerb server [@fosdem-2025-localkdc-schedule, @cryptomilk-localkdc].</Sidenote>

The reader who started Section 6 believing "NTLM is too entrenched to remove" finishes Section 6 believing something else. The entrenchment is *exactly four* named cases, and *each one* has been given an engineered answer. Removal is now a sequencing problem, not an architecture problem.

The engineering existed by October 2023. The shipping commitment came in January 2026. What is Microsoft actually shipping, and on what schedule?

## 7. The Three-Phase Roadmap

January 29, 2026. The Windows IT Pro Blog publishes "Advancing Windows security: Disabling NTLM by default" under the byline `mariam_gewida` [@gewida-2026-disabling]. The post documents Microsoft's published roadmap and opens with a caveat that the rest of this article works hard not to forget.

> **Note:** "Disabling NTLM by default does not mean completely removing NTLM from Windows yet... during phase 3, NTLM will remain present in the OS and can be explicitly re-enabled via policy if you still need it." -- mariam_gewida, "Advancing Windows security: Disabling NTLM by default," Microsoft Windows IT Pro Blog, January 29, 2026 [@gewida-2026-disabling]

The plan has three phases. They are sequenced; each phase produces the inputs the next phase needs.

### Phase 1 (now) -- Audit

Phase 1 is auditing. The deliverable is enhanced NTLM logging in Windows 11 24H2 and Windows Server 2025, documented in KB 5064479 (published July 11, 2025) [@ms-kb5064479]. The new logging surface is `Applications and Services Logs > Microsoft > Windows > NTLM > Operational`, gated by two GPOs called "NTLM Enhanced Logging" and "Log Enhanced Domain-wide NTLM Logs." For each NTLM authentication, the event tells the administrator three things: *who* called (the process), *why* (the negotiated SSPI provider chose NTLM), and *where* (the target service). The KB also names per-event warning classes for NTLMv1, MIC-less, and EPA-not-supported authentications [@ms-kb5064479].

Phase 1 also closes the oldest residual: NTLMv1. Microsoft's deprecation page added an NTLM entry in June 2024 with verbatim language: "All versions of NTLM, including LANMAN, NTLMv1, and NTLMv2, are no longer under active feature development and are deprecated. Use of NTLM will continue to work in the next release of Windows Server and the next annual release of Windows. Calls to NTLM should be replaced by calls to Negotiate" [@ms-deprecated-features].

The same row adds: "NTLMv1 is removed starting in Windows 11, version 24H2 and Windows Server 2025" -- the November 2024 update note [@ms-deprecated-features, @ms-upcoming-ntlmv1]. The KB 4090105 pre-24H2 NTLMv1 auditing surface (Event ID 4624 with `Package Name (NTLM only): NTLM V1`) remains valid for legacy environments [@ms-ntlmv1-dc-audit].

### Phase 2 (H2 2026) -- IAKerb + Local KDC + Negotiate-first refactor in pre-release

Phase 2 puts the engineered closures from Section 6 into pre-release. IAKerb and Local KDC ship for Windows Insiders and Server preview channels. The Negotiate-first refactor lands -- Microsoft's own subsystems audit their `AcquireCredentialsHandleW("Ntlm", ...)` and `RPC_C_AUTHN_WINNT` call sites and replace them with `Negotiate` calls. Per-machine policy controls for NTLM scope make finer-grained restriction possible. IP-SPN policy lands so the "no SPN" case can be closed without naming every server by FQDN [@gewida-2026-disabling, @ms-cuomo-ad2025].

The Microsoft outreach mechanism for Phase 2 is the `ntlm@microsoft.com` mailbox; the January 2026 post names it explicitly as the channel for surfacing cross-forest, federated, and ISV-edge cases that need engineering help before Phase 3 [@gewida-2026-disabling].

### Phase 3 (next major Windows / Windows Server release) -- Disabled by default

Phase 3 is the default-off flip. Network NTLM authentication is disabled by default in the next major Windows and Windows Server release. The disablement is a configuration, not a binary removal: NTLM remains in the OS, callable through `Negotiate` only when a policy explicitly re-enables it for a named scope [@gewida-2026-disabling]. The Hacker News' summary of the roadmap published February 2026 documents the same three-phase structure for industry-press consumption [@thn-2026-ntlm-phaseout].

<Mermaid caption="The three-phase NTLM disablement roadmap. Phase 1 audit data feeds Phase 2's refactor list; Phase 2's IAKerb / Local KDC / IP-SPN are prerequisites for Phase 3's default-off.">
flowchart LR
    P1[Phase 1 -- NOW<br/>KB 5064479 enhanced auditing<br/>NTLMv1 removed in 24H2 / WS2025] --> P2
    P2[Phase 2 -- H2 2026<br/>IAKerb + Local KDC pre-release<br/>Negotiate-first refactor<br/>Per-machine NTLM scope policy] --> P3
    P3[Phase 3 -- next major Windows<br/>Network NTLM disabled by default<br/>Re-enablement requires explicit policy]
</Mermaid>

| Phase | Deliverable | Date / target | Prerequisite | Primary |
|---|---|---|---|---|
| Phase 1 | Enhanced NTLM auditing | KB 5064479, July 11, 2025 | Windows 11 24H2 / Server 2025 | [@ms-kb5064479] |
| Phase 1 | NTLMv1 removal | Windows 11 24H2 / Server 2025, November 2024 | NTLM family deprecation (June 2024) | [@ms-deprecated-features, @ms-upcoming-ntlmv1] |
| Phase 2 | IAKerb + Local KDC pre-release | H2 2026, Windows Insider channel | Phase 1 audit data identifies callers | [@gewida-2026-disabling, @ms-cuomo-ad2025] |
| Phase 2 | Negotiate-first refactor of Windows subsystems | H2 2026 | Phase 1 audit data | [@palko-2023-evolution, @gewida-2026-disabling] |
| Phase 2 | IP-SPN policy for "no SPN" case | Windows Server 2025 + flighting | NEGOEX in Negotiate | [@ms-cuomo-ad2025] |
| Phase 3 | Network NTLM disabled by default | Next major Windows / Server release | All Phase 2 features GA | [@gewida-2026-disabling] |

Phase 3 is the first default configuration in 30 years that does not include NTLM. It is *not* the first configuration in 30 years without authentication-relay attacks. Why not?

## 8. What Disabling NTLM Cannot Buy You

A blunt section. Phase 3 is real progress. It is not the end of authentication attacks on Windows. Three structural ceilings survive the transition; the article will not pretend otherwise.

### Disabled is not removed

Phase 3 still ships NTLM in the OS. The default is off; the policy lockout is exactly as strong as the domain's tier-0 administrative segregation, not stronger. An attacker who reaches a domain controller with Group Policy edit rights can flip the policy and re-enable NTLM for the scope they want. The wording in the January 2026 post is precise: "during phase 3, NTLM will remain present in the OS and can be explicitly re-enabled via policy if you still need it" [@gewida-2026-disabling].

This is the design choice Microsoft has to make, because removing NTLM binaries entirely would brick every third-party application that hard-codes `Ntlm` and every legacy device that has not been firmware-updated since 2018. "Disabled by default with policy override" is the only configuration that has any chance of getting deployed.

### Kerberos has its own relay class

The relay *class* does not depend on NTLM. KrbRelay, KrbRelayUp, RBCD abuse, unconstrained-delegation abuse, S4U2Self / S4U2Proxy chains -- the entire taxonomy survives the move to Kerberos with different named primitives. Dec0ne's KrbRelayUp README, quoted at the end of Section 4, calls the class a universal no-fix local privilege escalation; the rest of the README enumerates the LDAP-signing default and the RBCD primitive that drive the post-NTLM relay surface [@gh-krbrelayup].

What changes is the protocol. What does not change is that an application server that receives an authenticated message without enforcing message integrity or channel binding can be coerced into accepting an attacker-relayed authentication. The named primitives change. The class survives.

### Local SAM hashes remain password-equivalent

The Local KDC reads the SAM. An attacker with SYSTEM-level access to the same machine reads the SAM too. Once they have the hash in hand, they can either feed it to a Local KDC running on a machine they control, or they can attempt offline cracking. IAKerb does not change either of those facts; what it changes is whether the *wire* exposes the password-equivalent secret. Defence in depth -- [TPM](https://paragmali.com/blog/the-tpm-in-windows-one-primitive-twenty-five-years-and-the-c/)-backed key wrapping, Credential Guard for VBS isolation of process credentials, [BitLocker](https://paragmali.com/blog/bitlocker-on-windows-architecture-attacks-and-the-limits-of-/) for the cold-boot scenario -- remains necessary [@ms-credential-guard].

> **Key idea:** Phase 3 is a transition between tradeoffs, not a transition out of them. The exit from NTLM-the-protocol is not the exit from the authentication-relay class, or from the chip-layer credential class. The arc closes one specific 30-year-old attack surface and opens different conversations about the next.

If the structural classes survive, what practical problems remain that an administrator should worry about between today and Phase 3?

## 9. Open Problems and the 2026-2027 Edge

Five named problems sit between Phase 1 (now) and Phase 3 GA. Each one has a primary source and a "best partial result" available today.

1. **ESC8 field deployment of EPA on `/certsrv/` is uneven.** Microsoft published KB 5005413 on July 30, 2021 with the dispositive recipe: `<extendedProtectionPolicy policyEnforcement="Always" />` on every `/certsrv/` virtual directory, plus disabling plain HTTP. Server 2025 hardening pushes EPA to required-by-default in many AD CS templates. Many environments are not on Server 2025 yet, and CISA's Known Exploited Vulnerabilities catalog still lists CVE-2021-36942 as actively exploited. CVE-2022-26925 ("Windows LSA Spoofing Vulnerability") is the LSARPC NTLM-relay variant that emerged after the initial PetitPotam patches; it is on the same KEV list [@ms-kb5005413, @nvd-cve-2021-36942, @nvd-cve-2022-26925].

2. **Third-party and legacy-app hard-coded NTLM.** Microsoft's Negotiate-everywhere refactor covers Microsoft's own code. Independent software vendors must do the same audit for theirs. Phase 1's enhanced auditing surface (KB 5064479) is the practical instrument for identifying the callers: every NTLM authentication carries the calling process name and a reason code [@ms-kb5064479]. The post-Phase-3 default-off configuration will surface these as outages on any environment that has not run the audit first.

3. **Cross-forest and federated IAKerb edges.** Single-forest IAKerb is well-defined. Multi-forest, federated, and partner-trust scenarios get implementation-defined quickly: NEGOEX has to carry IAKerb tokens through `Negotiate` across trust boundaries where the proxying server may not be in the same forest as the KDC. Microsoft's `ntlm@microsoft.com` outreach mailbox exists precisely to surface these edge cases before Phase 3 [@draft-ietf-kitten-iakerb, @gewida-2026-disabling].

4. **Linux and macOS parallel.** MIT Kerberos has had IAKerb since 1.9 (2010). Apple ships `GSS_IAKERB_MECHANISM` since macOS 10.14. The Samba and `localkdc` effort from Bokovoy and Schneider (FOSDEM 2025) is the parallel open-source path: a Linux machine that can act as the IAKerb application server for a Windows client, or vice versa, under the same `Negotiate` envelope [@fosdem-2025-localkdc-schedule, @cryptomilk-localkdc]. The interoperability story should be *better* in 2026-2027 than it has been in twenty years.

5. **Policy pressure.** EU NIS2 mandates cybersecurity risk-management measures for entities in critical sectors; the Cyber Resilience Act adds mandatory security requirements for products with digital elements. Both frameworks make legacy authentication a documented compliance concern [@ec-nis2-directive, @ec-cyber-resilience-act]. Deprecation of NTLM under Microsoft's own deprecation page (`ms-deprecated-features`) gives a clean audit surface that did not exist before; an organisation can point to KB 5064479 audit data showing NTLM call sites with named callers and target services, and demonstrate progress on retirement [@ms-deprecated-features].

<Sidenote>The EU regulatory framing here is touched lightly because the primary texts (NIS2 Directive, Cyber Resilience Act) are extensive regulatory documents this article does not quote verbatim beyond the European Commission's official summaries. The relevant connection is operational: deprecation pages and audit logs give compliance teams an artifact for "we are retiring this class of credential under a published deprecation," which is the kind of evidence regulators ask for.</Sidenote>

All five problems converge to one question for the AD engineer reading this article: *what should I do this quarter?*

## 10. What an AD Engineer Should Do This Quarter

Six numbered actions, ordered by impact. No filler, no compliance boilerplate.

> **Note:** This is the prerequisite. Without Who/Why/Where data, Phase 3 surfaces breakage as outage. Enable the "NTLM Enhanced Logging" and "Log Enhanced Domain-wide NTLM Logs" GPOs on every domain controller and member server you operate. Subscribe to the `Applications and Services Logs > Microsoft > Windows > NTLM > Operational` channel. Identify every process that initiates NTLM, the reason `Negotiate` declined Kerberos, and the target service. Triage by call volume and criticality [@ms-kb5064479].

> **Note:** Set `LDAPClientIntegrity = 2` and `LdapEnforceChannelBinding = 2` on every domain controller. This closes SMB-to-LDAP relay regardless of whether the originating authentication was NTLM or Kerberos. KrbRelayUp's existence makes this *more* urgent post-NTLM, not less: the relay class on Kerberos uses the same un-anchored LDAP target [@gh-krbrelayup].

> **Note:** The KB 5005413 recipe is verbatim: add `<extendedProtectionPolicy policyEnforcement="Always" />` to the authentication element of the IIS virtual directory and disable plain HTTP. `/certsrv/` is the dispositive ESC8 target. Web Enrollment proxy endpoints (`/certenroll/`, `/adpolicyprovider_cep_kerberos/` and similar) are the second tier. Audit every IIS authentication endpoint in the estate and confirm `policyEnforcement="Always"` is the value, not `"None"` or `"Partial"` [@ms-kb5005413].

> **Note:** The Print Spooler service is the single highest-impact MS-RPRN coercion surface. Disabling Spooler on every server that does not actually print closes the entire `RpcRemoteFindFirstPrinterChangeNotificationEx` coercion class on those hosts. Microsoft's hardening guidance and the PrintNightmare disclosures (2021) made this an explicit recommendation [@gh-spoolsample].

> **Note:** Coercer's scan mode is the canonical defensive auditing tool: it inventories which RPC coercion methods a given server still answers. Run it against every server you operate, in scan mode. The output is a list of unauthenticated and authenticated coercion endpoints to either patch, disable, or compensate around. Treat unauthenticated endpoints (LSARPC, `\PIPE\lsarpc`) as P0 [@gh-coercer].

> **Note:** Microsoft's preferred sequence: Windows Insider flighting -> pilot non-production NTLM-off configurations -> identify hard-coded `Ntlm` SSPI calls in your in-house code -> stage Phase-3 rollout against your audit data. If you wait, the cut-over surfaces breakage as outage. If you audit, the cut-over is uneventful [@gewida-2026-disabling].

The Phase 1 audit is the load-bearing piece. Action 1 produces the data that makes Actions 2-6 prioritise correctly. The following snippet sketches the audit-event query logic an administrator would express in PowerShell -- the JavaScript runs the same logic so you can think through edge cases interactively.

<RunnableCode lang="js" title="Detect NTLM usage (PowerShell-equivalent triage logic)">{`
// Sketch of the triage logic an administrator would run against
// "Applications and Services Logs > Microsoft > Windows > NTLM > Operational"
// after enabling the KB 5064479 enhanced auditing GPOs. The point of running
// this in JavaScript is to make the rules explicit so you can think through
// edge cases without standing up a Windows event channel.

const sampleEvents = [
  { process: "C:\\\\app\\\\legacy.exe",      reason: "NoSPN",          target: "ldap/dc01.example.local", count: 142 },
  { process: "C:\\\\Program Files\\\\Backup\\\\agent.exe", reason: "ExplicitNtlm",   target: "cifs/backup02.example.local", count: 9 },
  { process: "C:\\\\Windows\\\\System32\\\\spoolsv.exe",   reason: "NoDcReach",      target: "cifs/attacker.example.local", count: 1 },
  { process: "C:\\\\Windows\\\\System32\\\\lsass.exe",     reason: "LocalAccount",   target: "host\\\\WORKGROUP-PC01",   count: 38 },
  { process: "C:\\\\Windows\\\\System32\\\\svchost.exe",   reason: "NoSPN",          target: "host/aliased.example.local", count: 7 },
];

function triage(events) {
  const out = [];
  for (const e of events) {
    let severity = "info";
    let actions = [];
    if (e.reason === "ExplicitNtlm") {
      severity = "high";
      actions.push("Fix caller: replace AcquireCredentialsHandle('Ntlm') with 'Negotiate'");
    }
    if (e.reason === "NoSPN") {
      severity = "medium";
      actions.push("Register an SPN for the target or enable IP-SPN policy");
    }
    if (e.reason === "LocalAccount") {
      severity = "medium";
      actions.push("Plan Local KDC enrollment in Phase 2 pilot");
    }
    if (/spoolsv\\.exe$/i.test(e.process) && /attacker/i.test(e.target)) {
      severity = "critical";
      actions.push("Suspicious: Spooler authenticating to non-domain UNC. Likely coercion attempt -- isolate, then disable Spooler on this host");
    }
    out.push({ process: e.process, severity, actions });
  }
  return out;
}

for (const row of triage(sampleEvents)) {
  console.log(\`[\${row.severity.toUpperCase()}] \${row.process}\`);
  for (const a of row.actions) console.log("    -> " + a);
}
`}</RunnableCode>

> **Note:** - **`LMCompatibilityLevel = 5` without audit.** Forcing NTLMv2-only on every DC is correct as an endpoint, but flipping it without first running KB 5064479 audit will outage legacy applications that still attempt NTLMv1 [@ms-lan-mgr-auth-level, @ms-kb5064479]. - **`RestrictNTLM:Deny` without exceptions.** The Restrict NTLM family of GPOs supports per-server exemptions. Going straight to `Deny` without an exemption list is the classic outage path. - **EPA on HTTPS-only while leaving plain HTTP enabled.** KB 5005413 explicitly requires *both* `policyEnforcement="Always"` and disabling plain HTTP on `/certsrv/`. Leaving HTTP up makes the EPA enforcement moot [@ms-kb5005413]. - **Trusting Credential Guard against coercion.** Credential Guard protects against credential *theft*. It does not protect against ESC8, PetitPotam, or any other relay-of-live-authentication chain [@ms-credential-guard].

<Spoiler kind="solution" label="One-line Windows Insider flighting flip for Phase 2 pilot">
On a non-production Windows 11 Insider machine, the per-machine NTLM scope policy lives under `HKLM\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0`. Microsoft's pre-release documentation will name the value used to gate the Phase 2 IAKerb / Local KDC behaviours; consult the Windows Insider release notes that ship with the Phase 2 flight rather than hard-coding a value here -- the keys are subject to change up to GA. Use the `ntlm@microsoft.com` outreach channel for any environment-specific question [@gewida-2026-disabling].
</Spoiler>

This is the work. The Phase 3 deadline is the next major Windows release; the Phase 1 audit window is right now. If you wait, the cut-over surfaces breakage as outage. If you audit, the cut-over is uneventful.

## 11. Frequently Asked Questions

<FAQ title="Frequently asked questions">

<FAQItem question="Is NTLMv2 safe to keep using?">
No. NTLMv2 is the version Drop-the-MIC, PetitPotam, and ESC8 all attack [@nvd-cve-2019-1040, @specterops-cert-preowned-blog]. The HMAC-MD5 response is strong against the response side, but the password-equivalence of the NT-hash and the lack of binding to the underlying transport are the structural properties every modern attack exploits. NTLMv2 is the *least bad* NTLM, not a safe NTLM.
</FAQItem>

<FAQItem question="Can I just disable NTLM today?">
Phase 1 controls let you *audit*. Phase 2 features (IAKerb, Local KDC, IP-SPN, the Negotiate refactor) are what make disabling *survivable* for most organisations. If you go straight to `RestrictNTLM:Deny` without running the KB 5064479 audit first, you will outage legacy applications and possibly your help-desk laptops. The honest answer is: audit now, pilot Phase 2 in H2 2026, default-off at Phase 3 [@gewida-2026-disabling, @ms-kb5064479].
</FAQItem>

<FAQItem question="Does Credential Guard fix this?">
No. Credential Guard fixes credential *theft* from LSASS. It does nothing about credential *use* (relay), coercion (PetitPotam), or cross-protocol chains (ESC8). It is necessary -- ESC8 + Mimikatz is worse than ESC8 alone -- but it is not sufficient against the relay class [@ms-credential-guard].
</FAQItem>

<FAQItem question="Does removing NTLM eliminate relay attacks?">
No. KrbRelay and KrbRelayUp demonstrate the relay *class* survives on Kerberos. What changes is the named primitives, not the existence of relay. Defence is the same shape after Phase 3 as before: LDAP signing and channel binding everywhere, EPA enforced on every authentication endpoint, message integrity required at every level [@gh-krbrelayup].
</FAQItem>

<FAQItem question="Why did Microsoft wait thirty years?">
Because the four fallback reasons (no DC, local accounts, no SPN, hard-coded NTLM) had no engineered answer until IAKerb, Local KDC, NEGOEX, and the Negotiate refactor existed in shippable form. The standards work, the IETF drafts (one of which was marked Dead WG Document in 2019 and is being revived), the MIT 1.9 parity, and the Apple precedent all had to exist before Microsoft had a credible removal path that did not break enterprise deployments [@palko-2023-evolution, @draft-ietf-kitten-iakerb].
</FAQItem>

<FAQItem question="Can Linux and macOS clients ride this transition?">
Yes. MIT Kerberos has had IAKerb since 1.9 (December 2010). Apple ships `GSS_IAKERB_MECHANISM` since macOS 10.14 (Mojave, 2018). The Samba `localkdc` effort from Bokovoy and Schneider (FOSDEM 2025) is the parallel open-source path for a Linux local KDC. Heterogeneous Windows-domain estates with Linux file servers and macOS clients are positioned to interoperate with Phase 3 *better* than they did with NTLMv2 [@fosdem-2025-localkdc-schedule, @cryptomilk-localkdc].
</FAQItem>

</FAQ>

NTLM was the answer to a 1987 problem and a 1993 problem. It survived because removing it required engineering four orthogonal capabilities that did not exist. They exist now. The next major Windows release ships without it on by default. The attacks that follow it -- KrbRelayUp, RBCD chains, S4U2Self abuse, certificate-template misconfiguration -- target a different protocol with a different vocabulary. The relay *class* persists. The protocol it targets is no longer NTLM.

If you read this article as part of a sequence, the prior pieces cover the [access-control model](https://paragmali.com/blog/can-this-code-do-this----twenty-five-years-of-attacks-on-the/) (`SeAccessCheck` and its inputs), the chip-layer credential story (TPM, [Pluton](https://paragmali.com/blog/pluton-a-tpm-on-silicon-microsoft-can-patch/), Credential Guard, BitLocker), and the [application-identity layer](https://paragmali.com/blog/who-is-this-code----the-quiet-33-year-reinvention-of-app-ide/) (Authenticode, signed binaries, AppLocker, smart application control). NTLM removal is one strand of the broader move from "trust the perimeter" to "tie every credential to a token, a chip, or a Kerberos ticket whose lifetime you can name." Each strand by itself is incomplete; together they are how the next decade of Windows authentication looks.

<StudyGuide slug="ntlmless-the-death-of-ntlm-in-windows" keyTerms={[
  { term: "LM hash", definition: "1987 LAN Manager hash. Uppercase the password, pad/truncate to 14 characters, split into two 7-byte halves, DES-encrypt KGS!@#$% with each half. Password-equivalent, case-insensitive, no salt." },
  { term: "NT-hash", definition: "MD4(UTF-16LE(password)). Sixteen bytes. The long-term secret every NTLM response derives from. Possession equals authority." },
  { term: "NTLMv2", definition: "HMAC-MD5 response over server_challenge || client_challenge || timestamp || av_pairs, keyed by NTOWFv2 = HMAC_MD5(NT-hash, UNICODE(Upper(user)||domain)). Ships in NT 4.0 SP4, October 1998." },
  { term: "SPNEGO / Negotiate", definition: "The GSS-API negotiation mechanism Windows uses to pick between Kerberos and NTLM. The Windows SSPI provider is called Negotiate." },
  { term: "MIC", definition: "Message Integrity Code -- HMAC-MD5 keyed by ExportedSessionKey over the concatenation of all three NTLM messages. Defeated by Drop-the-MIC (CVE-2019-1040)." },
  { term: "EPA / CBT", definition: "Extended Protection for Authentication / Channel Binding Token. A hash of the TLS endpoint certificate placed in the MsvAvChannelBindings AV_PAIR." },
  { term: "Pass-the-Hash", definition: "Using a stolen NT-hash directly as the credential, without ever knowing the cleartext password. First published by Paul Ashton in 1997." },
  { term: "NTLM relay", definition: "Forwarding a live NTLM exchange between a victim client and a third-party target. First public PoC: Sir Dystic's SMBRelay (March 31, 2001)." },
  { term: "Coercion", definition: "Causing a Windows service running as SYSTEM to NTLM-authenticate to an attacker-controlled destination via an RPC method that takes a UNC path. SpoolSample (2018), PetitPotam (2021), Coercer (2022)." },
  { term: "ESC8", definition: "Coerced NTLM relayed to AD CS Web Enrollment (/certsrv/), yielding a certificate that yields a TGT via PKINIT. Schroeder + Christensen, Certified Pre-Owned, June 17, 2021." },
  { term: "IAKerb", definition: "Initial and Pass Through Authentication Using Kerberos V5 and the GSS-API. Lets a client with no KDC reach proxy AS-REQ / TGS-REQ through an application server." },
  { term: "Local KDC", definition: "A small Kerberos KDC against the local SAM, exposed via IAKerb. Shipping in Windows 11 / Server 2025." },
  { term: "NEGOEX", definition: "SPNEGO Extended Negotiation. Adds a meta-data exchange inside the SPNEGO envelope so IAKerb can be negotiated under Negotiate. NOT RFC 8143 (which is NNTP+TLS); the correct primaries are [MS-NEGOEX] and draft-zhu-negoex." }
]} />
