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
| Signal | Where | ATT&CK |
|---|---|---|
| POST to /certsrv/certfnsh.asp authenticated as a machine account from another IP | IIS W3C logs on CA | T1557.001 |
| Certificate issued for a DC or machine template to a non-DC requester IP | CA 4887, IIS | T1649 |
| PKINIT TGT for a machine account from an IP that is not that machine | DC Security 4768 | T1649 |
| Coercion RPC against a DC shortly before the enrollment request | Security 5145, network | T1187 |
| Web enrollment reachable over HTTP with NTLM and no EPA | Config audit | T1557.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:
- Alert on a 4768 with pre-authentication type 16 for a
$account from an IP that does not match the asset record, then look for 4662 replication GUIDs (see the DCSync page). - Look for coercion shortly before the enrollment request: Event 5145 to
efsrpc,spoolssornetdfson a DC. - Require HTTPS and Extended Protection for Authentication on the CA web enrollment site, or disable the web enrollment role where it is not needed.
- Disable NTLM on the CA IIS site and prefer Kerberos; remove unused enrollment web services.
- Restrict the DomainController and Machine templates so only the right principals can enroll.
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 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.
Stay ahead of emerging threats. Get notified when we publish new intelligence reports and advisories.
Subscribe to Alerts