diff --git a/tools/cachedata2hashcat.py b/tools/cachedata2hashcat.py new file mode 100644 index 000000000..4ec57b6b1 --- /dev/null +++ b/tools/cachedata2hashcat.py @@ -0,0 +1,112 @@ +#!/usr/bin/env python3 +# +# Script to extract the hash from a CacheData-file. +#--MicrosoftAccount +### C:\Windows\system32\config\systemprofile\AppData\local\microsoft\windows\CloudAPCache\MicrosoftAccount\\Cache\CacheData +#--AzureAD +### C:\Windows\system32\config\systemprofile\AppData\local\microsoft\windows\CloudAPCache\AzureAD\\Cache\CacheData +# +# This code is build from scratch. Nonetheless, all the initial reverse engineering work has been done +# by https://github.com/tijldeneut and https://github.com/synacktiv +# +# Authors: +# https://github.com/Banaanhangwagen +# https://github.com/Ctrl-Shift-Defeat +# +# v2025-5: initial release +# +# License: MIT +# + +import sys +import struct + +def read_node_info(file, node_count, start_address): + """Extracts node info from the binary file.""" + node_info = [] + node_size = 20 + node_type_counts = {} + for i in range(node_count): + node_start = start_address + i * node_size + node = file[node_start:node_start + node_size] + node_type = node[0] + node_type_counts[node_type] = node_type_counts.get(node_type, 0) + 1 + crypto_blob_size = struct.unpack('111}") + hashes_found += 1 + else: + # Skip the other nodes properly + start_address += crypto_blob_size + encrypted_part_size + 8 + + return hashes_found + + +def print_banner(): + print("╔══════════════════════════════╗") + print("║ Cachedata2hashcat ║") + print("╚══════════════════════════════╝") + + +def main(): + if len(sys.argv) != 2: + print(f"Usage: {sys.argv[0]} path_to_CacheData") + sys.exit(1) + try: + with open(sys.argv[1], 'rb') as f: + file = f.read() + except IOError as e: + print(f"Error opening file: {e}") + sys.exit(1) + + print_banner() + + # Extract version + version = struct.unpack('5}") + if version != 2: + print("\033[91m[!]\033[0m Unsupported version. Be careful when proceeding.") + + # Extract node count + node_count = struct.unpack('14}") + if node_count == 0: + print("\033[91m[!]\033[0m No nodes found. Cannot proceed.") + sys.exit(1) + + node_info, node_type_counts = read_node_info(file, node_count, 0x54) + + type1_count = node_type_counts.get(1, 0) + print(f"\033[92m[+]\033[0m Type 1-nodes: {type1_count:>15}") + if type1_count == 0: + print("\033[91m[!] Warning: No hash-containing nodes (Type 1) found.\033[0m") + + hashes_found = extract_hashes(file, node_info, 0x54 + node_count * 20) + + if hashes_found == 0: + print(f"\033[91m[!]\033[0m No valid hashes found in the file.\033[0m") + else: + print(f"\033[92m[+]\033[0m Successfully extracted {hashes_found} hash(es).") + + +if __name__ == "__main__": + main()