WHFB and Entra ID : Say Hello to your new cache flow

Rédigé par Geoffrey Bertoli , Théo Gordyjan , Rémi Jullian - 05/06/2024 - dans Pentest - Téléchargement

During security assessments, the cache can be a goldmine on Microsoft environments. Red teamers are familiar with MSCache or DCC2 hashes, which could be a fast track to a privileged account. However, when using WHFB and a cloud-only Entra ID environment, these hashes no longer exist.

This blogpost aims at analyzing the cache components of Entra ID-joined devices with WHFB configured and provides a toolkit to use them.

WHFB and Microsoft Entra ID

Definition

Microsoft Entra ID (previously known as Azure AD) is an integrated cloud identity and access solution for managing directories, enabling access to applications, and protecting identities. It can be seen as an AD DS (Active Directory Domain Services) in the cloud.

Moreover, Windows Hello and its "For Business" counterpart tend to replace passwords with two-factor authentication on devices. The first factor is a PIN, biometrics, or a security key set by the user, while the second factor is the device itself as it stores cryptographic material. As we will discuss later, this is more a strong authentication than a two-factor authentication.

Registration process

To set up Windows Hello For Business when joining a Microsoft Entra ID tenant, an initial two-step verification (with a phone number or Authenticator app) is asked to the user during enrollment. After this step, WHFB is set up on the user device and Windows asks the user to provide the second factor (PIN, biometrics, etc.). After a reboot, Windows is now able to authenticate the user using this second factor on this device.

Use_Windows_Hello
 Windows Hello For Business Enrollment

 

Password authentication relies on symmetric authentication, meaning that the server where you want to authenticate stores the password as a hash or another representation. On the contrary when using WHFB, neither the server nor the client have a copy of the authentication material: authentication is based on asymmetrical cryptography.

After successfully registering a computer having a TPM, a public/private key pair is generated. The second factor (PIN, biometric, etc.) is an entropy used to protect the private key stored in the TPM, while the public key is registered on Entra ID. The sharp-eyed reader could notice that this is not a "true" two-factor authentication, as the two factors (the PIN and the private key) are conditional (as a credit card and a PIN code).

As discussed later, if the device does not have a TPM (virtual machines for instance), the private key is encrypted using DPAPI-NG and stored on the file system, thus exposing it to brute force attacks. However, despite common knowledge, the WHFB PIN can be configured with non-digits characters, which could improve protection.

A primer on Windows Hello

Windows Hello is the « non business » version of WHFB which can be used as a way to get instant access to your Windows 10 device using a PIN, facial recognition, fingerprint, etc. As for WHFB, while the PIN is sufficient to sign in, it also needs to be setup as part of configuring fingerprint or facial recognition sign-in.

These options make it easier and safer to sign in to computers as it can be backed up for recovery with a Microsoft account.

When you are using a PIN with Windows Hello, the final goal is to decrypt a file containing the user password. The file can be a vault or directly a registry key: HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\LogonUI\NgcPin\Credentials\S-1-5-21-xxx\encryptedPassword.

There are several steps to decrypt it including DPAPI-NG, PBKDF2-SHA256 key derivation, RSA and AES-CBC decryption. The full behavior is widely described here.

 

DEcrypt Password using DPAPI-NG
Password decryption with DPAPI-NG

 

Therefore when used without a TPM, it is easy for an attacker to brute force the PIN to retrieve the clear text password of the local user. This repository contains all the tools needed for this.

When using a TPM however, the process is similar but the DecryptPIN is no longer stored in the NGC folder as inputData. Instead, it is now stored directly in the TPM and can only be accessed by providing the right PIN.

The NGC crypto provider will be marked as Microsoft Platform Crypto Provider.

Authentication on Microsoft Entra ID with Windows Hello For Business

Multiple steps are involved when authenticating on Microsoft Entra ID using WHFB. Here is a schema when a TPM is used:

