Abusing Active Directory Certificate Services – Part One
Active Directory Certificate Services (ADCS)1 is used for public key infrastructure in an Active Directory environment. ADCS is widely used in enterprise Active Directory environments for managing certificates for systems, users, applications, and more.
In 2021, SpecterOps published a white paper that described ADCS in-depth along with ADCS misconfigurations and vulnerabilities2 that can be abused for credential theft, domain escalation, and persistence. This white paper took a deep dive into attack techniques for ADCS and provided guidance on how to prevent, detect, and respond to such attacks.
This blog post will not cover all techniques discussed in the white paper. I highly recommend reviewing both the white paper and the shortened blog post written by Will Schroeder and Lee Christensen. A link to the white paper3 and SpecterOps blog post4 can be found in the resources listed at the end of this post.
Tools
Since the white paper came out, several tools have been published to help identify vulnerabilities and exploit Active Directory Certificate Services. Similarly, tools have been published to help blue teamers identify and remediate these issues.
This blog post is the start of a short series that will cover ADCS attacks primarily using Certipy (https://github.com/ly4k/Certipy). Certipy is a Python-based offensive security tool that can be used to enumerate and abuse vulnerable ADCS. Certipy is the tool I use most often, but I have listed a few other related tools below:
- PKINITtools: https://github.com/dirkjanm/PKINITtools
- PyWhisker: https://github.com/ShutdownRepo/pywhisker
- Certi: https://github.com/zer1t0/certi
- Impacket: https://github.com/fortra/Impacket
- Certify: https://github.com/GhostPack/Certify
Abusing Misconfigured Templates
Certificate templates are Active Directory objects used to define certificate policies. In the certificate template, an admin can specify settings such as the subject (the identity), validity period, and purpose, as well as users authorized to request a certificate. Users authorized in the template settings can request a certificate based on configurations defined in the certificate template.
Users authorized to request a certificate can be defined using a descriptor on the Certificate Authority itself and in the certificate template object.
To enumerate ADCS template information from your target domain, you need valid domain credentials. Based on my experience, enumeration of ADCS does not usually require a highly privileged domain account. Any domain credential can typically be used to query ADCS templates and configuration details.
In the following example, let’s imagine that we have gained a foothold in our target company FOOBAR’s internal network and have compromised the account of a user with the name “billy.” We want to enumerate the ADCS configuration for the internal target domain “foobar.com”.
To enumerate ADCS configurations with Certipy, use the find
command. By specifying the -enabled
and -vulnerable
flags, we can tell Certipy to specifically print out vulnerable templates that are enabled.
The full Certipy command is shown below:
certipy find -u '[email protected]' -p <password> -dc-ip <DC_IP> -vulnerable -enabled
Certipy outputs the configuration details of interest in JSON (JavaScript Object Notation) and TXT files following the naming convention “<DATE-TIMESTAMP>_Certipy” as shown in the figure below. Certipy also runs BloodHound collectors which output to a zip file following the same naming convention. The BloodHound results can be imported into your BloodHound database and used to obtain a visual of potential domain privilege escalation paths. BloodHound is out of scope for this particular blog post. However, if you are interested in leveraging this feature, here are a couple things to note:
- At the time of writing, Certipy generates BloodHound data that can only be ingested by a fork of BloodHound found here: https://github.com/ly4k/BloodHound.
- To use BloodHound maintained at https://github.com/BloodHoundAD/BloodHound, you need to specify the
-old-bloodhound
flag.
A simple grep command using search terms like “ESC” can be used to check the resulting TXT file for escalation opportunities discovered by Certipy.
For example, we can check the file for ESC1 as follows:
ESC1
A certificate template with the ESC1 vulnerability allows low privileged users to enroll and request a certificate on behalf of any domain object specified by the user. This means that any user with enrollment rights can request a certificate for a privileged account such as a domain administrator.
Templates vulnerable to ESC1 have the following configurations:
- Client Authentication: True
- Enabled: True
- Enrollee Supplies Subject: True
- Requires Management Approval: False
- Authorized Signatures Required: 0
Upon investigating the Certipy output file “20230602164801_Certipy.txt”, we notice that Certipy found an ESC1 vulnerability on the first template called “FOO_Templ”. All conditions for ESC1 are met by the “FOO_Templ” template.
As shown in the figure below, the “Permissions” section of the vulnerable template states that users in the Domain Users or Authenticated Users groups can enroll. This means that any domain user can request a certificate on behalf of a Domain Admin.
Our compromised user account “billy” is a part of the Domain Users group and therefore is authorized to request a certificate using the vulnerable template. We can request a certificate for Dan the DA by setting the user’s principal name (UPN) to [email protected]. The Certipy arguments required to request a certificate are as follows:
u
– usernamep
– compromised user passworddc-ip
– domain controller IP addresstarget
– target CA (Certificate Authority) DNS (Domain Name System) Nameca
– short CA Nametemplate
– vulnerable template nameupn
– target user/object name
The full Certipy command is shown below:
certipy req -u '[email protected]' \
-p '<PASSWORD>' \
-dc-ip '10.10.1.100' \
-target ' foobar-CA.foobar.com ' \
-ca 'foobar-CA' -template 'FOO_Templ'\
-upn '[email protected]'
Note: The Certipy results will return the request ID or an Object SID. Note this, as you will need this information to revoke the certificate once the test is completed.
As shown in the figure above, our certificate and private key are stored in the “DA_Dan.pfx” file.
**Troubleshooting Sidebar**
If this does not work and you receive an error that says something like SMB (Server Message Block) SessionError: STATUS_NOT_SUPPORTED`
You can try to use Kerberos authentication instead of username and password. Gabriel Prud’homme (vendetce) taught me this work around so if it works for you hit him up and tell him how dope he is! To get a service ticket for your user, you can use Impacket’s getTGT module (https://github.com/fortra/impacket/blob/impacket_0_10_0/examples/getTGT.py).
python3 getTGT.py 'foobar.com/billy'
After you run the command above, you will be prompted for the password for your user and the module will return a CCache file with the name “<USERNAME>.ccache.”. Export the resulting CCache file to an environment variable like so:
*Make sure to include the full path to your CCache file*
export KRB5CCNAME=/full/path/to/billy.ccache
To request a certificate using Kerberos authentication the command will be similar to the previous except we will use -k
for use Kerberos authentication and -no-pass
. The full Certipy command is shown below:
certipy req -u '[email protected]' -k -no-pass \
-dc-ip '10.10.1.100' \
-target ' foobar-CA.foobar.com ' \
-ca 'foobar-CA' -template 'FOO_Templ'\
-upn '[email protected]'
**End Sidebar**
Once we have our certificate, we can use the certificate to obtain the credential hash and a Kerberos ticket of the target DA account using the Certipy -auth
command as shown below:
certipy auth -pfx DA_Dan.pfx
As shown in the figure below, we successfully retrieved the hash for the DA_Dan account. Now we can impersonate DA_Dan!
In summary, due to the overly permissive ADCS template, we were able to escalate from a normal domain account to a Domain Administrator account.
Validity Period
It is important to note that the certificate obtained will be valid for the DA account until the validity period ends unless the certificate is explicitly revoked. Let’s look at the vulnerable template again. As we can see in the figure below, the template specifies a validity period of 5 years.
This means that we will have access to DA Dan’s account for the next five years, regardless of any password changes. We can also renew the certificate before the expiration date to maintain access to the account. Which means that this technique is not only a handy privilege escalation technique but could serve as a means of persistence as well.
I have observed certificate templates with validity periods of 1-10 years. I typically see templates with a validity period of 3-5 years. This may be a common practice or a default configuration, it may not, this is just based on what I have observed in various enterprise environments that I have tested.
Prevention and Detection
So, what can we do to prevent and detect such attacks? Here are a few steps you can take to harden your certificate templates.
- Take stock of your certificate templates and determine whether all enabled templates are currently in use. Disable all templates that are unnecessary.
- Make sure that template permissions are as restrictive as possible. Only grant necessary groups/users enrollment permissions.
- Modify the “Issuance Requirements” to require the manual approval of an issued certificate where possible.
- Disable the “Enrollee Supplies Subject” flag where possible.
- Remove “Client Authentication” where possible.
Monitoring
By monitoring certificate enrollment events for users, you can detect when an account requests a certificate and when your CA issues a certificate. By monitoring certificate enrollment events, an administrator can alert on anomalous behavior and revoke certificates that appear to be malicious or suspicious. Some useful event IDs can be found below:
- 4886 – Request for certificate
- 4887 – Certificate Issued
- 4768 – Request for Kerberos ticket (TGT)
Defensive Resources:
- “Defensive Guidance” section of Certified_Pre-Owned5
- Microsoft PKI defensive guidance: https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2012-r2-and-2012/dn786443(v=ws.11)
- PKIAudit: https://github.com/GhostPack/PSPKIAudit
Additional Resources
- https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2012-r2-and-2012/hh831740
- SpecterOps Whitepaper: https://specterops.io/wp-content/uploads/sites/3/2022/06/Certified_Pre-Owned.pdf
- SpecterOps Blog Post: https://posts.specterops.io/certified-pre-owned-d95910965cd2
- https://specterops.io/wp-content/uploads/sites/3/2022/06/an_ace_up_the_sleeve.pdf
- https://www.securew2.com/blog/how-to-revoke-certificate-in-windows-ad-cs
- https://www.thehacker.recipes/ad/movement/ad-cs/certificate-templates
- https://dirkjanm.io/ntlm-relaying-to-ad-certificate-services/
- PKINITtools: https://github.com/dirkjanm/PKINITtools
- PyWhisker: https://github.com/ShutdownRepo/pywhisker
- Certi: https://github.com/zer1t0/certi
- Impacket: https://github.com/fortra/Impacket
- Certipy: https://github.com/ly4k/Certipy
- Certify: https://github.com/GhostPack/Certify
Footnotes
[1] https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2012-r2-and-2012/hh831740(v=ws.11)
[2] https://specterops.io/wp-content/uploads/sites/3/2022/06/Certified_Pre-Owned.pdf
[3] https://specterops.io/wp-content/uploads/sites/3/2022/06/Certified_Pre-Owned.pdf
[4] https://posts.specterops.io/certified-pre-owned-d95910965cd2
[5] https://specterops.io/wp-content/uploads/sites/3/2022/06/Certified_Pre-Owned.pdf
READ:
Ready to learn more?
Level up your skills with affordable classes from Antisyphon!
Available live/virtual and on-demand