## https://sploitus.com/exploit?id=KITPLOIT:TOOLS-GITHUB-MCIPEKCI-WP2SHELL
# wp2shell — RCE без аутентификации в ядре WordPress
> RCE PoC без аутентификации для ядра WordPress, объединяющий в цепочку CVE-2026-63030 + CVE-2026-60137. Только авторизованное тестирование.
`wp2shell.py` — это proof of concept из одного файла, использующий только стандартную библиотеку, который связывает **две** уязвимости ядра WordPress в цепочку, приводящую к удалённому выполнению кода без аутентификации:
CVE| Компонент| Ошибка
---|---|---
**CVE-2026-63030**| обработчик REST `/batch/v1`| **desync** из-за путаницы маршрутов — batch-обработчик теряет синхронизацию между таблицей _обработчиков_ и таблицей _валидации_ , когда путь под-запроса не удаётся разобрать, поэтому под-запрос направляется через обработчик, для которого он никогда не проходил валидацию.
**CVE-2026-60137**| `WP_Query`| скалярная **SQL-инъекция** — значение `author__not_in` вставляется прямо в SQL, поэтому строка, попадающая в него, инъектируема.
Ни одна из них по отдельности не даёт RCE. Desync — это _доставка_ (он протаскивает строку атакующего в запрос, до которого она никогда не должна дойти); инъекция — это _примитив_. Вместе они дают атакующему без аутентификации полный SQL-оракул чтения/записи, а оттуда — рабочую оболочку.
> ⚠️ **Только авторизованное тестирование.** Этот эксплойт атакует реально работающие WordPress-установки. Используйте его только против систем, которыми вы владеете или на тестирование которых у вас есть явное письменное разрешение.
* * *
## Затронутые версии
Уязвимые версии: **6.8.0–6.8.5** , **6.9.0–6.9.4** , **7.0.0–7.0.1** Исправленные версии: **6.8.6** , **6.9.5** , **7.0.2** (и более поздние) **Сообщил** Адам Кьюс (Assetnote / Searchlight Cyber); вклад в обнаружение SQLi также внесли TF1T, dtro, haongo.
**RCE-способны только версии 6.9.0–7.0.1.** На ветке 6.8.x desync по-прежнему срабатывает, но ветвь, которая должна сместить обработчик, вместо этого упирается в фатальную ошибку `WP_Error::get_method()` — так что 6.8.x — это **отказ в обслуживании / краш** , а не оболочка. Инструмент определяет это и сообщает, какой примитив доступен.
* * *
## Как работает цепочка
Эксплойт построен по слоям; каждый из них — мост к следующему.
1. **Desync (CVE-2026-63030).** Batch-запрос вкладывает в себя второй batch. Один под-запрос несёт намеренно повреждённый путь (`http://:`, который отклоняет `wp_parse_url()`). В версиях 6.9.0+ неудачный разбор заставляет таблицу обработчиков и таблицу валидации разойтись на одну запись, поэтому _следующий_ под-запрос выполняется через обработчик, для которого он не проходил валидацию, — публичную коллекцию записей.
2. **Инъекция (CVE-2026-60137).** Этот ошибочно направленный вызов достигает `WP_Query` с контролируемым атакующим `author__not_in`. `UNION ALL SELECT` там не _читает_ строки — он **фабрикует** их, позволяя подделывать произвольные записи в результате запроса.
3. **Мост SQL → запись.** Сфабрикованные записи содержат разметку `[embed]`. WordPress послушно разрешает и **кэширует** их как настоящие строки post-meta `oembed_cache` — превращая инъекцию только для чтения в произвольный примитив _записи_.
4. **Смена привилегий.** Используя этот мост записи, мы подделываем (a) **changeset** кастомайзера, автором которого указан настоящий администратор, и (b) самоссылающуюся запись `request`. Вместе они заставляют WordPress **повторно выполнить собственный конвейер запросов от имени этого администратора** — окно, которого как раз хватает, чтобы поставленный в очередь вызов создал нового администратора.
### Оракулы извлечения
Для чтения (`--dump`, определение префикса, кэшированные ID) инструмент автоматически выбирает самый быстрый работающий оракул и **останавливается на первом же срабатывании** :
1. **`union`** — in-band UNION: `post_title` сфабрикованной строки содержит `|||HEX(value)|||`, который дословно отражается в теле ответа `/wp/v2/posts`. Считывает целое значение (любой длины) за **один запрос**. Если UNION отражается, булевы оракулы не опрашиваются.
2. **`bool`** — булев оракул X-WP-Total: заголовок `X-WP-Total` спутанного под-ответа равен `count>0` при true / `0` при false. Один бит за запрос (бисекция).
3. **`time`** — time-based `SLEEP()`: запасной вариант, когда тело ответа удаляется _и_ ответ — 500 (например, фатальная ошибка после диспетчеризации, вызванная кэширующим mu-плагином). Работает даже на целях, которые падают при каждом REST-вызове.
`--dump` использует `GROUP_CONCAT`, чтобы вытащить весь набор учётных данных одним заходом, когда доступен UNION.
* * *
## Установка
Установка не требуется. Только стандартная библиотека Python 3.7+ — без `pip install`.
root@kitploit:~
chmod +x wp2shell.py
* * *
## Использование
root@kitploit:~
# 1. Is it vulnerable? (no injection, no writes, no account created)
./wp2shell.py http://target --check
# 2. Read-only credential dump — FIRST administrator + option secrets
./wp2shell.py http://target --dump
# …every administrator
./wp2shell.py http://target --dump all
# 3. Full RCE — create a temp admin, run a command, clean up
./wp2shell.py http://target --exec "id; uname -a"
### Разведка только для чтения (без создания администратора, обходит 2FA)
root@kitploit:~
./wp2shell.py http://target --user-list # full user table (logins/emails/roles)
./wp2shell.py http://target --content # every post type at status=any (private/draft)
./wp2shell.py http://target --content full # …including each item's raw body
### Сканирование множества хостов
root@kitploit:~
./wp2shell.py -f targets.txt --check --target-threads 8
* * *
## Параметры
### Обход WAF / защитных механизмов
* * *
## Примечания по выводу
* **Хэши паролей** (`$wp$2y$…` / `$P$…` / `$2y$…`) передаются напрямую в hashcat (`-m 3200` для phpass или режим WP bcrypt). WordPress 6.8+ использует bcrypt `$wp$…`.
* **`--dump`** по умолчанию извлекает данные только первого администратора. Используйте **`--dump all`** для получения полного списка администраторов.
* **Цели с ошибкой 500 / крашем:** если фатальная ошибка после диспетчеризации (например, кэширующий mu-плагин в стиле Pantheon) превращает каждый REST-ответ в 500, создание администратора не сработает, но чтение по-прежнему работает — переключитесь на `--oracle time --dump`, чтобы получить хэши.
* * *
## Почему важна очистка
Сценарий `--exec` спроектирован так, чтобы не оставлять **ничего после себя** : временный администратор, его usermeta, сфабрикованные строки `oembed_cache` и загруженный веб-шелл удаляются до выхода из инструмента. Флага `--keep` нет — оператор никогда не должен оставлять живую учётную запись администратора, созданную атакующим, в системе клиента.
* * *
## Файлы
* `wp2shell.py` — эксплойт (один файл, только стандартная библиотека).
* * *
## Авторство
Авторство в обнаружении уязвимостей, их раскрытии и оригинальном разборе «wp2shell» принадлежит исследовательской команде **Searchlight Cyber / Assetnote** :
* **CVE-2026-63030** — desync из-за путаницы маршрутов в REST `/batch/v1`
* **CVE-2026-60137** — SQL-инъекция в `WP_Query author__not_in`
Этот репозиторий — независимая proof-of-concept реализация цепочки эксплойтов, которую они раскрыли; он не претендует на обнаружение лежащих в основе уязвимостей. Если какая-то ссылка на авторство неполна или некорректна, откройте issue, и она будет исправлена.
## Ссылки
* Searchlight Cyber / Assetnote — _wp2shell: Pre-Authentication RCE in WordPress core_ https://slcyber.io/research-center/wp2shell-pre-authentication-rce-in-wordpress-core/
* Релиз WordPress 7.0.2 (исправление) — https://wordpress.org/news/2026/07/wordpress-7-0-2-release/
* Уведомления об уязвимостях — GHSA-ff9f-jf42-662q, GHSA-fpp7-x2x2-2mjf
## Отказ от ответственности
Это proof of concept для исследований в области безопасности, предназначенный для авторизованного тестирования на проникновение и защитной проверки. Запуск его против систем, которыми вы не владеете или на тестирование которых у вас нет письменного разрешения, незаконен. Автор не несёт ответственности за неправомерное использование.