Skip to content
HackIndex logo

HackIndex

ADCS Misconfiguration Discovery

7 min read Jun 11, 2026

Active Directory Certificate Services misconfigurations are among the most impactful privilege escalation paths in modern AD environments. Vulnerable certificate templates allow low-privileged users to request certificates on behalf of other accounts, including Domain Admins. Several escalation paths exist depending on template and CA configuration — these are catalogued as ESC1 through ESC8.

This page covers detection only. For how to abuse confirmed findings see ADCS Exploitation.

Confirm ADCS is deployed

Before running any template enumeration, confirm a Certificate Authority is present in the environment. If no CA exists, ADCS-based techniques including Shadow Credentials will not work.

┌──(kali㉿kali)-[~]
└─$ # nxc — check for ADCS via LDAP
┌──(kali㉿kali)-[~]
└─$ nxc ldap $TARGET_IP -u $USER -p $PASSWORD -M adcs
 
┌──(kali㉿kali)-[~]
└─$ # BloodyAD — query CA objects directly
┌──(kali㉿kali)-[~]
└─$ bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP get search --filter '(objectClass=pKIEnrollmentService)' --attr cn dNSHostName
LDAP  10.10.10.10  389  DC01  [+] Found PKI Enrollment Services
LDAP  10.10.10.10  389  DC01  CA Name: corp-DC01-CA
LDAP  10.10.10.10  389  DC01  DNS Hostname: dc01.corp.local

Certipy — full ADCS enumeration

Certipy is the primary tool for ADCS enumeration. The find command queries all certificate templates and CA settings, then flags vulnerable configurations with an ESC identifier. The -vulnerable flag filters output to only show confirmed misconfigurations.

┌──(kali㉿kali)-[~]
└─$ # Full enumeration — saves output to JSON and text
┌──(kali㉿kali)-[~]
└─$ certipy find -u $USER@$DOMAIN -p $PASSWORD -dc-ip $TARGET_IP
 
┌──(kali㉿kali)-[~]
└─$ # Filter to vulnerable templates and CA settings only
┌──(kali㉿kali)-[~]
└─$ certipy find -u $USER@$DOMAIN -p $PASSWORD -dc-ip $TARGET_IP -vulnerable
 
┌──(kali㉿kali)-[~]
└─$ # Pass-the-Hash
┌──(kali㉿kali)-[~]
└─$ certipy find -u $USER@$DOMAIN -hashes :$NTHASH -dc-ip $TARGET_IP -vulnerable
 
┌──(kali㉿kali)-[~]
└─$ # Kerberos authentication
┌──(kali㉿kali)-[~]
└─$ certipy find -u $USER@$DOMAIN -k -dc-ip $TARGET_IP -vulnerable
 
┌──(kali㉿kali)-[~]
└─$ # Output to stdout only
┌──(kali㉿kali)-[~]
└─$ certipy find -u $USER@$DOMAIN -p $PASSWORD -dc-ip $TARGET_IP -vulnerable -stdout
Certificate Templates
  Template Name: UserAuthentication
  Enabled: True
  Client Authentication: True
  Enrollee Supplies Subject: True
  Certificate Authorities: corp-DC01-CA
  Permissions
    Enrollment Permissions
      Enrollment Rights: CORP.LOCAL\Domain Users
  [!] Vulnerabilities
    ESC1: 'CORP.LOCAL\Domain Users' can enroll, enrollee supplies subject and template allows client authentication

ESC1 — enrollee supplies subject

ESC1 is the most common and most directly exploitable ADCS misconfiguration. It requires three conditions to be true simultaneously on the same template. Each condition must be confirmed before attempting exploitation.

  • The template allows Client Authentication (EKU includes Smart Card Logon, Client Authentication, or PKINIT)

  • The template allows the enrollee to supply the Subject Alternative Name (CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT is set)

  • Low-privileged users or Domain Users have Enrollment rights on the template

When all three are true, any domain user can request a certificate for an arbitrary UPN — including a Domain Admin — and use it to obtain a TGT as that account.

ESC4 — write access on template

