
CVE-2026-63030
Proof-of-concept для неаутентифицированной SQL-инъекции в ядре WordPress, которая приводит к удалённому выполнению кода через путаницу маршрутов REST batch (CVE-2026-63030).
Эксплойту не требуются учётные данные и какая-либо конфигурация, кроме доступной цели. Он добирается до инъекции через единственную конечную точку: POST /wp-json/batch/v1.
Сама находка — это неаутентифицированная SQL-инъекция: check подтверждает её, а read демонстрирует произвольное чтение базы данных. Команда shell — необязательная пост-эксплуатация (восстановленные учётные данные администратора → загрузка плагина → выполнение команд), включена для демонстрации полного воздействия; она не является уязвимостью.
| Ветка | Затронуты | Исправлена в |
|---|---|---|
| 6.9.x | 6.9.0 – 6.9.4 | 6.9.5 |
| 7.0.x | 7.0.0 – 7.0.1 | 7.0.2 |
Версии до 6.9.0 не затрагиваются этой цепочкой.
Конечная точка REST batch (/batch/v1) не требует аутентификации и выполняет несколько подзапросов за один вызов, полагаясь на то, что каждый подзапрос проверяется и проходит проверку прав доступа самостоятельно.
serve_batch_request_v1() создаёт два параллельных массива — $matches (подходящий обработчик для каждого подзапроса) и $validation (результат проверки для каждого подзапроса) — а затем при отправке обращается к обоим по одному и тому же смещению. Подзапрос, чей путь не проходит wp_parse_url(), добавляется в $validation, но не в $matches, поэтому массивы рассинхронизируются, и подзапрос отправляется под обработчиком другого подзапроса. Это и есть путаница маршрутов.
PoC вкладывает этот примитив дважды:
POST /wp/v2/posts с телом requests отправляется под самим обработчиком batch. Поскольку он был проверен как запрос к постам, его список requests никогда не сверяется со схемой batch, поэтому его подзапросы могут использовать GET — белый список методов обходится.GET /wp/v2/users со строкой author_exclude (в схеме пользователей нет такого параметра, поэтому значение проходит проверку без изменений) отправляется под get_items() постов. Там author_exclude сопоставляется с query-переменной author__not_in из WP_Query, которую уязвимая сборка подставляет в SQL как строку.В результате получается boolean- и time-based blind SQL-инъекция, доступная до аутентификации. Имея доступ на чтение базы данных, можно восстановить хеш пароля администратора; после подбора пароля доступ администратора даёт выполнение кода через загрузку плагина.
Python 3.8+ и стандартная библиотека. Без сторонних зависимостей.
Запускайте из каталога репозитория:
./wp2shell.py <command> <url> [options]
Или выполните pip install ., чтобы получить команду wp2shell в вашем PATH.
Подтверждает эксплуатируемость с помощью дифференциальной временной задержки. Не считывает данные и ничего не изменяет.
./wp2shell.py check http://target
./wp2shell.py read http://target # server fingerprint
./wp2shell.py read http://target --preset users # user logins and password hashes
./wp2shell.py read http://target --query "SELECT @@version"
Необязательная пост-эксплуатация. Требует действительных учётных данных администратора; инъекция восстанавливает хеш пароля, поэтому здесь нужно указать восстановленный открытый текст.
./wp2shell.py shell http://target --user admin --password '<recovered>' --cmd id
./wp2shell.py shell http://target --user admin --password '<recovered>' -i # interactive shell
shell загружает веб-шелл плагина (защищённый случайным путём и одноразовым токеном) и выводит его путь. Удалите его после завершения.
Обновите WordPress до 6.9.5 или 7.0.2. До этого блокируйте на периметре и /wp-json/batch/v1, и query-параметр rest_route=/batch/v1, либо требуйте аутентификацию для конечной точки batch через фильтр rest_pre_dispatch.
Только для авторизованного тестирования безопасности. Используйте исключительно против систем, которыми вы владеете или на тестирование которых имеете явное письменное разрешение. Автор не несёт ответственности за неправомерное использование.
| Параметр | Применяется к | Описание |
|---|
--rest-route | все | Использовать /?rest_route=/batch/v1 (для сайтов без ЧПУ). |
--proxy URL | все | Направлять трафик через HTTP-прокси (например, Burp). |
--timeout N | все | Таймаут запроса в секундах. |
--sleep N | check | Задержка для подтверждения инъекции. |
--preset | read | fingerprint или users. |
--query | read | Скалярное SQL-выражение для чтения. |
--prefix | read | Префикс таблиц базы данных (по умолчанию wp_). |
--max-length N | read | Максимальное число символов на значение (по умолчанию 128). |
--user / --password | shell | Учётные данные администратора (открытый текст, восстановленный из хеша). |
--cmd | shell | Команда для выполнения (не указывайте при использовании -i). |
-i / --interactive | shell | Открыть интерактивную оболочку после развёртывания. |