From 79dc09ec2e661c79f5e35d2f8d50150573203157 Mon Sep 17 00:00:00 2001 From: Chris Gavin Date: Wed, 23 Oct 2024 11:40:52 +0100 Subject: [PATCH 1/7] Fix handling of cookies in Chromium cookie database versions >=24. --- src/pycookiecheat/chrome.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/pycookiecheat/chrome.py b/src/pycookiecheat/chrome.py index 2ecee56..736336b 100644 --- a/src/pycookiecheat/chrome.py +++ b/src/pycookiecheat/chrome.py @@ -66,7 +66,7 @@ def clean(decrypted: bytes) -> str: def chrome_decrypt( - encrypted_value: bytes, key: bytes, init_vector: bytes + encrypted_value: bytes, key: bytes, init_vector: bytes, cookie_database_version: int ) -> str: """Decrypt Chrome/Chromium's encrypted cookies. @@ -88,6 +88,10 @@ def chrome_decrypt( decryptor = cipher.decryptor() decrypted = decryptor.update(encrypted_value) + decryptor.finalize() + if cookie_database_version >= 24: + # Cookies in database version 24 and later include a SHA256 hash of the domain to the start of the encrypted value. + decrypted = decrypted[32:] + return clean(decrypted) @@ -310,6 +314,9 @@ def chrome_cookies( conn.row_factory = sqlite3.Row + sql = "select value from meta where key = 'version';" + cookie_database_version = int(conn.execute(sql).fetchone()[0]) + # Check whether the column name is `secure` or `is_secure` secure_column_name = "is_secure" for ( @@ -344,6 +351,7 @@ def chrome_cookies( row["encrypted_value"], key=enc_key, init_vector=config["init_vector"], + cookie_database_version=cookie_database_version, ) del row["encrypted_value"] cookies.append(Cookie(**row)) From c105fdb14b62d5aead5201d0515bc4d24a57f47c Mon Sep 17 00:00:00 2001 From: Chris Gavin Date: Wed, 23 Oct 2024 13:57:38 +0100 Subject: [PATCH 2/7] Handle non-UTF8 sequences in encrypted cookie values. --- src/pycookiecheat/chrome.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/pycookiecheat/chrome.py b/src/pycookiecheat/chrome.py index 736336b..2215370 100644 --- a/src/pycookiecheat/chrome.py +++ b/src/pycookiecheat/chrome.py @@ -313,6 +313,7 @@ def chrome_cookies( raise e conn.row_factory = sqlite3.Row + conn.text_factory = bytes sql = "select value from meta where key = 'version';" cookie_database_version = int(conn.execute(sql).fetchone()[0]) @@ -354,6 +355,9 @@ def chrome_cookies( cookie_database_version=cookie_database_version, ) del row["encrypted_value"] + for key, value in row.items(): + if isinstance(value, bytes): + row[key] = value.decode("utf8") cookies.append(Cookie(**row)) conn.rollback() From 5ee552728fb4026fb6fb25e860a50bd71e14f1ed Mon Sep 17 00:00:00 2001 From: Chris Gavin Date: Wed, 23 Oct 2024 13:59:11 +0100 Subject: [PATCH 3/7] Wrap some long lines. --- src/pycookiecheat/chrome.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/pycookiecheat/chrome.py b/src/pycookiecheat/chrome.py index 2215370..1790183 100644 --- a/src/pycookiecheat/chrome.py +++ b/src/pycookiecheat/chrome.py @@ -66,7 +66,8 @@ def clean(decrypted: bytes) -> str: def chrome_decrypt( - encrypted_value: bytes, key: bytes, init_vector: bytes, cookie_database_version: int + encrypted_value: bytes, key: bytes, init_vector: bytes, + cookie_database_version: int ) -> str: """Decrypt Chrome/Chromium's encrypted cookies. @@ -89,7 +90,8 @@ def chrome_decrypt( decrypted = decryptor.update(encrypted_value) + decryptor.finalize() if cookie_database_version >= 24: - # Cookies in database version 24 and later include a SHA256 hash of the domain to the start of the encrypted value. + # Cookies in database version 24 and later include a SHA256 + # hash of the domain to the start of the encrypted value. decrypted = decrypted[32:] return clean(decrypted) From ead2b752d8a001cb64ee3aaac6da5ff64f9bf286 Mon Sep 17 00:00:00 2001 From: Chris Gavin Date: Wed, 23 Oct 2024 14:00:53 +0100 Subject: [PATCH 4/7] Add a link to the Chromium source code explaining the version 24 format. --- src/pycookiecheat/chrome.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/pycookiecheat/chrome.py b/src/pycookiecheat/chrome.py index 1790183..9c880bf 100644 --- a/src/pycookiecheat/chrome.py +++ b/src/pycookiecheat/chrome.py @@ -92,6 +92,9 @@ def chrome_decrypt( if cookie_database_version >= 24: # Cookies in database version 24 and later include a SHA256 # hash of the domain to the start of the encrypted value. + # https://github.com/chromium/chromium/blob/ + # 280265158d778772c48206ffaea788c1030b9aaa/net/extras/ + # sqlite/sqlite_persistent_cookie_store.cc#L223-L224 decrypted = decrypted[32:] return clean(decrypted) From a01f3f56098ff50d907dd450965c85d11d16f5dd Mon Sep 17 00:00:00 2001 From: Chris Gavin Date: Wed, 23 Oct 2024 14:03:58 +0100 Subject: [PATCH 5/7] Handle missing meta table and version in the cookie database. --- src/pycookiecheat/chrome.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/pycookiecheat/chrome.py b/src/pycookiecheat/chrome.py index 9c880bf..af7d4d8 100644 --- a/src/pycookiecheat/chrome.py +++ b/src/pycookiecheat/chrome.py @@ -321,7 +321,15 @@ def chrome_cookies( conn.text_factory = bytes sql = "select value from meta where key = 'version';" - cookie_database_version = int(conn.execute(sql).fetchone()[0]) + cookie_database_version = 0 + try: + row = conn.execute(sql).fetchone() + if row: + cookie_database_version = int(row[0]) + else: + logger.info("cookie database version not found in meta table") + except sqlite3.OperationalError as e: + logger.info("cookie database is missing meta table") # Check whether the column name is `secure` or `is_secure` secure_column_name = "is_secure" From 34c5a28424a4a980287c0a7e5f6ca915d5118734 Mon Sep 17 00:00:00 2001 From: Chris Gavin Date: Wed, 23 Oct 2024 14:07:18 +0100 Subject: [PATCH 6/7] Remove an unused variable. --- src/pycookiecheat/chrome.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pycookiecheat/chrome.py b/src/pycookiecheat/chrome.py index af7d4d8..186dc68 100644 --- a/src/pycookiecheat/chrome.py +++ b/src/pycookiecheat/chrome.py @@ -328,7 +328,7 @@ def chrome_cookies( cookie_database_version = int(row[0]) else: logger.info("cookie database version not found in meta table") - except sqlite3.OperationalError as e: + except sqlite3.OperationalError: logger.info("cookie database is missing meta table") # Check whether the column name is `secure` or `is_secure` From 4028b202442cac2cc5316ee37ec2e6ea121be8b2 Mon Sep 17 00:00:00 2001 From: Chris Gavin Date: Wed, 23 Oct 2024 14:12:36 +0100 Subject: [PATCH 7/7] Run black. --- src/pycookiecheat/chrome.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/pycookiecheat/chrome.py b/src/pycookiecheat/chrome.py index 186dc68..a31d213 100644 --- a/src/pycookiecheat/chrome.py +++ b/src/pycookiecheat/chrome.py @@ -66,8 +66,10 @@ def clean(decrypted: bytes) -> str: def chrome_decrypt( - encrypted_value: bytes, key: bytes, init_vector: bytes, - cookie_database_version: int + encrypted_value: bytes, + key: bytes, + init_vector: bytes, + cookie_database_version: int, ) -> str: """Decrypt Chrome/Chromium's encrypted cookies.