Active Directory Certificate Services (ADCS) is also known as “privilege escalation as a service.” ADCS is a service provided with Active Directory that issues certificates for machines and services within a Windows environment, and it is very easy to misconfigure. Certipy, a Python port of Certify by ly4k, is one of the best tools to abuse, and exploit ADCS. While there are over a dozen ESC vulnerabilities, the most common to encounter are ESC1 and ESC8.
ADCS ESC1
ESC1 is a certificate template-based vulnerability where an administrator configures a certificate template in a way that allows a low-privileged user to request a certificate on behalf of a highly privileged user. This certificate can then be used to authenticate as the privileged user, making it extremely valuable. Even if the user changes their password, the certificate can still be requested again until it expires. The expiration period can be a week, a month, a year, or even ten years. Although Windows now warns users that the configuration they are creating for a template may lead to security vulnerabilities, this is only a recent change. Any templates created before this change do not have this warning, and if those templates are cloned, now warnings appear.
Requirements for ESC1
For ESC1 to occur, a few settings need to be configured on the template. First, Client Authentication needs to be enabled for the certificate. Next, Enrollee Supplies Subject needs to be enabled. The next item is partially optional, and that is Requires Manager Approval. While having this setting disabled makes the certificate issuance instant, there is still the possibility that a manager may simply approve the certificate without fully checking to ensure the certificate request is not malicious. Lastly, you need a user account that can enroll in the certificate template. This most often occurs when an administrator sets the Domain Users group to be able to enroll.
Attacking ESC1
The first step for this attack is to gain access to a valid domain account.
Next, we are going to run Certipy’s find command. Now depending on the LDAP configuration for the domain controller you may experience some errors. In our case we are getting a connection reset by peer.
To fix this we can force Certipy to use LDAP only and not attempt to upgrade to LDAPS with the -scheme ldap argument.
Note if the domain controller is set to require channel binding you may need to try running Certipy find with -ldap-channel-binding and -scheme ldaps.
We can now cat the file that Certipy saved its output to, and we see that there is one certificate authority with one vulnerable template.
We are now going to run Certipy’s req module to generate a certificate.
With this certificate, we can attempt to retrieve the user’s NT hash using Certipy’s auth module. Note that during this process, you may be prompted to choose between the user and the DNS name. Simply enter the number corresponding to the user.
ADCS ESC8
ESC8 is a vulnerability related to ADCS Web Enrollment. ADCS Web Enrollment is a feature that deploys a web server, enabling clients to request a certificate template. This web server supports NTLM authentication, making it susceptible to relay attacks. For this attack to succeed, you must know a valid template name to enroll in. Fortunately, ADCS comes with several default enabled templates that can be used, including ‘User,’ ‘Machine,’ and ‘DomainController.’ These templates are fairly self-explanatory: ‘User’ is for Domain Users, ‘Machine’ is for Domain Computers, and ‘DomainController’ is for Enterprise Domain Controllers.
For this attack chain, where we have no credentials, we can use 'openssl s_client -connect dcip:636 -debug'
to enumerate which certificate authority the domain controller uses. This command will display all the data related to the domain controller’s certificate that is being used for LDAPS, including the hostname of the certificate authority. We can then check if the certificate authority supports web enrollment by navigating to “http://certificate-authority/certenroll/”. If we are prompted to enter credentials or presented with a 403 Forbidden error, web enrollment is likely enabled.
Now we need to relay some credentials to do this there are two options the first is Certipy and the second is ntlmrelayx by Impacket. It is also good to pair these tools with Responder and MITM6 for better results.
certipy relay -target certificate-authority
ntlmrealyx.py -t http://certificate-authority/certsrv/certfnsh.asp –adcs -smb2support
Both commands accept an argument: --template
for ntlmrelayx
and -template
for certipy
. If this argument is not provided, both tools will default to using the ‘Machine’ or ‘User’ template, depending on the account type that was relayed. This argument is particularly useful when relaying from a domain controller or if the ‘User’ and ‘Machine’ templates are disabled or have been renamed.
Ntlmrelayx Method:
Once we obtain a certificate, we need to save the base64 encoded data to a file.
Then download PKINITTools
git clone https://github.com/dirkjanm/PKINITtools.git
We are going to use gettgtpkinit.py to convert our certificate into a Ticket Granting Ticket (TGT).
python3 gettgtpkinit.py -pfx-base64 $(cat /path/to/certfile) -dc-ip dcip domain/username username.ccache
NOTE: The username in domain/username needs to be the same as the username that was gotten from ntlmrelayx including a ‘$’ if it is a machine account.
Finally run export KRB5CCNAME=/path/to/username.ccache and now you can use that account with any tool that supports Kerberos authentication with a -k.
Now with a valid account’s TGT we can use this to escalate our privilege within the environment. Using Ly4k’s version of PetitPotam, we can coerce a domain controller to authenticate to an arbitrary host. In this case we will make it authenticate to our attacker machine.
Now, repeat the previous steps to obtain a TGT for the domain controller’s account
With this TGT we can dump NTDS using secretsdump.py
Certipy Method:
Once a certificate has been issued it will be saved as a .pfx file automatically. Next, you can retrieve the accounts NT hash with certipy auth -pfx /path/to/.pfxfile -dc-ip dcip
Persisting Credentials:
One thing you may notice is that even if a user changes their password, if you have a PFX certificate, you can request their NT hash again to obtain the new credential. As long as you have a valid PFX certificate, you have unlimited access to the account. Even if the administrator deletes the certificate template that issued the certificate, the certificate will continue to work until it expires. This is an excellent way to persist access to a domain account with very few requirements. The only three requirements are that the template allows for Client Authentication, does not require Manager Approval, and that the account you have can enroll in the template. If these criteria are met, you have an easy way to maintain access to an account.
Multi Domain Environments:
Many enterprises use multiple domains within their environment, with varying levels of trust between each. The most common approach is to have a root domain; in this example, we will use acme.local. This domain may have several child domains, such as test.acme.local, prod.acme.local, dev.acme.local, and corp.acme.local. Typically, there is bidirectional trust between each domain, allowing accounts from one domain to authenticate on machines in another, usually with reduced privileges unless otherwise specified.
With this in mind, if an account in one domain is compromised, it can often be used with ESC1 to request a user account on a different domain. Additionally, if an account is compromised on one machine within a domain, Coercer can be used to elevate that account’s privileges to administrator on all domain controllers in the other domains. The only requirement on the certificate authority side is that each domain trusts the certificate authority.
Other Cool ADCS Stuff
Blindly Find Certificate Authorities
There are ways to unauthenticated blindly check for certificate authorities that have potential ESC8 vulnerabilities. For this we just need to know a domain controller’s IP address. Then we can run openssl s_client -connect dcip:636 -debug -showcerts. With this we can see the certificate authority’s common name and its hostname within the decoded hex data.
With this information we can attempt to enumerate it for information regarding what services it has.
Web enrollment is likely enabled, as port 80 is open. If web enrollment is enabled, trying to browse to http://certauthority/certsrv/ will result in a 401 unauthorized error. If it is not enabled, browsing to http://certauthority/certsrv/ will result in a 404 not found error.
Enumerate ADCS With a Relay
If we have no credentials and any captured hashes fail to crack, we can use a relay by creating a target file containing ldap://dcip
and ldaps://dcip
. This allows us to attempt to enumerate LDAP for certificate information using ntlmrelayx. This approach is particularly useful if you encounter an ESC8 vulnerable certificate authority, but cannot find a valid template name.