Каждый день на NVD сыплются десятки новых CVE. Большинство пентестеров бегло глянут описание, запомнят CVSS-балл и пойдут дальше. А зря. В сухом тексте advisory, если знать куда смотреть, лежит практически готовый рецепт эксплойта: уязвимый эндпоинт, класс ошибки, затронутые версии и даже подсказка, какой gadget chain дёргать.
Русскоязычные публикации по теме CVE в основном разжёвывают, что такое CVSS и как устроен формат записи. Практической стороны - как превратить строчку из advisory в reverse shell - они не касаются вообще. В англоязычном пространстве получше: ребята из Orange Cyberdefense и OPSWAT публикуют полные writeup-ы с разбором кода. Но это всегда про конкретную дырку, а не про методологию.
Я разберу системный подход к анализу CVE advisory для open-source CMS и ERP, покажу его на двух свежих цепочках эксплуатации - CVE-2025-32432 в Craft CMS и CVE-2025-55182 в React Server Components - и дам конкретный workflow с инструментами, который можно натянуть на любую новую уязвимость в PHP- или JS-стеке.
Методология: от CVE-описания до рабочего эксплойта
Анализ CVE веб-приложений - не творчество, а ремесло с повторяемыми шагами. Каждый разбор уязвимости ERP-системы или CMS, который я проводил, укладывается в три фазы. Порядок важен: перескочите шаг - потеряете контекст и убьёте часы впустую.Шаг 1. Декомпозиция advisory - что читать и где искать
CVE-описание на NVD - отправная точка, но далеко не единственный источник. Вот что нужно вытащить и где это искать:Класс уязвимости (CWE). NVD указывает CWE-ID, и часто их несколько. Например, Log4Shell (CVE-2021-44228, CVSS 10.0 CRITICAL) имеет сразу четыре CWE: CWE-20 (Improper Input Validation), CWE-400 (Uncontrolled Resource Consumption), CWE-502 (Deserialization of Untrusted Data) и CWE-917 (Improper Neutralization of Special Elements used in an Expression Language Statement). Каждый CWE описывает отдельный аспект уязвимости (root cause, impact, категория), но не обязательно отдельный вектор эксплуатации. В случае Log4Shell основной вектор - CWE-917 (EL injection) и CWE-502 (десериализация объекта из LDAP).
Вектор CVSS. Не балл, а именно вектор.
AV:N/AC:L/PR:N/UI:N означает: сетевой доступ, низкая сложность, без привилегий, без взаимодействия пользователя - то есть pre-auth RCE, самый «вкусный» класс для атакующего. S:C (Scope: Changed) говорит, что эксплуатация затрагивает компоненты за пределами уязвимого модуля.GitHub Security Advisory (GHSA). Часто содержит больше деталей, чем NVD: конкретные коммиты с патчем, затронутые функции, иногда - PoC-фрагменты. Лично я начинаю именно с GHSA, а в NVD иду за CVSS-вектором.
CISA KEV (Known Exploited Vulnerabilities). Если CVE попала в каталог CISA - эксплуатация в дикой природе подтверждена. Такие CVE уже используются в реальных атаках, включая ransomware-кампании, и приоритет вашего ресёрча, максимальный.
Шаг 2. Patch diffing и локализация уязвимого кода
Advisory говорит «что сломано». Patch diff показывает «где именно». Для open-source проектов (Craft CMS, Dolibarr, OpenCart, Laravel-based ERP) этот шаг тривиален: берёте коммит из GHSA и смотрите diff.
На что обращать внимание в diff-е PHP-приложений:
- Добавление валидации входных данных - значит, раньше данные приходили в обработчик «как есть». Это ваша точка входа.
- Замена
createObject()/unserialize()/eval()на безопасные альтернативы - указывает на десериализацию или code injection. - Добавление проверок типов или whitelist-ов для параметров - раньше атакующий мог подставить произвольный класс или метод.
dol_eval(), dol_include_once() и прямые конкатенации SQL-запросов в модулях, которые изначально никто не проектировал с оглядкой на безопасность. Patch diffing в таких проектах регулярно обнажает годами не закрывавшиеся точки инъекции в административных интерфейсах (и это при том, что код открыт - бери да смотри).Шаг 3. Построение цепочки и proof of concept
Одиночная уязвимость редко даёт полноценный RCE. Обычно нужна цепочка: точка входа (инъекция, десериализация) плюс gadget (класс с опасными побочными эффектами при инстанциировании) плюс механизм доставки payload-а (запись во временный файл, сессию, лог).
Именно тут CWE-классификация из шага 1 становится картой: CWE-502 подсказывает искать gadget chains, CWE-94 указывает на code injection через пользовательский ввод, CWE-22 (path traversal) - на возможность чтения/записи произвольных файлов для доставки payload-а.
Теперь - к конкретике.
CVE-2025-32432: pre-auth RCE в Craft CMS через gadget chain Yii
CVSS-вектор:CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:L - оценка NVD: 10.0 (CRITICAL). Примечание: калькулятор FIRST для данного вектора с A:L даёт 9.6; расхождение с опубликованным NVD score 10.0 (который соответствует вектору с A:H) может указывать на несоответствие между вектором и score в записи NVD. Классификация: CWE-94 (Improper Control of Generation of Code, Code Injection). Уязвимость попала в каталог CISA KEV 2025-04-29.Затронутые версии: 3.0.0-RC1 - 3.9.14, 4.0.0-RC1 - 4.14.14, 5.0.0-RC1 - 5.6.16. Исправления выпущены в версиях 3.9.15, 4.14.15 и 5.6.17.
Анализ attack surface ERP и CMS: эндпоинт без аутентификации
Craft CMS использует механизм Image Transforms - серверную оптимизацию изображений. Эндпоинтactions/assets/generate-transform доступен без аутентификации, чтобы анонимные посетители тоже получали оптимизированные миниатюры. Согласно исследованию OPSWAT, метод AssetsController::actionGenerateTransform принимает POST-запрос и вытаскивает параметр handle из тела запроса, передавая его дальше по цепочке вызовов.Вот первый паттерн, который стоит запомнить: публичный эндпоинт, принимающий сложные структуры данных - красный флаг при аудите любой CMS или ERP на PHP-стеке. Если эндпоинт торчит наружу без аутентификации и ест массивы - копайте глубже.
Gadget chain: обход is_subclass_of через __class
📚 Этот материал доступен участникам сообщества с рангом One Level или выше
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме
CVE-2025-55182: десериализация в React Server Components без аутентификации
Если Craft CMS - пример PHP-цепочки, то CVE-2025-55182 (React2Shell) показывает тот же паттерн в JavaScript-стеке. Другой язык - та же болезнь.От POST-запроса до выполнения команд на сервере
Уязвимость затрагивает React Server Components - Server Actions в пакетахreact-server-dom-webpack, react-server-dom-parcel и react-server-dom-turbopack версий 19.0.0, 19.1.0, 19.1.1, 19.2.0. Опосредованно затронуты фреймворки, использующие эти пакеты: Next.js (App Router), react-router, waku, @parcel/rsc, @vitejs/plugin-rsc, rwsdk - конкретные уязвимые версии фреймворков уточняйте в соответствующих GHSA.Механизм эксплуатации прямолинеен: атакующий отправляет POST-запрос на эндпоинт Server Function с сериализованным набором данных. Обработчик выполняет небезопасную десериализацию без валидации - классический CWE-502. Никаких gadget chains, никаких хитрых обходов - десериализация сама по себе даёт RCE.
CISA добавила CVE-2025-55182 в каталог KEV 2025-12-05 (используется в ransomware-кампаниях).
Для временной блокировки эксплуатации до установки патчей, согласно рекомендациям из security-advisory проекта, фильтруйте POST-запросы, содержащие характерные маркеры десериализации в параметрах или теле:
#constructor, #[B]proto[/B], #prototype, vm#runInThisContext, child_process#execSync, child_process#spawnSync, module#_load, fs#readFileSync, fs#writeFileSync.Эти строки - готовые IoC для WAF-правил. Видите их в логах reverse proxy - эксплуатация уже идёт.
Паттерны уязвимостей в open-source ERP и CMS на PHP-стеке
Обе разобранные цепочки используют один принцип: публичный эндпоинт принимает сложную структуру данных, которая без достаточной валидации попадает в опасный вызов - будь тоYii::createObject(), PHP require или JS deserialize.В open-source ERP на PHP (Dolibarr, ERPNext с PHP-модулями, OpenCart) этот паттерн встречается с завидной регулярностью. На что смотреть при аудите:
Динамическое включение файлов. Функции вроде
dol_include_once() в Dolibarr, принимающие пользовательские параметры для формирования пути к файлу - потенциальный LFI -> RCE через log poisoning.Небезопасная десериализация.
unserialize() на данных из cookie, POST-параметров или кеша - путь к PHP Object Injection и gadget chains через популярные библиотеки (Monolog, Guzzle, Doctrine).SQL-инъекции в административных модулях. ERP-системы содержат десятки модулей для учёта, складов, HR - и не все проходят одинаково строгий code review. SQL-инъекция в модуле отчётов с правами DB-пользователя нередко позволяет
INTO OUTFILE для записи веб-шелла. На одном аудите мы нашли такую инъекцию в модуле складского учёта - он был написан сторонним контрибьютором и не ревьюился с 2019 года.Прямой вызов
eval() / system(). В PHP ERP-системах нередко встречаются кастомные шаблонизаторы и генераторы отчётов, использующие eval() для подстановки переменных - классический CWE-94. Разработчику было лень писать парсер, и вот результат.Разбор CVE advisory для таких систем отличается от CMS тем, что attack surface значительно больше: ERP-система может иметь сотни контроллеров с различными уровнями аутентификации.
Маппинг цепочки на MITRE ATT&CK
Цепочка эксплуатации веб-приложения - не единичное действие, а последовательность тактик. Маппинг на ATT&CK помогает и атакующему (понять, что делать после эксплуатации), и защитнику (знать, на каком этапе можно обнаружить атаку).Типичная цепочка от advisory до полного компромисса ERP/CMS:
| Этап | Тактика ATT&CK | Техника | Пример из CVE-2025-32432 |
|---|---|---|---|
| Начальный доступ | Initial Access | Exploit Public-Facing Application (T1190) | POST на generate-transform без аутентификации |
| Выполнение кода | Execution | Command and Scripting Interpreter (T1059) | PHP-код из session file выполняется через require (T1059 без подтехники, т.к. PHP не имеет dedicated sub-technique в ATT&CK); T1059.004 (Unix Shell) применяется только если payload явно вызывает /bin/sh |
| Закрепление | Persistence | Web Shell (T1505.003) | Установка PHP web shell после эксплуатации (MITRE ATT&CK описывает T1505.003 для Linux, Windows, macOS и Network, однако публичные тесты Atomic Red Team на момент написания доступны только для Windows) |
| Повышение привилегий | Privilege Escalation | Exploitation for Privilege Escalation (T1068) | Эскалация через gadget chain PhpManager |
| Обход защиты | Defense Evasion | Command Obfuscation (T1027.010) | Обфускация payload в параметрах сессии |
| Доступ к данным | Credential Access | Credentials In Files (T1552.001) | Чтение конфигов БД из .env / config/db.php |
| Исследование | Discovery | File and Directory Discovery (T1083) | Поиск конфигов, бэкапов, ключей API |
| Доставка инструментов | Command and Control | Ingress Tool Transfer (T1105) | Загрузка дополнительных инструментов через web shell |
Remote code execution в веб-приложении - это только T1190 + T1059. Весь остальной kill chain (T1505.003, T1552.001, T1083, T1105) происходит уже после первоначальной эксплуатации и представляет отдельные возможности для детекции. Иными словами, даже если RCE прошло - у защитника ещё есть шансы поймать атакующего на следующих шагах.
Практический workflow: инструменты и порядок действий
Требования к окружению
- ОС: Kali Linux или любой Linux с Docker
- Инструменты: Burp Suite Community/Pro, nuclei (последняя версия), curl, Docker/Docker Compose
- Сеть: изолированная лаборатория, НЕ тестировать на продуктивных системах без разрешения
- Целевая среда: Docker-контейнер с уязвимой версией приложения (Craft CMS <= 5.6.16, или любая другая target CVE)
Фаза 1: Разведка. Первым делом проверьте, есть ли CVE в каталоге CISA KEV:
curl -s "https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json" | jq '.vulnerabilities[] | select(.cveID=="CVE-XXXX-XXXXX")'. Если есть - эксплуатация подтверждена, приоритет максимальный.Фаза 2: Сбор контекста. Найдите GHSA advisory и patch commit на GitHub. Скачайте уязвимую версию приложения. Для Craft CMS:
composer create-project craftcms/craft vulnerable-craft && cd vulnerable-craft && composer require craftcms/cms:5.6.16 -W.Фаза 3: Patch diff. Сравните уязвимую и исправленную версии:
Bash:
git clone https://github.com/craftcms/cms.git
cd cms
git diff 5.6.16..5.6.17 -- src/controllers/AssetsController.php
git diff 5.6.16..5.6.17 -- src/services/ImageTransforms.php
Фаза 4: Воспроизведение. Поднимите уязвимую версию в Docker, сконфигурируйте Burp Suite как прокси, воспроизведите цепочку вручную. Отправьте POST-запрос на уязвимый эндпоинт, отследите поведение приложения в Burp Repeater.
Фаза 5: Детекция. После понимания механизма эксплуатации напишите nuclei-шаблон для массового сканирования. Для CVE в open-source CMS структура шаблона стандартна - матчите специфичный ответ сервера на crafted-запрос:
YAML:
id: CVE-2025-32432-detect
info:
name: Craft CMS RCE - Version Detection
severity: critical
reference:
- https://github.com/craftcms/cms/security/advisories/GHSA-f3gw-9ww9-jmc3
http:
- method: POST
path:
- "{{BaseURL}}/actions/assets/generate-transform"
headers:
Content-Type: application/x-www-form-urlencoded
body: "handle=test"
matchers-condition: and
matchers:
- type: status
status: [200, 400, 403]
- type: word
part: header
words:
- "X-Powered-By: Craft CMS"
# NB: точное сообщение об ошибке зависит от версии; проверьте AssetsController.php
Фаза 6: Отчёт. Документируйте каждый шаг цепочки с привязкой к ATT&CK: какая техника на каком этапе использовалась, какой HTTP-запрос отправлен, какой ответ получен. Это превращает ваш writeup из «нашёл дырку» в воспроизводимое исследование, которое коллега сможет повторить без звонка вам в три ночи.
Для CVE-2025-55182 подход аналогичен, но вместо PHP patch diff анализируйте изменения в пакетах
react-server-dom-webpack. Ключевое отличие: здесь нет gadget chain, десериализация сама по себе даёт RCE. Основной фокус - на формате сериализованного payload-а и валидации, которую добавил патч.Вопрос к читателям
CVE-2025-32432 в Craft CMS эксплуатирует цепочкуYii::createObject() -> __class override -> PhpManager::loadFromFile(). В Dolibarr и аналогичных PHP ERP есть похожие паттерны с динамическим инстанциированием классов. Кто поднимал Dolibarr в Docker для аудита - в каких модулях вы находили вызовы dol_eval() или прямую конкатенацию пользовательского ввода в SQL-запрос? Поделитесь конкретным путём: контроллер, метод, параметр - интересно сравнить attack surface разных версий.
Последнее редактирование модератором: