diff --git a/libs/chromium/chromium/helpers.py b/libs/chromium/chromium/helpers.py index 7450cbb..74e52a2 100644 --- a/libs/chromium/chromium/helpers.py +++ b/libs/chromium/chromium/helpers.py @@ -8,8 +8,7 @@ import psycopg import structlog from Crypto.Cipher import AES, ChaCha20_Poly1305 from dapr.clients import DaprClient -from impacket.dpapi import DPAPI_BLOB -from impacket.uuid import bin_to_string +from nemesis_dpapi import Blob logger = structlog.get_logger(module=__name__) @@ -101,15 +100,10 @@ def detect_encryption_type(encrypted_value: bytes) -> tuple[str, str | None]: # Check for DPAPI (first 4 bytes are \x01\x00\x00\x00) if encrypted_value[:4] == b"\x01\x00\x00\x00": try: - blob = DPAPI_BLOB(encrypted_value) - if blob.rawData is not None: - blob.rawData = blob.rawData[: len(blob.getData())] - masterkey_guid = bin_to_string(blob["GuidMasterKey"]).lower() - return "dpapi", masterkey_guid + blob = Blob.parse(encrypted_value) + return "dpapi", str(blob.masterkey_guid) except Exception as e: - logger.warning("Failed to parse DPAPI blob", error=str(e)) - return "dpapi", None - return "dpapi", None + raise Exception(f"Found DPAPI app bound key, but couldn't parse blob: {str(e)}") from e # Check for key-based encryption (v10, v11) if len(encrypted_value) >= 3: diff --git a/libs/chromium/chromium/local_state.py b/libs/chromium/chromium/local_state.py index eb380ba..e3975a3 100644 --- a/libs/chromium/chromium/local_state.py +++ b/libs/chromium/chromium/local_state.py @@ -57,7 +57,7 @@ async def process_chromium_local_state( with psycopg.connect(conn_str) as pg_conn: state_key_data = await _insert_state_keys(file_enriched, username, browser, content, pg_conn, dpapi_manager) - logger.warning("Completed processing Chromium Local State", object_id=object_id) + logger.debug("Completed processing Chromium Local State", object_id=object_id) return state_key_data @@ -155,6 +155,7 @@ async def _insert_state_keys( app_bound_key_b64 = os_crypt.get("app_bound_encrypted_key") app_bound_key_enc = b"" app_bound_key_system_masterkey_guid = None + app_bound_key_user_masterkey_guid = None if app_bound_key_b64: logger.debug("Found v2 app bound key encrypted_key in Local State") diff --git a/libs/chromium/chromium/logins.py b/libs/chromium/chromium/logins.py index a9c069f..210ea2d 100644 --- a/libs/chromium/chromium/logins.py +++ b/libs/chromium/chromium/logins.py @@ -1,7 +1,7 @@ """Chromium Login Data file parsing and database operations.""" -import sqlite3 import asyncio +import sqlite3 import psycopg import structlog @@ -109,7 +109,7 @@ def _insert_logins( try: password_dec_bytes = asyncio.run(dpapi_manager.decrypt_blob(Blob.parse(password_value))) if password_dec_bytes: - password_value_dec = password_dec_bytes.decode('utf-8', errors='replace') + password_value_dec = password_dec_bytes.decode("utf-8", errors="replace") is_decrypted = True except: pass @@ -134,13 +134,15 @@ def _insert_logins( password_dec_bytes = password_dec_bytes[:-16] # v20 passwords typically don't have offset like cookies - password_value_dec = password_dec_bytes.decode('utf-8', errors='replace') + password_value_dec = password_dec_bytes.decode("utf-8", errors="replace") is_decrypted = True except Exception as e: - logger.debug("Failed to decrypt password with state key", - state_key_id=state_key_id, - encryption_type=encryption_type, - error=str(e)) + logger.debug( + "Failed to decrypt password with state key", + state_key_id=state_key_id, + encryption_type=encryption_type, + error=str(e), + ) login_data = { "originating_object_id": file_enriched.object_id,