ADCS-012: ESC9 - No Security Extension

Platform
Active Directory
Category
AD Certificate Services
Severity
High
Zero Trust pillar
Identity (weight 3)
Golden fixtures
2
Branch coverage
Observed: fixtures prove the verdicts they exercise
Provenance
baseline

What it checks

The check performs two parallel evaluations. First, on the AD side it enumerates every pKICertificateTemplate object under CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=<forest>, reads msPKI-Enrollment-Flag, and tests the CT_FLAG_NO_SECURITY_EXTENSION bit (0x00080000). Templates with that bit set and with pKIExtendedKeyUsage containing an authentication EKU (Client Authentication 1.3.6.1.5.5.7.3.2, Smart Card Logon 1.3.6.1.4.1.311.20.2.2, PKINIT Client Authentication 1.3.6.1.5.2.3.4, or the catch-all Any Purpose 2.5.29.37.0) are flagged as ESC9 candidates. The check also captures msPKI-Certificate-Name-Flag for the CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT bit (0x00000001) and the template DACL via nTSecurityDescriptor to identify which principals can enroll. Second, on every domain controller Guerrilla reads HKLM\SYSTEM\CurrentControlSet\Services\Kdc\StrongCertificateBindingEnforcement and HKLM\SYSTEM\CurrentControlSet\Services\Kdc\CertificateMappingMethods. A value of 0 (Disabled) or 1 (Compatibility) on StrongCertificateBindingEnforcement combined with any flagged template constitutes a confirmed ESC9 path.

Why it matters

ESC9 is a pre-authentication identity substitution attack. Unlike ESC1, it does not require the SAN (Subject Alternative Name) to be enrollee-supplied in the request, and unlike ESC6 it does not require EDITF_ATTRIBUTESUBJECTALTNAME2 on the CA. The only prerequisite on the attacker side is GenericWrite (or any right that permits modifying userPrincipalName) on a single victim account, a primitive that is widely available in real environments via stale delegations, help-desk groups, self-service password reset tooling, and Exchange permissions. The blast radius is the entire forest: the attacker can target the krbtgt account UPN (which is empty by default and therefore writable in some configurations), any Tier 0 service account, or a Domain Admin. Microsoft addressed the underlying certificate-mapping weakness in KB5014754 (May 2022) by introducing the szOID_NTDS_CA_SECURITY_EXT extension and the StrongCertificateBindingEnforcement registry control, but Full Enforcement (value 2) was not made mandatory by default and the original phased rollout has been repeatedly delayed. As of February 2025 Microsoft moved enforcement to mandatory; environments running older DCs or with the registry value explicitly downgraded to 1 remain vulnerable.

Attack path

Step 1: Reconnaissance. The attacker, holding any low-privilege foothold, runs Certipy find -vulnerable or runs ADCS-012 to list templates that have CT_FLAG_NO_SECURITY_EXTENSION set and that the current principal can enroll in. Concurrently the attacker queries each DC for the StrongCertificateBindingEnforcement value (reg query \\DC01\HKLM\SYSTEM\CurrentControlSet\Services\Kdc) or infers it from KB5014754 build numbers. Step 2: ACL discovery. The attacker uses BloodHound to find an account they have GenericWrite or GenericAll over. The victim does not need to be privileged; only the eventual target (the UPN the attacker will impersonate) must be. Step 3: UPN swap. The attacker reads the current userPrincipalName of the victim and saves it. They then set userPrincipalName on the victim to the sAMAccountName of the target (for example "administrator" without @domain suffix, since the krbtgt account has an empty UPN and would otherwise collide). Set-ADUser -Identity victim -UserPrincipalName "administrator". Step 4: Enrollment. From the victim account context, the attacker requests a certificate from the vulnerable template. Certipy req -u victim@contoso.local -p Password -ca CONTOSO-CA -template VulnerableTemplate. Because CT_FLAG_NO_SECURITY_EXTENSION is set, the issued certificate contains no SID extension; the subject identity is carried only via UPN. Step 5: UPN restore. The attacker reverts userPrincipalName on the victim to the original value, hiding the modification from naive monitoring. Step 6: PKINIT. The attacker presents the certificate to the KDC via Certipy auth -pfx victim.pfx. The KDC, running with StrongCertificateBindingEnforcement below 2, performs UPN-based mapping, matches the UPN in the certificate to the target (now reverted) account, and issues a TGT for that account. The attacker has fully impersonated the higher-privileged identity, typically Domain Admin or a service account with Tier 0 reach.

How Guerrilla assesses it

Guerrilla binds to the Configuration naming context over LDAP and enumerates every (objectClass=pKICertificateTemplate) object under CN=Certificate Templates,CN=Public Key Services,CN=Services. For each template it pulls msPKI-Enrollment-Flag and tests for the 0x00080000 bit (CT_FLAG_NO_SECURITY_EXTENSION). Templates passing that filter are cross-checked against pKIExtendedKeyUsage for an authentication-capable OID set, and the nTSecurityDescriptor is parsed to surface which non-default principals hold Certificate-Enrollment or AutoEnroll extended rights (1.3.6.1.4.1.311.21.13 / 1.3.6.1.4.1.311.21.10). The check then connects to each domain controller over remote registry or WinRM and reads HKLM\SYSTEM\CurrentControlSet\Services\Kdc\StrongCertificateBindingEnforcement and CertificateMappingMethods. A finding is raised when at least one template carries the no-security-extension flag and at least one DC reports StrongCertificateBindingEnforcement value of 0 or 1. The check also captures the published-on CA via the msPKI-Cert-Template-OID join against pKIEnrollmentService objects so the operator knows where to revoke or republish.

Recommended value

StrongCertificateBindingEnforcement set to 2 on all domain controllers; CT_FLAG_NO_SECURITY_EXTENSION not set on authentication templates

Remediation

Check for templates with CT_FLAG_NO_SECURITY_EXTENSION (0x80000) in msPKI-Enrollment-Flag. Remove this flag from all authentication-capable templates. Set the registry value StrongCertificateBindingEnforcement to 2 under HKLM\SYSTEM\CurrentControlSet\Services\Kdc on all domain controllers to enforce strong certificate mapping. Test certificate-based authentication after enabling enforcement.

Fixture-proven verdicts

Every verdict below is proven by a golden fixture in the module's gating test suite. This table derives from the last green run; it cannot be edited by hand.

Verdict scenarios for ADCS-012
ScenarioExpected verdict
compat-modeWARN
throttledNot Assessed

Framework mappings

NIST SP 800-53
IA-5(2), CM-6, AC-6
ANSSI
vuln_adcs_esc9
MITRE ATT&CK
T1649, T1098