ESC4 exists when a low-privileged account has write access on a certificate template object. This does not directly enable certificate abuse, but it allows modifying the template to introduce ESC1 conditions. Certipy flags this when WriteDacl, WriteOwner, or WriteProperty exists on a template for Domain Users or similar principals.

ESC8 — NTLM relay to AD CS HTTP endpoint

ESC8 is present when the CA's web enrollment interface is running over HTTP without Extended Protection for Authentication enabled. This allows an NTLM relay attack against the enrollment endpoint to request a certificate on behalf of any coerced account. The CA web enrollment endpoint is typically at http://<CA_HOST>/certsrv.

┌──(kali㉿kali)-[~]
└─$ # Check if CA web enrollment is running over HTTP
┌──(kali㉿kali)-[~]
└─$ curl -I http://$CA_HOST/certsrv/
 
┌──(kali㉿kali)-[~]
└─$ # nxc — check for web enrollment
┌──(kali㉿kali)-[~]
└─$ nxc ldap $TARGET_IP -u $USER -p $PASSWORD -M adcs
 
┌──(kali㉿kali)-[~]
└─$ # Certipy flags ESC8 automatically in find output
┌──(kali㉿kali)-[~]
└─$ certipy find -u $USER@$DOMAIN -p $PASSWORD -dc-ip $TARGET_IP -vulnerable -stdout | grep -A5 ESC8
Certificate Authorities
  CA Name: corp-DC01-CA
  DNS Name: dc01.corp.local
  Web Enrollment: Enabled
  [!] Vulnerabilities
    ESC8: Web Enrollment is enabled and Request Disposition is set to Issue

ESC2 — Any Purpose EKU or no EKU defined on a template with low-privilege enrollment rights. Functions like ESC1 but the certificate can be used for any purpose.
ESC3 — Template has Certificate Request Agent EKU and a second template allows enrollment on behalf of another user. Allows enrolling as any user through a two-step process.
ESC5 — Write access on the CA object in AD (pKIEnrollmentService or certificationAuthority). Allows enabling disabled templates, adding enrollment officers, or modifying CA flags.
ESC6 — CA has EDITF_ATTRIBUTESUBJECTALTNAME2 flag set, allowing any template to accept a custom SAN regardless of template settings — functions like ESC1 domain-wide.
ESC7 — Low-privileged account has ManageCA or ManageCertificates rights on the CA, allowing modification of CA settings or approval of pending requests.

┌──(kali㉿kali)-[~]
└─$ # Certipy catches these automatically — check find output
┌──(kali㉿kali)-[~]
└─$ certipy find -u $USER@$DOMAIN -p $PASSWORD -dc-ip $TARGET_IP -vulnerable -stdout | grep -E 'ESC6|ESC7|EDITF_ATTRIBUTESUBJECTALTNAME2|ManageCA'
 
┌──(kali㉿kali)-[~]
└─$ # Manual CA flag check via BloodyAD
┌──(kali㉿kali)-[~]
└─$ bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP get search --filter '(objectClass=certificationAuthority)' --attr name flags
[!] Vulnerabilities
    ESC6: CA has EDITF_ATTRIBUTESUBJECTALTNAME2 flag set

Any confirmed ESC finding is directly exploitable. ESC1 is a single-command escalation to Domain Admin. ESC8 requires coercion and relay but works in environments where no template misconfiguration exists. For exploitation steps see ADCS Exploitation, ADCS ESC2/3/5/7, and ADCS ESC9/10.

ESC9 — CT_FLAG_NO_SECURITY_EXTENSION

ESC9 is present when a template has CT_FLAG_NO_SECURITY_EXTENSION set in its enrollment flags, meaning certificates issued from it do not embed the szOID_NTDS_CA_SECURITY_EXT extension that binds the cert to the issuing AD account. Without this extension, Kerberos PKINIT maps the certificate purely by its UPN. If StrongCertificateBindingEnforcement on the DC is not set to 2 (full enforcement), a certificate with any UPN will authenticate as that account.

Exploitation requires GenericWrite on a domain account to modify its UPN before requesting the certificate.

