AD CS
ESC8
WEB ENROLLMENT
NTLM RELAY
DetectionBlue TeamSOCOctober 12, 2026•9 min read

Detecting AD CS ESC8: NTLM Relay to Web Enrollment

ESC8 turns a coerced Domain Controller authentication into a certificate for that Domain Controller. The relay leaves a web log entry with the wrong IP on it.

Scroll

When AD CS web enrollment or the enrollment web services accept NTLM over HTTP without Extended Protection, an attacker can relay a coerced machine authentication to the CA and request a certificate in the victim’s name. That certificate then authenticates to Kerberos through PKINIT. The IIS log and the CA log both record the relay, which makes it detectable if you collect them.

Signals at a Glance

SignalWhereATT&CK
POST to /certsrv/certfnsh.asp authenticated as a machine account from another IPIIS W3C logs on CAT1557.001
Certificate issued for a DC or machine template to a non-DC requester IPCA 4887, IIST1649
PKINIT TGT for a machine account from an IP that is not that machineDC Security 4768T1649
Coercion RPC against a DC shortly before the enrollment requestSecurity 5145, networkT1187
Web enrollment reachable over HTTP with NTLM and no EPAConfig auditT1557.001

IIS and CA Evidence

Web enrollment requests are POSTs to /certsrv/certfnsh.asp; the enrollment web services use their own URLs. IIS logs the authenticated username and the client IP, so a machine account such as DC01$ arriving from a workstation range is a direct indicator. Collect W3C logs from every CA that runs web enrollment:

index=iis sourcetype="ms:iis:auto" cs_method=POST
    (cs_uri_stem="/certsrv/certfnsh.asp" OR cs_uri_stem="*/service.svc*")
| rex field=cs_username "^(?<dom>[^\\\\]+)\\\\(?<acct>.+)$"
| where match(acct, "\\$$")
| lookup asset_inventory hostname AS acct_host OUTPUT ip AS expected_ip
| where isnull(expected_ip) OR expected_ip!=c_ip
| table _time, host, cs_username, c_ip, cs_uri_stem, sc_status
# tune/validate: build acct_host from acct (strip the $); the field names
# and the escaping of backslashes depend on your IIS input and Splunk version.

Any machine-account request through web enrollment is worth a look, because machines normally enroll over RPC or DCOM with auto-enrollment. Add the CA record by request ID so the analyst sees the template and the result in one row:

SecurityEvent
| where EventID == 4887 and Computer has "CA"   // tune/validate: your CA hostnames
| extend d = parse_xml(EventData).EventData.Data
| mv-apply item = d on (
    summarize kv = make_bag(bag_pack(tostring(item["@Name"]), tostring(item["#text"]))))
| where tostring(kv.Requester) endswith "$"
| where tostring(kv.Attributes) has_any ("DomainController", "Machine", "KerberosAuthentication")
| project TimeGenerated, Computer, Requester = tostring(kv.Requester),
          Attributes = tostring(kv.Attributes), RequestId = tostring(kv.RequestId)

Follow-On and Hardening

A relayed certificate is only useful once it is used. For a domain controller, that usually means PKINIT logon followed by directory replication. Chain the two so a single alert shows the whole path:

Vetted sources

Use SpecterOps Certified Pre-Owned research for the ESC8 mechanism, the SigmaHQ and Elastic AD CS rules, Splunk ESCU certificate analytics and Microsoft’s guidance on EPA for AD CS. Baseline your own environment — some device-enrollment flows legitimately use web enrollment, and those IP ranges should be named exceptions.

Build Detections That Fire

Mjolnir Security helps blue teams turn threat intelligence into high-fidelity detections across endpoint, network, identity and cloud telemetry.

Detection EngineeringManaged Detection & ResponseThreat HuntingIncident ResponsePurple Teaming
  • Detection Engineering We build and tune detections mapped to ATT&CK from your own telemetry.
  • Threat Hunting as a Service Hypothesis-driven hunts for the behaviours on this page.
  • 24/7 Incident Response Containment when a detection fires. Call +1 833 403 5875.
Written by: Mjolnir Threat Research (MTAC)  |  Published: October 12, 2026  |  Last reviewed: October 12, 2026