Authentication process
Authentication process

 

  1. The user signs in with the 'second factor" which can be a PIN, a biometric proof, etc. The PIN is a user-provided entropy used to access the private key from the TPM. The credential provider packages the credentials and returns them to Winlogon which passes them to LSASS, which in turn passes the collected credentials to CloudAP.

  2. CloudAP requests a nonce from Microsoft Entra ID, uses the private key to sign it and returns it to Entra ID.

  3. Entra ID validates the signed nonce using the registered public key and creates an encrypted Primary Refresh Token (PRT) using the public key, and sends it back to CloudAP. This PRT includes a session key.

  4. CloudAP decrypts the data with the private key, and stores the session key on the TPM.

  5. CloudAP returns a successful authentication response to LSASS, which caches the PRT, and the user is logged in.

Here, you can see the benefit of the asymmetric cryptography, as the private key is stored on the TPM, and Entra ID is able to authenticate the user thanks to the data encrypted with it. Note that this process can also vary depending on the environment (hybrid, authentication to Active Directory, etc.).

Without a TPM, the process is almost the same, but all the critical information is stored on the disk and the decryption process can be performed simply by accessing the filesystem with the right privileges.

Let's now dig into the PRT.

Primary Refresh Token

A Primary Refresh Token (PRT) is a key artifact of Microsoft Entra ID authentication. It can be seen as a TGT in Active Directory, and used to sign in a user on their Entra ID device and connected resources.

Once issued, a PRT is valid for 14 days and is continuously renewed as long as the user actively uses the device and is connected to the network (CloudAP renews the PRT every 4 hours). A PRT is used to request an access token, whose role is to provide data access. Furthermore, when a PRT is issued, Entra ID also issues an encrypted session key to the device. It is encrypted with the public key generated and sent to Entra ID as part of device registration. The session key is the Proof-of-Possession key for any request sent to Entra ID. If you want to further understand how it works and how it could be abused, many articles were written on this topic. Dirk-jan Mollema wrote amazing articles about that and created ROADtools which is a framework to interact with Entra ID. Moreover, Benjamin Delpy also implemented features in mimikatz related to CloudAP and PRT.

To summarize, here is the process for creating what Dirk-jan called a PRT cookie, which is a JWT used to access Entra ID-connected resources:

  • Cloud AP takes the PRT and generates a random context.

  • It takes the encrypted session key and uses DPAPI to decrypt it on a device with no TPM. On a device with a TPM, the session key can only be decrypted by the private key stored on the TPM.

  • It then passes the session key and the random 24-byte context to BCryptKeyDerivation, using the AzureAD-SecureConversation label.

  • This returns a derived key which is used to sign the JWT.

Now that we understand all the mechanisms involved with Entra ID and WHFB, we will dig into the offline authentication process, i.e., how it works when the device is not connected to the internet.

Cached data for offline authentication

Using the password

