Securing AD CS web enrollment against ESC8 and ESC11
Close NTLM relay to AD CS: find HTTP enrollment endpoints, enforce HTTPS and EPA, disable NTLM, remove Web Enrollment and enforce RPC encryption.
ESC8 is the reason PetitPotam became a domain-takeover technique rather than a curiosity. An attacker coerces a domain controller into authenticating over NTLM, relays that authentication to the CA's HTTP enrollment page, and receives a certificate issued to the domain controller's own computer account. That certificate authenticates via PKINIT as the DC, which is enough to request replication data. No template is misconfigured, and no password is guessed; the flaw is that the CA accepts NTLM over a channel that does not bind authentication to the session (see the ESC8 glossary entry). ESC11 is the same idea against the CA's RPC enrollment interface when request encryption is not enforced.
This guide covers the enrollment surface in depth: finding every HTTP and RPC endpoint that issues certificates, deciding which ones should exist at all, and hardening the rest with HTTPS, Extended Protection for Authentication (EPA), NTLM removal and IF_ENFORCEENCRYPTICERTREQUEST. It complements the ESC overview in the AD CS hardening pillar and the wider relay controls in Stop NTLM relay.
Measure: find every enrollment endpoint
AD CS can expose four enrollment paths. Only the first is always present:
| Endpoint | Role service | Transport | Relay class |
|---|---|---|---|
MS-ICPR / DCOM (ICertPassage, ICertRequest) | Certification Authority | RPC | ESC11 if encryption not enforced |
/certsrv | Certification Authority Web Enrollment (ADCS-Web-Enrollment) | HTTP/HTTPS | ESC8 |
| Certificate Enrollment Web Service (CES) | ADCS-Enroll-Web-Svc | HTTPS | ESC8 with Windows Integrated auth |
Network Device Enrollment Service (/certsrv/mscep) | ADCS-Device-Enrollment | HTTP/HTTPS | Separate risk, same hardening |
Start with what is installed on each CA and enrollment server:
# Run on each CA / enrollment web server
Get-WindowsFeature ADCS-* | Where-Object Installed | Select-Object Name, DisplayName
# Enterprise CAs and any CES URIs published in AD
$pks = "CN=Public Key Services,CN=Services,$((Get-ADRootDSE).configurationNamingContext)"
Get-ADObject -SearchBase "CN=Enrollment Services,$pks" -LDAPFilter '(objectClass=pKIEnrollmentService)' `
-Properties dNSHostName, msPKI-Enrollment-Servers |
Select-Object Name, dNSHostName, @{n='CES';e={$_.'msPKI-Enrollment-Servers' -join '; '}}Then check what each web endpoint actually offers. From a domain-joined admin workstation in Windows PowerShell 5.1, an unauthenticated request returns the authentication schemes in the WWW-Authenticate header. NTLM or Negotiate over plain HTTP is the worst case.
foreach ($url in 'http://ca01.corp.example/certsrv/','https://ca01.corp.example/certsrv/') {
try { Invoke-WebRequest -Uri $url -UseBasicParsing -ErrorAction Stop | Out-Null; "$url -> anonymous 200" }
catch { "$url -> $($_.Exception.Response.StatusCode) $($_.Exception.Response.Headers['WWW-Authenticate'])" }
}Finally, measure use. If the IIS logs show no legitimate hits to /certsrv in 90 days, you are not hardening the endpoint, you are deleting it.
Get-ChildItem 'C:\inetpub\logs\LogFiles\W3SVC1\*.log' |
Where-Object LastWriteTime -gt (Get-Date).AddDays(-90) |
Select-String -Pattern ' /certsrv' |
ForEach-Object { ($_.Line -split ' ')[8] } | # c-ip column in the default W3C field order
Group-Object | Sort-Object Count -Descending | Select-Object -First 20 Count, NameConfirm the column index against the #Fields: header of your log files before trusting the client IP column.
Decide per endpoint
Classify each endpoint before changing anything. An endpoint with no legitimate traffic is removed. An endpoint used only by domain-joined Windows clients can usually move to RPC-based autoenrollment and then be removed. An endpoint that serves non-domain devices, partner forests or appliances stays, and gets the full HTTPS, EPA and Kerberos-only treatment below. CES deserves its own note: it can be configured with Windows Integrated, username and password, or client certificate authentication. Only the Windows Integrated variant is relayable in the ESC8 sense, but username and password authentication exposes a password prompt to anything that can reach the service, so prefer certificate authentication for renewal scenarios. NDES is not an ESC8 target in the same way, since it issues certificates based on a challenge password rather than the caller's Windows identity, but it runs on the same IIS stack and deserves the same HTTPS and exposure review.
Enforce option 1: remove Web Enrollment
The legacy certsrv pages exist mainly for manual requests from browsers. Group Policy autoenrollment uses RPC/DCOM, not certsrv, so most domain-joined workflows are unaffected by removing it. If the usage data allows, uninstall it:
# On the server hosting Web Enrollment
Uninstall-AdcsWebEnrollment -Force
Uninstall-WindowsFeature ADCS-Web-EnrollmentIf the CA server also has IIS for no other reason, remove the Web Server role too, which shrinks the attack surface of a Tier 0 host. Do the same review for CES and NDES: if nothing consumes them, remove them.
Enforce option 2: HTTPS, EPA and no NTLM
When an endpoint must stay, harden it in three layers. Authentication sections in IIS are locked at server level by default, so write the settings to applicationHost.config with a location path rather than to the site's web.config.
Import-Module WebAdministration
$loc = 'Default Web Site/CertSrv'
# 1. Require TLS
Set-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' -Location $loc `
-Filter 'system.webServer/security/access' -Name sslFlags -Value 'Ssl'
# 2. Require Extended Protection for Authentication (channel binding)
Set-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' -Location $loc `
-Filter 'system.webServer/security/authentication/windowsAuthentication' `
-Name 'extendedProtection.tokenChecking' -Value 'Require'
# 3. Offer Kerberos only: remove the NTLM provider, keep Negotiate
Remove-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' -Location $loc `
-Filter 'system.webServer/security/authentication/windowsAuthentication/providers' `
-Name '.' -AtElement @{ value = 'NTLM' }Also remove the plain HTTP binding from the site (or at least from the enrollment virtual directories) so nothing falls back to port 80. Removing the NTLM provider string alone does not stop NTLM inside Negotiate; Negotiate can still fall back to NTLM. To remove NTLM completely, block it at the operating system level on the enrollment server, after auditing:
- Computer Configuration > Policies > Windows Settings > Security Settings > Local Policies > Security Options > Network security: Restrict NTLM: Audit Incoming NTLM Traffic = Enable auditing for all accounts
- After a clean audit period: Network security: Restrict NTLM: Incoming NTLM traffic = Deny all accounts
Audit events land in Applications and Services Logs > Microsoft > Windows > NTLM > Operational (event 8002 for incoming NTLM). The step-by-step method is in auditing and restricting NTLM.
For CES, Microsoft's ESC8 advisory (KB5005413) additionally asks you to enable EPA in the service's own web.config, typically under C:\Windows\SystemData\CES\<CA name>_CES_Kerberos\, by setting extendedProtectionPolicy policyEnforcement="Always" on the transport security element, alongside the IIS setting. Where a load balancer terminates TLS in front of CES or certsrv, EPA cannot work because the client's channel binding token refers to the balancer's certificate; either pass TLS through to IIS or do not publish the endpoint through that balancer.
Enforce: RPC request encryption (ESC11)
The MS-ICPR interface used by certreq and some clients accepts requests without packet privacy unless the CA's IF_ENFORCEENCRYPTICERTREQUEST interface flag is set. Check every CA:
certutil -config "ca01.corp.example\CORP-Issuing-CA" -getreg CA\InterfaceFlagsIf IF_ENFORCEENCRYPTICERTREQUEST is missing from the output, set it and restart the service:
certutil -config "ca01.corp.example\CORP-Issuing-CA" -setreg CA\InterfaceFlags +IF_ENFORCEENCRYPTICERTREQUEST
Restart-Service certsvc # run on the CAThe flag is enabled by default on current CA installations. When it is missing, the usual reason is a past troubleshooting change for a legacy client, so find out which client before assuming it is safe to set.
Reduce the coercion side
EPA and NTLM removal break the relay target; also shrink the supply of coerced authentications. Disable the Print Spooler on domain controllers, apply the EFSRPC and RPC filter mitigations for PetitPotam-style coercion, and block outbound SMB and HTTP from DCs to anything that is not another Tier 0 system. These controls are covered in blocking authentication coercion and domain controller firewalling.
Verify
Read back the IIS configuration for each virtual directory you hardened:
$loc = 'Default Web Site/CertSrv'
Get-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' -Location $loc `
-Filter 'system.webServer/security/access' -Name sslFlags
Get-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' -Location $loc `
-Filter 'system.webServer/security/authentication/windowsAuthentication' -Name 'extendedProtection.tokenChecking'
Get-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' -Location $loc `
-Filter 'system.webServer/security/authentication/windowsAuthentication/providers' -Name '.' |
Select-Object -ExpandProperty Collection | Select-Object valueExpected: Ssl, Require, and only Negotiate (or Negotiate:Kerberos) in the providers list. Rerun the WWW-Authenticate probe from the Measure step: the HTTP URL should no longer answer, and the HTTPS URL should not advertise NTLM. Rerun certutil -getreg CA\InterfaceFlags on every CA, and confirm Locksmith or your own checks no longer flag ESC8 or ESC11.
On the CA, keep auditing issuance (events 4886 and 4887) and alert when a certificate is issued to a domain controller computer account from any template other than your domain controller authentication template, or from a requester that is not the DC itself. That alert catches a relay that slips through a forgotten endpoint.
What it breaks
- Removing Web Enrollment: manual browser-based requests, some Linux and macOS enrollment scripts, and appliances that scrape the
certsrvpages stop working. Give those userscertreqon a domain-joined host, a dedicated template requested through a controlled service, or a proper ACME/SCEP front end. - Requiring EPA: clients and proxies that do not support channel binding fail with HTTP 401. TLS-terminating load balancers and some reverse proxies are the common case; older third-party HTTP clients are the other.
- Removing NTLM: requests from non-domain-joined machines, from clients that reach the CA by IP address or by a name without a matching SPN, and from cross-forest clients without a Kerberos path all fail. Register the SPN for any alias you use (
HTTP/pki.corp.exampleon the application pool identity). IF_ENFORCEENCRYPTICERTREQUEST: very old clients (Windows XP and Server 2003 era) and some third-party tools that call MS-ICPR without packet privacy cannot enroll over RPC.- Disabling the spooler on DCs: print pruning of published printers stops; nothing else on a DC should depend on it.
Related reading: the AD Certificate Services topic hub, the NTLM relay glossary entry, and LDAP signing and channel binding for the equivalent relay protection on domain controllers.
Frequently asked questions
Does strong certificate mapping stop ESC8?
No. In an ESC8 relay the attacker obtains a certificate for the account whose authentication was relayed, for example a domain controller computer account. The CA puts that account's genuine SID in the certificate, so the certificate is strongly mapped and passes KB5014754 enforcement. Only removing the relayable endpoint, or binding authentication to the TLS channel with EPA and removing NTLM, closes the path.
Is HTTPS alone enough to protect certsrv?
No. HTTPS protects the traffic in transit but does not stop a relay: the attacker simply opens their own TLS session to the CA and forwards the NTLM exchange through it. Extended Protection for Authentication is what ties the NTLM or Kerberos exchange to the specific TLS channel, which makes a relayed authentication fail. You need HTTPS and EPA together, or no NTLM at all.
What does IF_ENFORCEENCRYPTICERTREQUEST protect?
It makes the CA reject certificate requests submitted over the MS-ICPR RPC interface unless the RPC call uses packet privacy (encryption). Without it, NTLM authentication to the RPC enrollment interface can be relayed, which is the ESC11 class. The flag is on by default on current Windows Server CAs, but administrators sometimes remove it to support old clients, so verify it on every CA.
Securing AD CS web enrollment against ESC8 and ESC11