┌──(kali㉿kali)-[~]
└─$ # Certipy auto-detects ESC9 in find output
┌──(kali㉿kali)-[~]
└─$ certipy find -u $USER@$DOMAIN -p $PASSWORD -dc-ip $TARGET_IP -vulnerable -stdout | grep -A8 ESC9
 
┌──(kali㉿kali)-[~]
└─$ # Check StrongCertificateBindingEnforcement on DC
┌──(kali㉿kali)-[~]
└─$ # 0 = disabled, 1 = audit mode, 2 = full enforcement (not vulnerable)
┌──(kali㉿kali)-[~]
└─$ nxc smb $TARGET_IP -u $USER -p $PASSWORD -x 'reg query HKLM\SYSTEM\CurrentControlSet\Services\Kdc /v StrongCertificateBindingEnforcement'
[!] Vulnerabilities
    ESC9: Template 'VulnerableUserAuth' has 'CT_FLAG_NO_SECURITY_EXTENSION' flag and
          'StrongCertificateBindingEnforcement' is not set to 2

HKLM\SYSTEM\CurrentControlSet\Services\Kdc
    StrongCertificateBindingEnforcement    REG_DWORD    0x1
PS C:\Users\Guest\Desktop> # Check binding enforcement on DC (run on DC or via PSRemoting)
PS C:\Users\Guest\Desktop> reg query HKLM\SYSTEM\CurrentControlSet\Services\Kdc /v StrongCertificateBindingEnforcement
PS C:\Users\Guest\Desktop> # 0 = disabled (vulnerable), 1 = audit (vulnerable), 2 = enforced (safe)
 
PS C:\Users\Guest\Desktop> # Check template flag via certutil
PS C:\Users\Guest\Desktop> certutil -template | Select-String -Pattern 'CT_FLAG_NO_SECURITY_EXTENSION|msPKI-Enrollment-Flag'

ESC10 — weak certificate mapping

ESC10 covers two conditions where the DC uses legacy certificate-to-account mapping that an attacker can exploit:

  • ESC10a: StrongCertificateBindingEnforcement = 0 on the DC. No binding enforcement at all — any certificate with a UPN matching a domain account authenticates as that account. Works with any client authentication template, no special template flag required.

  • ESC10b: CertificateMappingMethods includes legacy SubjectName mapping bits (0x4 or 0x2). The DC maps certificates using the certificate Subject CN or Issuer+Subject in addition to UPN. Requires GenericWrite on an account.

┌──(kali㉿kali)-[~]
└─$ # Certipy auto-detects ESC10 in find output
┌──(kali㉿kali)-[~]
└─$ certipy find -u $USER@$DOMAIN -p $PASSWORD -dc-ip $TARGET_IP -vulnerable -stdout | grep -A8 ESC10
 
┌──(kali㉿kali)-[~]
└─$ # Manual: check both registry values on DC
┌──(kali㉿kali)-[~]
└─$ nxc smb $TARGET_IP -u $USER -p $PASSWORD -x 'reg query HKLM\SYSTEM\CurrentControlSet\Services\Kdc /v StrongCertificateBindingEnforcement'
┌──(kali㉿kali)-[~]
└─$ nxc smb $TARGET_IP -u $USER -p $PASSWORD -x 'reg query HKLM\SYSTEM\CurrentControlSet\Services\Kdc /v CertificateMappingMethods'
[!] Vulnerabilities
    ESC10a: 'StrongCertificateBindingEnforcement' is set to 0

StrongCertificateBindingEnforcement    REG_DWORD    0x0
CertificateMappingMethods              REG_DWORD    0x1f
PS C:\Users\Guest\Desktop> # Check both relevant KDC registry values on DC
PS C:\Users\Guest\Desktop> reg query HKLM\SYSTEM\CurrentControlSet\Services\Kdc /v StrongCertificateBindingEnforcement
PS C:\Users\Guest\Desktop> reg query HKLM\SYSTEM\CurrentControlSet\Services\Kdc /v CertificateMappingMethods
PS C:\Users\Guest\Desktop> # CertificateMappingMethods with bit 0x4 (value includes 4) = SubjectName mapping = ESC10b

References