When the user is not connected to the internet, it is possible to login using their password on the device. Once disconnected, we were able to analyze the LSASS memory with mimikatz and noticed that CloudAP contains a valid PRT.

 cloudap :
             Cachedir : f3efc[...]006
             Key GUID : {7d41[...]cc367}
             PRT      :  [...] "Prt":"[...]", "PrtReceivedtime":1706690568, "PrtExpirytime":1707900171, "ProofOfPossesionKey":{"Version":1, "KeyType":"ngc", "KeyValue":"[...]_ak1s1FjFCHlt7qzu3aBroMAAAAPBviM1l-[...] "CloudTgtMessage":"[...]
             DPAPI Key: [...] 

As discussed previously, it is not possible to generate a PRT using only a password, meaning it must be stored somewhere on the disk.

By debugging the Windows authentication process, we see that the file used to store this information is located at C:\Windows\system32\config\systemprofile\AppData\local\microsoft\windows\CloudAPCache\AzureAD\<unique_hash>\Cache\CacheData.

We also noticed that the cloudAP!DeriveKeyFromSecret function takes the password as an argument (without salt), and that the resulting key is used in AES-CBC decryption (with a null IV) to retrieve the PRT from the CacheData file.

So if attackers can read the CacheData file, they can perform a bruteforce attack in order to guess the user password. They can then retrieve a valid PRT as well as the DPAPI Cred Key (more information about this key can be found here) and the session key. We will see later that it is more complicated using a PIN.

When a password is used, extracting the PRT file is pretty straightforward as it is encrypted with an AES key simply derived from the password with PBKDF2 (10 000 rounds as for a DPAPI encryption). We will see later that it is more complicated using a PIN...

If you made your homework and read the articles we mentioned before, something should have happened in your head here.

By dumping all the DPAPI masterkeys, it is possible to decrypt the session key which is inside the CacheData file, and derive the signing key from the session key. We can then use it to modify and re-sign the PRT. This allows using the PRT as long as it is valid (14 days) on other systems than it was issued to.

To extract the DPAPI masterkeys, mimikatz can be used on a live system, or other methods described in our previous blogpost. Here is the result of the command using another device (if done on the targeted device, you can skip the /masterkey argument as SYSTEM):

mimikatz # dpapi::cloudapkd /keyvalue:AQAA[...]PFNXS4C /masterkey:e636[...]6712
Label      : AzureAD-SecureConversation
Context    : 20[...]31
 * masterkey     : e636[...]6712
Key type   : Software (DPAPI)
Clear key  : fca3[...]12c
Derived Key: b0c[...]2a7

But this only works on a device enrolled in Entra ID with no TPM. If a TPM is present:

mimikatz # dpapi::cloudapkd /keyvalue:AQA[...]Ag
Label      : AzureAD-SecureConversation
[...]
Key type   : TPM protected (DPAPI)
Key Name   : SK[...]6
Opaque key : 007[...]150
ERROR kull_m_crypto_ngc_keyvalue_derived_hardware ; NCryptOpenStorageProvider: 0x80090030

Here, the session key is protected by the TPM and an additional step is required to retrieve a derived key. So the only way to extract it is to have a live session on the device where the TPM is located. For that purpose, mimikatz can also be used as SYSTEM:

mimikatz # dpapi::cloudapkd /keyvalue:AQ[...] /unprotect
[...]
Key type   : TPM protected (DPAPI)
Key Name   : SK[...]6
Opaque key : 007[...]150
Derived Key: eb2[...]b62

Finally, you can use this derived key to forge your own PRT cookie using ROADtools.

With a PIN

Introduction

When a PIN is used, it is another story. NGC and DPAPI-NG are used to decrypt the blob related to authentication, with a PIN on the CacheData file. The first parts involved here are very well explained in the blogpost from Tijl Deneut, so some explanations you will find later on regarding the decryption of the AES-256 key stored inside the CacheData file are extracted from it. Let’s start by explaining some theory.

NGC (Next-Gen-Cryptography) is also called "Cryptography API: Next Generation" or CNG, and is the long-term replacement for the CryptoAPI. NGC works with providers and protectors:

  • A provider is a component responsible for managing cryptographic operations and interacting with the NGC framework.
  • A protector is the method or technique used to encrypt and protect sensitive data, ensuring its security and confidentiality.

In order to retrieve the protectors, providers and associated items, it is only necessary to retrieve the content of the NGC folder by parsing the non-encrypted data inside it.

Within the NGC folder %windir%\ServiceProfiles\LocalService\AppData\Local\Microsoft\Ngc, there is a GUID for each provider and user that is initialized. There are some dat-files containing metadata about the provider and the user SID. Then, there is a Protectors subfolder holding a list of protected data bytes, presented as dat-files inside a subfolder. Some NGC data is RSA encrypted, which we will describe later. For each protector's folders, there is a subdirectory 1, and then .dat files (containing the metadata). Each protector has its associated items.

PS C:\Windows\ServiceProfiles\LocalService\AppData\Local\Microsoft\Ngc> tree /f .
Folder PATH listing
Volume serial number is 00000013 BEEE:F099
C:\WINDOWS\SERVICEPROFILES\LOCALSERVICE\APPDATA\LOCAL\MICROSOFT\NGC
└───{20024BC6-7FC7-43B3-8C18-DB3204A14C0A}
    │   1.dat
    │   10.dat
    │   [...]
    │
    ├───Protectors
    │   └───1
    │           1.dat
    │           2.dat
    │           [...]
    │
    ├───Temp
    ├───{93F10861-19F1-42B8-AD24-93A28E9C4096}
    │   ├───56d07ac46c9c347e6d1ef0b0ffbd5bf3255e5edfaff4ee78ae36e7b143efdaa5
    │   │       1.dat
    │   │       2.dat
    │   │       [...]
    │   │
    │   ├───967764170a8f4c3864cf33ac6bf306bb461913b909c5bd1a79137f0131818b8e
    │   │       1.dat
    │   │       2.dat
    │   │       [...]
    │   │
    │   ├───bf6555188e70249b68ef5a4c3421743d93a20ced94383b4c42c32e67aed72ff3
    │   │       1.dat
    │   │       2.dat
    │   │       [...]
    │   │
    │   └───{93F10861-19F1-42B8-AD24-93A28E9C4096}
    └───{EB787EE1-FD6F-11E3-80D4-10604B681CFA}
        └───{EB787EE1-FD6F-11E3-80D4-10604B681CFA}

Depending on whether a TPM is present/used, the protector's provider will be different. If the provider is Microsoft Software Key Storage Provider, no TPM is used, everything is stored locally so bruteforce is possible, even on another computer, by extracting the appropriate files. On the other hand if a TPM is used, the provider is Microsoft Platform Crypto Provider. Hence, bruteforce will be limited by the TPM on a live system, and will simply not be possible on another computer. However, it will still be possible to recover the PRT if the PIN is known on a live system.

Here is the output of what is explained above using dpapilab-ng:

If a TPM is present:

$ python3 _ngc_step_by_step_on_and_offline.py <ngc_folder> 
[...]
== Protectors ==
[-] Protector "1" is being stored in the TPM chip.
= 1 =
[+] Provider  : Microsoft Platform Crypto Provider
[+] Key Name  : 
[+] Timestamp : 2024-03-21 11:25:53
[+] Data Size : 292 byte(s)
[...]

Without a TPM:

$ python3 _ngc_step_by_step_on_and_offline.py <ngc_folder> 
[...]
== Protectors ==
= 1 =
[+] Provider  : Microsoft Software Key Storage Provider
[+] Key Name  : {660A7562-EE22-4A5F-81BB-DCFC6A3DCACF}
[+] Timestamp : 2024-03-12 17:51:22
[+] Data Size : 256 byte(s)

== Items ==
= {93F10861-19F1-42B8-AD24-93A28E9C4096} =
* bf6555188e70249b68ef5a4c3421743d93a20ced94383b4c42c32e67aed72ff3
[+] Name     : login.windows.net/f046467a-566b-47c8-a75e-f55e572de5dc/theog@s1nresearch.onmicrosoft.com
[+] Provider : Microsoft Software Key Storage Provider
[+] Key Name : {7FBF5E65-0559-4A16-BFFE-A9187C742560}

* 967764170a8f4c3864cf33ac6bf306bb461913b909c5bd1a79137f0131818b8e
[+] Name     : //CA00CFA8-EB0F-42BA-A707-A3A43CDA5BD9
[+] Provider : Microsoft Software Key Storage Provider
[+] Key Name : {1EB9AF77-CC62-4C28-A173-19267DD63045}

* 56d07ac46c9c347e6d1ef0b0ffbd5bf3255e5edfaff4ee78ae36e7b143efdaa5
[+] Name     : //9DDC52DB-DC02-4A8C-B892-38DEF4FA748F
[+] Provider : Microsoft Software Key Storage Provider
[+] Key Name : {70D75889-1A20-4A37-8DDB-7E933AE3D755}

[...]

The item related to the PIN authentication has the name //CA00CFA8-EB0F-42BA-A707-A3A43CDA5BD9. More on this later.

 

Without a TPM

We introduced the differences related to whether a PIN is used or not and the notion of providers, protectors, and items. Now, let’s dive into the details to know how to decrypt the blob inside the CacheData file related to authentication with a PIN.

A first RSA private key needs to be constructed from its encrypted data (called a BCRYPT RSA Private Key Blob) to construct a second one which is also constructed from another BCRYPT RSA Private Key Blob. These blobs are stored inside %windir%\ServiceProfiles\LocalService\AppData\Roaming\Microsoft\Crypto\Keys, identified by cleartext metadata for each key (their GUID).

The first BCRYPT RSA Private Key Blob linked with NGC is decrypted using DPAPI mechanisms after multiple steps involving the system masterkeys, SYSTEM and SECURITY hives, the PIN, and a static entropy string. Then, the RSA private key is constructed.

After that, it is used to decrypt NGC data to obtain the so called DecryptPIN.

Finally, the second BCRYPT RSA Private Key Blob is decrypted using the GUID of the item used for WHFB (named //CA00CFA8-EB0F-42BA-A707-A3A43CDA5BD9) using the same method replacing the PIN by the DecryptPIN, and the CryptoKey by the one linked with the GUID of the item.

Here is the schema for the parts explained above from Tijl Deneut's blogpost. We highlight the only difference, which is the GUID used for the second round, as the name of the item used in the process for WHFB is different: //CA00CFA8-EB0F-42BA-A707-A3A43CDA5BD9 and so is the key.

Decrypt Password using DPAPI-NG
Password decryption with DPAPI-NG

We introduced the CacheData file earlier in this article and noticed how the PRT file could be easily decrypted when using a password.

Now, when using a PIN, let’s see how the second BCRYPT RSA Private Key Blob is used for decrypting the PRT blob. As the process is totally different, if a user can authenticate using both a password and PIN, two distinct entries of encrypted PRT blobs will be present in the same CacheData file. Our script handles such cases, as described later.

In order to understand the cryptographic mechanisms involved when using a PIN, and more precisely, to identify the role of the second BCRYPT RSA Private Key Blob, we had to look at several DLLs:

  • cloudAP.dll: Cloud Authentication Provider, used to authenticate a user logon attempt on the user's initial logon. Implement the SECPKG_FUNCTION_TABLE structure, which contains pointers to the LSA functions that a security package must implement. This DLL is not documented by Microsoft.

  • cryptngc.dll: NGC cryptographic implementation, used by cloudAP.dll, for instance for decrypting BCRYPT RSA Private Key Blob, based on the provided PIN. This DLL is used both with TPM (Microsoft Platform Crypto Provider) or without TPM (Microsoft Software Key Storage Provider). This DLL is not documented by Microsoft, and uses ncrypt.dll.

  • ncrypt.dll: High level interface for manipulating NGC cryptographic keys, implementing for instance NCryptEncrypt() or NCryptDecrypt(), to RSA encrypt or decrypt a secret. This library works with key of type NCRYPT_KEY_HANDLE, opened with NCryptOpenKey(). To open a key, a cryptographic provider of type NCRYPT_PROV_HANDLE must be provided. Such provider could be open with NCryptOpenStorageProvider(). Cryptographic primitives are not implemented directly within the DLL. This DLL is documented by Microsoft.

  • ngcksp.dll: Ngc Key Storage Provider, used to implement "Microsoft Software Key Storage Provider", by issuing RPC client calls to the "CNG key isolation" service (keyiso.dll) . This DLL is used by ncrypt.dll, and is not documented by Microsoft.

  • keyiso.dll: Used to implement the "CNG Key Isolation" service, also known as “KeyIso”. It implements an RPC interface (b25a52bf-e5dd-4f4a-aea6-8ca7272a0e86) queried by ngcksp.dll, which interact then with the key storage interface. This DLL is not documented by Microsoft.

  • ncryptprov.dll: High level interface for exposing several providers such as "Microsoft Software Key Storage Provider". Exports the function GetKeyStorageInterface(), documented by Microsoft, and called by keyiso.dll.
  • bcrypt.dll: High level interface exposing functions to implement various cryptographic algorithms or hash functions. For instance, encryption and decryption routine are implemented by BCryptEncrypt() and  BCryptDecrypt() . This DLL is documented by Microsoft, and uses bcryptprimitives.dll as a backend.
  • bcryptprimitives.dll: Low level implementation of cryptographic algorithms (both symmetric and asymmetric) or hash functions. The code used to build this DLL is based on the open-source SymCrypt project, the core cryptographic function library currently used by Windows.

The following schema illustrates interactions between these DLLs, when trying to decrypt an RSA encrypted AES Key, using a BCRYPT RSA Private Key (described later):

Image
Workflow for decrypting RSA encrypted secret when calling NgcDecryptWithUserIdKeySilent

Now that we described the role of these DLLs, let's look at the overall workflow, in order to decrypt the PRT file. The workflow is not really straightforward, as multiple RPCs are involved all along the decryption process. For the sake of simplicity, we will only focus on the cryptographic operations here. The following schema describes the PRT decryption using a PIN, and is recommended to read the three upcoming paragraphs:

Image
CacheData file

Rsa Decrypt #1

Let’s start with the second BCRYPT RSA Private Key Blob, decrypted using the DecryptPIN, as explained previously. This is the RSA private key located on the left-hand side on the schema. The related public key is stored as a BCRYPT RSA Public Key Blob, in the CacheData file, so both keys can be matched as they have the same modulus. When creating the CacheData entry, this RSA private key is used to encrypt a 256-bit AES key, padded according to PCKS1.5. The result of the RSA encryption is a blob of 0x100 bytes, which is a big integer of 2048 bits (matching the size of the RSA key), stored in the CacheData file (Encrypted AES Key 1 on the figure). So the first RSA decrypt operation will produce a 256-bit AES key (AES Key Decrypted 1).

AES Decrypt #1

Once decrypted, the AES key is used to decrypt a second AES key (AES Key Decrypted 2), which is stored encrypted in the CacheData file (Encrypted AES Key 2). For the decryption of this key, a 0x10-byte IV is retrieved from the CacheData file (IV for Encrypted Key 2 on the figure).

AES Decrypt #2

Finally, the second AES key can be used to decrypt a blob containing the PRT file as well as the DPAPI CredKey. For this operation, another IV of 0x10 bytes is also used, and retrieved from the CacheData file (IV for PRT).

The CredKey is derived as follows and serves as the base secret to decrypt the DPAPI masterkeys of the user: HMAC(SHA1(CredKey), USERSID_UTF16_LE, SHA1)

We made a PR to diana to integrate this.

With a TPM

As the private key is stored on the TPM, and the PIN is used to access it, the bruteforce of the PIN might be possible but very hard.

  • In TPM 1.2, the protection was implemented by the manufacturer, so TPM chips were not equal regarding the mechanism in place.
  • In TPM 2.0, the TPM is configured by Windows to lock after 32 authorization failures and to forget one authorization failure every 10 minutes.
PS C:\Windows\system32> Get-TPM
TpmPresent                : True
TpmReady                  : True
TpmEnabled                : True
TpmActivated              : True
TpmOwned                  : True
RestartPending            : False
ManufacturerId            : 1229081856
ManufacturerIdTxt         : IBM
[...]
LockedOut                 : False
LockoutHealTime           : 10 minutes
LockoutCount              : 0
LockoutMax                : 31
SelfTest                  : {}


PS C:\Windows\system32> tpmtool getdeviceinformation
-TPM Present: True
-TPM Version: 2.0
[...]

 

Tooling

We developed the tooling needed to bruteforce the password (TPM enabled or not) and the PIN with the TPM disabled. It can be used on both Windows and Linux. It then extracts the PRT from the CacheData file if the bruteforce is successful. Here is a summary of what could be achieved depending on the authentication process:

Summary

Password bruteforce

Past work has already been done on the CacheData file for the password blob. We took advantage of this work in order to have a python script with the ability to bruteforce the PRT.

By passing a dictionary as an argument you can extract the PRT as follows:

$ python3 decrypt_cachedata.py password -C CacheData -P password.txt
[+] Password: 'P@ssw0rd!'
[+] Dumping raw DPAPI Cred key, with GUID c0c17f7a-2b1e-43ff-a739-f698b29469b5 (0x40 bytes):
00000000: D9 00 C8 20 3A 6E FB 10 EC AD AD 3A 02 28 31 7C ... :n.....:.(1|
00000010: E4 31 4E 09 A0 CC BE 96 1D 31 FA C5 42 AF CC 56 .1N......1..B..V
00000020: 70 32 6B 1F A3 94 F8 15 B8 63 5A B2 69 A8 ED 07 p2k......cZ.i...
00000030: D4 71 1C 96 8F 49 18 64 23 0F 30 16 6C 6D 1B CE .q...I.d#.0.lm..
[+] Dumping decrypted PRT file:
{
  "Version": 3,
  "UserInfo": {
    "Version": 2,
    "UniqueId": "57d07212-f77d-402f-90b1-f590b8890bb4",
    "PrimarySid": "S-1-12-1-1473278482-1076885373-2432020880-3020655032",
    [...]
  }
  [...]
}

 

PIN bruteforce

The part related to the bruteforce of the PIN has been mostly inspired by the scripts developed by TIjl Deneut. Then, to be able to decrypt the PIN blob on the CacheData file and extract the PRT, a reverse engineering part has been performed and detailed in the section above.

To use our script, first gather all required files and directories from the target filesystem:

$ ls -ld CacheData secrets/Ngc/ PIN.txt secrets/system secrets/security secrets/Crypto/Keys/ secrets/masterkey/
-rw-r--r-- 1 user user 14036    Feb 15 11:12 CacheData
-rw-r--r-- 1 user user 21       Apr 22 10:56 PIN.txt
drwx------ 2 user user 4096     Feb 15 09:59 secrets/Crypto/Keys/
drwxr-xr-x 2 user user 4096     Apr  8 21:57 secrets/masterkey/
drwx------ 3 user user 4096     Feb 15 09:58 secrets/Ngc/
-rwxr-xr-x 1 user user 40960    Apr  8 21:56 secrets/security
-rwxr-xr-x 1 user user 12734464 Apr  8 21:56 secrets/system

Then, start the script with the pin argument and all required files and directories:

$ python3 decrypt_cachedata.py pin -C CacheData -N secrets/Ngc/ -P PIN.txt \
--system secrets/system --security secrets/security --keys secrets/Crypto/Keys/ \
--masterkey secrets/masterkey/
[+] Found PIN: 123456
[+] Parsing CacheData file CacheData
[+] CacheData file version is 0x2
[+] CacheData expected sha256: b'e56c1ec9d053dfd0618aaed1f5bd0ebbaecf9ed11917a526d5714b7c86101423'
[+] CacheData computed sha256: e56c1ec9d053dfd0618aaed1f5bd0ebbaecf9ed11917a526d5714b7c86101423
[+] RSA decrypt encrypted AES key 1
[+] AES decrypt encrypted AES key 2
[+] AES decrypt encrypted blob of size 0x1970 (DPAPI CredKey + PRT)
[+] Dumping raw DPAPI Cred key, with GUID c0c17f7a-2b1e-43ff-a739-f698b29469b5 (0x40 bytes):
00000000: D9 00 C8 20 3A 6E FB 10 EC AD AD 3A 02 28 31 7C ... :n.....:.(1|
00000010: E4 31 4E 09 A0 CC BE 96 1D 31 FA C5 42 AF CC 56 .1N......1..B..V
00000020: 70 32 6B 1F A3 94 F8 15 B8 63 5A B2 69 A8 ED 07 p2k......cZ.i...
00000030: D4 71 1C 96 8F 49 18 64 23 0F 30 16 6C 6D 1B CE .q...I.d#.0.lm..
[+] Dumping decrypted PRT file:
{
  "Version": 3,
  "UserInfo": {
    "Version": 2,
    "UniqueId": "57d07212-f77d-402f-90b1-f590b8890bb4",
    "PrimarySid": "S-1-12-1-1473278482-1076885373-2432020880-3020655032",
    [...]
  }
  [...]
}

 

Conclusion

By now, we know it is possible to bruteforce the password of an account using its CacheData file even if a TPM is present. While nowadays workstations are usually configured with disk encryption, thus protecting the critical files, this protection could still be bypassed depending on hardware configuration. Administrative rights are then necessary to extract this critical file.

Our toolkit could help you bruteforce the PIN if no TPM is present. If a TPM 2.0 is present, it could take years to crack it. While TPM are more and more globally widespread on physical workstations (it is a requirement on Windows 11), that's not the case on virtual machines.

Finally, while we only discussed the PIN as a second factor. Other factors may be of interest, and researchers started exploring attack vectors on them.

 

References

https://learn.microsoft.com/en-us/windows/security/identity-protection/hello-for-business/

https://www.insecurity.be/blog/2020/12/24/dpapi-in-depth-with-tooling-standalone-dpapi/

https://github.com/tijldeneut/diana

https://learn.microsoft.com/en-us/windows/security/identity-protection/hello-for-business/hello-how-it-works-authentication

https://dirkjanm.io/

https://github.com/dirkjanm/ROADtools

https://github.com/gentilkiwi/mimikatz

https://github.com/EvanMcBroom/lsa-whisperer/blob/master/wiki/sspi/cloudap.asciidoc#_cloudap_credkey_info

https://dirkjanm.io/digging-further-into-the-primary-refresh-token/

https://www.synacktiv.com/en/publications/windows-secrets-extraction-a-summary

https://learn.microsoft.com/en-us/windows/win32/seccng/cng-portal

https://github.com/tijldeneut/dpapilab-ng

https://helgeklein.com/blog/checking-windows-hello-for-business-whfb-key-storage-tpm-hardware-or-software/

https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/ns-bcrypt-bcrypt_rsakey_blob

https://research.nccgroup.com/wp-content/uploads/2020/07/blackhat_europe_2011_exporting_non-exportable_rsa_keys.pdf 

https://github.com/tijldeneut/diana/pull/3/files#diff-3f1c5fff5b24e597402b8dbebcd1ca6bcda59d035065f6be9c74912b4e59f68dR158

https://github.com/synacktiv/CacheData_decrypt

https://github.com/Gerenios/AADInternals

https://github.com/tijldeneut/dpapilab-ng/blob/main/_ngc_step_by_step_on_and_offline.py

https://github.com/tijldeneut/dpapilab-ng/blob/main/ngccryptokeysdec.py

https://i.blackhat.com/USA21/Wednesday-Handouts/us-21-Tsarfati-Bypassing-Windows-Hello-For-Busniess-And-Pleasure.pdf