Concept: ADCS is Microsoft’s PKI role for Active Directory — it lets a domain-joined Certification Authority (CA) issue X.509 certificates to users and computers for things like smart-card logon, TLS, and code signing. The security-relevant part: a certificate that maps to a domain identity is an alternate credential for that identity — anyone who can get one issued to them for Administrator can authenticate as Administrator, no password or hash needed. Almost every ADCS attack is really “how do I get a certificate issued for an identity that isn’t mine.”
Impact: Misconfigured certificate templates or CA settings routinely let a low-privileged, even unauthenticated-adjacent user request a certificate that authenticates as Domain Admin — this is the “ESC” (Escalation) family cataloged by SpecterOps’ original research and kept current by Certipy.
How it works
A Certificate Template defines what a requester is allowed to put into their certificate request and what the CA will sign — subject name source, allowed Extended Key Usages (EKUs), who’s allowed to enroll, and whether a manager has to approve it first.
A client sends a Certificate Signing Request (CSR) to the CA (over RPC/ICertPassage, DCOM, or a web enrollment endpoint) referencing a template.
If the requester is in the template’s enrollment permissions and the request fits the template’s rules, the CA signs it and returns a certificate binding a public key to whatever identity/UPN/SAN ended up in the cert.
That certificate is now usable for Kerberos PKINIT — present it to the KDC and get back a TGT for whichever identity it’s bound to, exactly as if that identity’s password had been used.
Security Quirks & Niche Facts
The ESC catalog is a checklist, not a single bug — each ESCn name (ESC1 through ESC16 as of Certipy’s current coverage) is a distinct misconfiguration that produces the same outcome (attacker-controlled certificate for a privileged identity) through a different mechanism. The most commonly seen ones:
A cert meant for one purpose (e.g. code signing) can be reused for client auth
—
ESC3
Template has the “Certificate Request Agent” EKU
Lets the holder enroll on behalf of another user (like an RA)
—
ESC4
Low-priv principal has write access to the template object itself
Rewrite the template’s own settings to make it vulnerable to ESC1, then request
—
ESC6
CA has the EDITF_ATTRIBUTESUBJECTALTNAME2 flag set
Any template accepts an attacker-supplied SAN, globally
—
ESC8
Web enrollment (HTTP) endpoint is enabled
Coerce/relay a machine account’s NTLM auth into a certificate request over HTTP
—
ESC9
Template has CT_FLAG_NO_SECURITY_EXTENSION set (no szOID_NTDS_CA_SECURITY_EXT)
The issued cert carries no strong (SID-backed) mapping — change the target user’s UPN to the victim’s name first, request, then the cert authenticates as whoever currently owns that UPN
Template is V1 schema and allows requester-supplied application policy
Inject a client-auth application policy into a template that was never meant to allow it
—
Shadow Credentials aren’t an “ESC” but they’re the ADCS-adjacent attack that shows up just as often: any principal with write access to a target’s msDS-KeyCredentialLink attribute can attach an attacker-generated certificate as a valid login credential for that target directly, no vulnerable CA template required at all. See Active Directory - Shadow Credentials Attack.
StrongCertificateBindingEnforcement (a DC registry setting, not a CA setting) governs how strictly the KDC checks that a certificate’s identity matches the requesting account when there’s no strong SID mapping — this is exactly the setting ESC9/ESC10 exploit gaps in.
Certipy is the standard tool for both enumerating (find -vulnerable) and exploiting (req, shadow, account update) all of the above — treat a certipy-ad find -vulnerable run as mandatory the moment ADCS shows up in a port scan (LDAP + a CA name, or port 80/443 web enrollment on the CA host).
ADCS attacks compose with ordinary ACL abuse: several ESC paths (ESC4, Shadow Credentials against a template/account) start from a plain GenericWrite/GenericAll found the same way as Active Directory - ACL Abuse (GenericAll & ForceChangePassword) — ADCS is often the payoff of a BloodHound path, not a separate starting point.
Mitigation
Fix 1: Run certipy-ad find -vulnerable (or equivalent) against your own CA periodically — template misconfigurations accumulate the same way ACL over-permissioning does, and there’s no built-in warning when one is introduced.
Fix 2: Enable StrongCertificateBindingEnforcement domain-wide and prefer templates whose Certificate Name Flag does not include CT_FLAG_NO_SECURITY_EXTENSION.
Fix 3: Restrict template enrollment rights and template-object write rights to the minimum groups that actually need them — most ESC paths still require some enrollment or write permission as a starting point.