Когда меня дёргают на инцидент с формулировкой «пользователь жалуется на странное поведение браузера - редиректы, утечка сессий, несанкционированный доступ к корпоративным аккаунтам», первое, что я проверяю - не история посещений и не cookies. Я лезу в директорию расширений. Потому что именно аддоны оказываются причиной инцидента куда чаще, чем принято думать, а стандартные IR-плейбуки до сих пор обходят этот вектор стороной.
Форензика браузерных расширений - дисциплина на стыке endpoint forensics и анализа веб-приложений. Расширение по сути - маленькое приложение с привилегированным доступом к браузерному контексту: DOM страниц, cookies, session tokens, буфер обмена. Если оно скомпрометировано - атакующий получает всё, что видит пользователь, и даже больше. Разберу конкретные артефакты, пути к файлам, инструменты и пошаговую методологию расследования инцидентов, связанных с вредоносными расширениями Chrome и Firefox.
Почему расширения - слепая зона при расследовании инцидентов
Большинство руководств по цифровой криминалистике браузеров крутятся вокруг классических артефактов: History, Cookies, Web Data, Cache. Расширения упоминаются вскользь - мол, «список установленных плагинов». Но расширение - это не статичный плагин. Это исполняемый код с собственным хранилищем, сетевыми соединениями и жизненным циклом.Масштаб проблемы хорошо иллюстрирует инцидент конца 2024 года: по данным Darktrace, атакующие скомпрометировали более 30 расширений Chrome, включая расширение компании Cyberhaven, затронув свыше 2,6 миллиона пользователей. Вредоносное обновление прилетело через штатный механизм автообновления Chrome - без какого-либо взаимодействия с пользователем. Параллельно, по анализу SecurityLab, всплыла кампания из 30 расширений с единой кодовой базой и общей инфраструктурой на домене
tapnetic.pro, набравших суммарно более 260 000 установок. Часть этих расширений даже получила статус Featured в Chrome Web Store (ага, вот так и живём).При расследовании подобных инцидентов стандартный набор браузерных артефактов бесполезен - в истории посещений вы не увидите, что расширение в фоне сливает session cookies на C2-сервер. Нужен другой подход и другие артефакты.
Карта артефактов расширений в Chrome
Все данные Chrome на Windows лежат в%LocalAppData%\Google\Chrome\User Data\Default\. На Linux - ~/.config/google-chrome/Default/, на macOS - ~/Library/Application Support/Google/Chrome/Default/. Внутри профиля есть несколько ключевых точек, относящихся к расширениям.Manifest.json - паспорт каждого расширения
ДиректорияExtensions содержит поддиректории по ID расширения (32-символьная строка из букв a–p, получаемая маппингом первых 16 байт SHA-256 хеша публичного ключа: каждый hex-символ 0–f преобразуется в a–p), внутри - папки по версиям. В каждой версии лежит manifest.json - первый файл, который я открываю при анализе браузерных расширений.На что смотреть в manifest.json:
- Поле
permissions- уровень доступа. Если, например, расширение-калькулятор запрашиваетcookies,webRequest,tabs,<all_urls>- это красный флаг. В кампании tapnetic.pro все 30 расширений имели идентичный набор широких разрешений, несмотря на разные заявленные функции. - Поле
content_scriptsсmatches: ["<all_urls>"]- расширение инжектирует код во все страницы. - Поле
background- в MV2 указывает на background page (persistent), в MV3 - на service worker. Подробнее о разнице ниже. - Поле
externally_connectable- список доменов, которые могут обмениваться сообщениями с расширением. - Поле
update_url- откуда приходят обновления. Если это неhttps://clients2.google.com/service/update2/crx(стандартный URL Chrome Web Store), расширение обновляется из стороннего источника.
Preferences и Secure Preferences - реестр установленных аддонов
ФайлыPreferences и Secure Preferences в корне профиля Chrome - JSON-файлы с полным реестром всех расширений. Секция extensions.settings хранит для каждого расширения: время установки (install_time), источник (install_source), предоставленные разрешения (granted_permissions), состояние (включено/отключено/заблокировано), URL обновления и причину отключения (disable_reasons).Это критически важный артефакт при анализе установленных расширений - он сохраняет информацию даже о расширениях, которые были отключены политикой или пользователем. Поле
install_time хранит время в формате Chrome/WebKit (микросекунды с 1 января 1601 года) в виде строки - перед арифметикой конвертируйте в int. Формула: unix_ts = (int(install_time) - 11644473600000000) / 1000000.Secure Preferences содержит HMAC-подписи настроек, что защищает от ручной модификации. Для форензики это плюс: если подпись не совпадает - файл был изменён вне браузера, и это само по себе артефакт.LevelDB и Local Storage - данные расширений в хранилищах
Расширения используют несколько хранилищ для оперативных данных.chrome.storage.local лежит в Local Extension Settings/<extension_id>/ (отдельная LevelDB на каждое расширение). chrome.storage.sync - в Sync Extension Settings/<extension_id>/ (локальный LevelDB-кэш; при включённом Chrome Sync данные синхронизируются с аккаунтом Google, при отключённом - API работает в локальном режиме). chrome.storage.managed (настройки от корпоративных политик) - в Managed Extension Settings/<extension_id>/. chrome.storage.session живёт только в RAM и на диск не пишется. Если расширение использует localStorage в своих extension pages, данные попадают в Local Storage/leveldb/ с ключом chrome-extension://<id>.LevelDB - key-value хранилище от Google, и его парсинг - одна из самых муторных задач в форензике расширений. Файлы
.ldb и .log содержат записи в бинарном формате. Для извлечения я использую Python-библиотеку plyvel или утилиту leveldb-dump. Проблема в том, что LevelDB-записи часто оказываются corrupted на живой системе из-за незавершённых транзакций - тогда помогает прямой парсинг .log-файлов, где лежат последние незафиксированные записи.Именно в Local Storage вредоносные расширения хранят конфигурацию C2-серверов, эксфильтрированные данные до отправки и промежуточные состояния. В кампании Cyberhaven, по данным Darktrace, расширение собирало session cookies и authentication tokens - эти данные транзитно проходили через локальное хранилище перед отправкой на
cyberhavenext[.]pro.Артефакты браузерных аддонов в Firefox
Firefox хранит данные расширений иначе. Профиль по умолчанию живёт в%AppData%\Roaming\Mozilla\Firefox\Profiles\<random>.default-release\ на Windows.Ключевые файлы для анализа вредоносных расширений в Firefox:
extensions.json- полный реестр расширений с метаданными: ID, версия, путь установки, время, источник, активность.addons.json- дополнительные метаданные: описание, автор, homepage.prefs.js- пользовательские настройки, включая параметры расширений. Бывает, что вредоносные аддоны правятprefs.jsдля подмены поисковой системы или homepage.storage/default/moz-extension+++<random-UUID>/- IndexedDB-хранилище данных расширения (UUID рандомизирован per-profile; соответствие UUID ↔ extension ID лежит вprefs.jsв ключеextensions.webextensions.uuids). Дляbrowser.storage.localданные вbrowser-extension-data/<extension_id>/. Firefox использует SQLite для IndexedDB, что упрощает парсинг - хватит DB Browser for SQLite.- Директория
extensions/- XPI-файлы (по сути ZIP-архивы) установленных расширений.
MV2 против MV3: что меняется для анализа браузерных расширений
Переход Chrome с Manifest V2 на Manifest V3 серьёзно влияет на то, какие артефакты остаются на диске. Для цифровой криминалистики браузера это различие - ключевое.MV2 (устаревший, но встречается на живых системах). Background page - полноценная HTML-страница с постоянным JavaScript-контекстом. Работает непрерывно, пока браузер открыт. Артефакты: файл background page в директории расширения, записи в
chrome://extensions-internals, постоянное соединение с C2 видно в сетевых логах как длительная сессия.MV3 (текущий стандарт). Service worker заменяет background page. Он запускается по событию и завершается после 30 секунд бездействия. До Chrome 110 действовал жёсткий лимит в 5 минут с момента запуска SW, независимо от активности; с Chrome 110+ активные события (входящие сообщения, API-вызовы) сбрасывают idle-таймер, и SW может жить дольше. Через
chrome.alarms (минимальный интервал 30 сек) SW периодически пробуждается - это позволяет поддерживать близкое к постоянному присутствие, хотя полностью persistent-режим MV2 недостижим. Артефакты: service worker регистрируется в Service Worker/ директории профиля, но его состояние эфемерно. Сетевая активность становится прерывистой - короткие всплески вместо постоянного beaconing. Для расследования инцидентов это значит, что окно для поимки активной коммуникации с C2 сужается.Практическое следствие: при MV3 вредоносное расширение сложнее поймать на горячем через анализ сетевых соединений. Зато в
Service Worker/ScriptCache/ остаются кэшированные версии service worker-скрипта, включая предыдущие - а там может быть вредоносный код даже после обновления расширения до «чистой» версии. Я начинаю именно с этого кэша, когда работаю с MV3-расширениями.Пошаговый анализ установленных расширений при инциденте
Триаж за первые 15 минут
При получении образа или доступе к живой машине первым делом снимаю снапшот расширений. Вот последовательность, которую я выполняю при каждом IR-кейсе, связанном с компрометацией через расширения браузера:Шаг 1. Копирую директорию профиля целиком с сохранением временных меток. На Windows:
robocopy "%LocalAppData%\Google\Chrome\User Data" E:\evidence\chrome_profile /MIR /COPY:DAT /LOG:E:\evidence\copy.log. Ключ /COPY:DAT обязателен - без него timestamps поплывут.Шаг 2. Вытаскиваю список расширений из
Preferences. Однострочник на jq:
Bash:
cat Preferences | jq '.extensions.settings | to_entries[] | {id: .key, name: .value.manifest.name, version: .value.manifest.version, install_time: .value.install_time, permissions: .value.manifest.permissions, update_url: (.value.update_url // .value.manifest.update_url), location: .value.location, install_source: .value.install_source}' > extensions_inventory.json
update_url указывает не на стандартный Google endpoint - немедленный красный флаг. Но для расширений из Chrome Web Store поле update_url часто отсутствует в манифесте - его отсутствие не означает sideload. Надёжнее смотреть на location != 1 или install_source != "webstore" в Preferences.Шаг 4. Проверяю
permissions каждого расширения на избыточный доступ: комбинация cookies + webRequest + <all_urls> у расширения, не связанного с безопасностью или разработкой - аномалия.Шаг 5. Фиксирую временные метки установки и последнего обновления, выстраиваю timeline.
Глубокий анализ подозрительного расширения
Когда триаж выявил подозрительное расширение, перехожу к полной декомпозиции.Открываю директорию расширения (
Extensions/<id>/<version>/) и изучаю JS-файлы. Обфусцированный код - не обязательно признак вредоносности (многие легитимные расширения минифицируют JS), но в сочетании с избыточными permissions это повод для деобфускации. Прогоняю через js-beautify для форматирования и дальше - ручной анализ.В кампании tapnetic.pro, описанной SecurityLab, ключевым индикатором был iframe, загружающий интерфейс с внешнего домена (
claude.tapnetic.pro). Такой паттерн - когда core-логика расширения приходит не из локального кода, а подгружается с внешнего сервера - один из самых надёжных маркеров обнаружения вредоносных расширений. В коде это выглядит как динамическое создание iframe с src, указывающим на левый домен.Дальше - сетевые артефакты. На живой системе -
chrome://net-export для захвата сетевой активности браузера. На уровне хоста - Sysmon Event ID 22 (DNS Query) с фильтрацией по процессу chrome.exe, EDR-телеметрия или network capture с корреляцией по времени. Сопоставление выявленных доменов с C2-индикаторами (например, cyberhavenext[.]pro или 149.28.124[.]84 из кейса Cyberhaven) - прямое доказательство компрометации.Обнаружение вредоносных расширений Chrome и Firefox
Для систематического обнаружения вредоносных расширений (а не только ручного ковыряния конкретного образца) есть несколько подходов.По данным Red Canary, использование фреймворка AssemblyLine в связке со статистическими методами - анализом энтропии и z-scores - позволяет автоматически детектировать подозрительные обновления расширений. В их эксперименте подход выявил 58% известных вредоносных расширений из выборки в 50 скомпрометированных образцов. Решение заточено на сокращение dwell time: поймать вредоносное обновление до того, как оно станет широко известным.
Любопытная цифра от Red Canary: типичная корпоративная среда содержит порядка 30 расширений на пользователя, а в отдельных случаях - более 3000. Тридцать ещё можно проверить руками. Три тысячи - нет. Инвентаризация расширений через EDR - обязательный первый шаг.
Маппинг на MITRE ATT&CK
Вредоносное расширение покрывает сразу несколько тактик и техник MITRE ATT&CK, что делает его универсальным инструментом атакующего:| Тактика | Техника | Как реализуется через расширение |
|---|---|---|
| Persistence | Browser Extensions (T1176.001) | Расширение переживает перезагрузку браузера и ОС |
| Credential Access | Steal Web Session Cookie (T1539) | Доступ к cookies API для кражи сессий |
| Credential Access | Credentials from Web Browsers (T1555.003) | Чтение сохранённых паролей через DOM или API |
| Collection | Browser Session Hijacking (T1185) | Перехват активной сессии через инжектированный скрипт |
| Collection | Data from Local System (T1005) | Чтение DOM страниц, включая email-переписку |
| Collection / Credential Access | Keylogging (T1056.001) | Перехват ввода через content script |
| Discovery | Browser Information Discovery (T1217) | Сбор данных о профиле, установленных расширениях |
| Exfiltration | Exfiltration Over C2 Channel (T1041) | Отправка данных на C2 через HTTP POST |
В кейсе Cyberhaven цепочка выглядела так: T1176.001 (Browser Extensions) → T1539 (Steal Web Session Cookie) → T1185 (Browser Session Hijacking) → T1041 (Exfiltration Over C2 Channel - на
cyberhavenext[.]pro). Darktrace зафиксировала 27 уникальных устройств, подключавшихся к C2 начиная с 3 декабря, а за двухдневный период два устройства передали 5,57 ГиБ входящих и 859,37 МиБ исходящих данных. Немало для «расширения-помощника».Кейс: компрометация Cyberhaven и массовые кампании через расширения
Инцидент с Cyberhaven - эталонный пример supply chain атаки через расширения. 24 декабря 2024 года фишинговая атака скомпрометировала учётные данные сотрудника Cyberhaven, что позволило атакующим опубликовать вредоносную версию расширения. Момент выбран не случайно, рождественские каникулы - большинство сотрудников отсутствует. Вредоносная версия была активна 25–26 декабря.Механизм: расширение после обновления начинало скрытно собирать session cookies и authentication tokens, целясь в высокоценные аккаунты - Facebook Ads, AI-сервисы. По данным Darktrace, на стороне сети это выглядело как persistent beaconing на домен
cyberhavenext[.]pro, замаскированный под легитимный cyberhaven[.]io. Подключения шли к IP 149.28.124[.]84, ассоциированному с двумя SSL-hostname, включая вредоносный домен.Параллельно работала кампания вокруг
tapnetic.pro: 30 расширений с разными названиями и ID, но единой кодовой базой. Расширения маскировались под AI-ассистентов (Claude, ChatGPT, Gemini, Grok) и помощников для Gmail. Отдельный модуль для Gmail запускался на mail.google.com, использовал MutationObserver для отслеживания DOM и многократно вытягивал содержимое переписки через textContent. Операторы быстро восстанавливали удалённые расширения: расширение с ID fppbiomdkfbhgjjdmojlogeceejinadg, удалённое 6 февраля 2025 года, появилось копией с ID gghdfkafnhfpaooiolhncejnlgglhkhe уже 20 февраля - с идентичным кодом, разрешениями и серверной инфраструктурой. Гидра, а не кампания.Следы удалённых расширений: что остаётся после деинсталляции
Один из самых частых вопросов на реальных расследованиях: «Расширение уже удалено, можно ли восстановить следы?» Короткий ответ - да, и нередко артефакты живут месяцами.При штатном удалении расширения через UI Chrome удаляет директорию из
Extensions/<id>/, но следы остаются в нескольких местах:PreferencesиSecure Preferences- запись о расширении может быть помечена как удалённая, но не стёрта из файла. Grep по ID в этих файлах часто даёт результат.Local Extension Settings/<id>/- директорияchrome.storage.localобычно удаляется вместе с расширением, но может быть восстановлена из NTFS-артефактов ($MFT, unallocated space).Local Storage/leveldb/- записиwindow.localStorageextension pages с ключомchrome-extension://<id>физически удаляются из LevelDB, но до компактификации базы остаются в.ldb-файлах как tombstone-записи. Прямой парсинг бинарных файлов (черезstringsили hex-редактор) может выявить остатки данных.Favicons- SQLite-база с иконками расширений. Записи остаются после удаления.- Sync-метаданные - если был включен Chrome Sync, информация о расширении может сохраняться в
Sync Data/. - Windows: файлы в NTFS могут быть восстановлены из
$MFT, если не были перезаписаны. FTK Imager позволяет вытащить удалённые директории расширений из нераспределённого пространства.
Preferences обновляется с записью disable_reasons, содержащей флаг принудительного отключения. Это позволяет установить, что расширение было удалено административно, а не пользователем.Ключевое различие: если пользователь сам удалил расширение - в
Preferences остаётся минимум информации. Если расширение заблокировано политикой или Safe Browsing - записывается причина блокировки, и это само по себе доказательный артефакт.Incident response при компрометации через расширения браузера
Когда компрометация подтверждена, IR-процесс для расширений имеет свою специфику.Containment. Немедленно блокируем расширение через групповую политику Chrome (
[URL='https://chromeenterprise.google/policies/#ExtensionInstallBlocklist']ExtensionInstallBlocklist[/URL]). Если ID вредоносного расширения известен - в blocklist. Если подозрение на supply chain (легитимное расширение получило вредоносное обновление, как в кейсе Cyberhaven) - блокируем автообновление расширений до завершения расследования. На уровне сети - блокируем известные C2-домены и IP-адреса.Eradication. Удаляем расширение со всех endpoint через централизованное управление. Обязательно проверяем, не осталось ли persistence-механизмов вне браузера: некоторые расширения создают scheduled tasks или правят registry для автоматической переустановки.
Recovery. Сбрасываем все сессии пользователей, чьи машины были скомпрометированы. Принудительная ротация паролей для сервисов, к которым расширение имело доступ. Если расширение имело permission
cookies - считаем все активные сессии скомпрометированными. Без вариантов.Lessons Learned. Внедряем инвентаризацию расширений через EDR. Настраиваем allowlist-политику: разрешить только проверенные расширения через
ExtensionInstallAllowlist. Мониторим аномальную сетевую активность браузерных процессов - persistent beaconing к rare domains, как в случае с Cyberhaven, должен генерировать алерт.Для автоматизации анализа расширений в масштабе организации стоит посмотреть на Hindsight (есть на GitHub) - он парсит артефакты Chrome, включая данные расширений, и строит единый timeline. Для побитового анализа образов дисков - Autopsy с модулем Chrome Extensions.
Вопрос к практикам
В инфраструктуре с Chrome, управляемом через групповые политики, расширения контролируются черезExtensionInstallAllowlist и ExtensionInstallBlocklist. Но на практике поддерживать allowlist на сотнях машин - боль, особенно когда бизнес-подразделения постоянно просят добавить «ещё одно расширение для Jira/Confluence/Figma». Кто из вас автоматизировал аудит запрашиваемых расширений перед добавлением в allowlist - через CRXcavator, кастомные скрипты парсинга manifest.json из CWS, или как-то иначе? Покажите конкретную связку: источник метаданных расширения, критерии accept/reject (например, максимальный набор permissions), и куда встроен этот чек - в тикет-систему, CI или ручной процесс?Вопрос к читателям
Коллеги, при разборе LevelDB-хранилищ расширений (Local Extension Settings/<extension_id>/) на живой системе часто встречаются corrupted-записи из-за незавершённых транзакций. Какой тулчейн вы используете для надёжного извлечения данных в таких случаях: plyvel с перехватом plyvel.Error и fallback на прямой парсинг .log-файлов, или что-то вроде leveldb-dump / ldb из пакета leveldb-tools? Если работали с расширениями из кампании tapnetic.pro или аналогичными MV3-аддонами - какие ключи в chrome.storage.local оказались информативны для реконструкции C2-конфигурации? Поделитесь конкретным jq-фильтром или Python-сниппетом с флагами открытия БД - особенно интересен опыт с образами, снятыми без предварительного graceful shutdown браузера.
Последнее редактирование модератором: