
Недеструктивный детектор для CVE-2026-64638 (XSS2Shell) — примитив отражённой XSS до аутентификации в WordPress
Неразрушающий детектор без зависимостей для примитива отражения CVE-2026-64638 ("XSS2Shell")
в WordPress wp-login.php.
CVE-2026-64638 — это пред-аутентификационная отражённая XSS-уязвимость в ядре WordPress, раскрытая PWN.AI 2026-08-07 (CVSS 8.9, CWE-79) и исправленная в версии 7.0.3 с бэкпортами во все поддерживаемые ветки (6.9.6, 6.8.7, 6.7.6, 6.6.6, 6.5.9, …).
Корневая причина — расхождение парсеров между PHP-функцией strip_tags() и
санитайзером KSES в WordPress:
strip_tags() отказывается распознавать тег, если после < идёт пробел, поэтому
имя пользователя вида < area id=x> сохраняется как обычный текст.<area id="x"> внутри сообщения об ошибке входа.Это даёт управляемую атакующим DOM-инъекцию с выбираемыми атрибутами
id/class/href — примитив, лежащий в основе опубликованной многоступенчатой
цепочки (DOM clobbering → REST JSONP → кража паролей приложений → загрузка плагина →
RCE против вошедшего в систему администратора-жертвы).
Два неразрушающих зонда (неудачная попытка входа со случайным маркерным именем пользователя):
<b>marker</b> появляется в ответе об ошибке без экранирования.< area id=marker> переживает strip_tags() и снова появляется
как живой/нормализованный элемент (например, area id="marker") в ответе.Никакая полезная нагрузка не выполняется; инструмент лишь определяет, отображается ли HTML атакующего как живой DOM. Дополнительные опции:
--version — определяет версию ядра по тегу <generator> в фиде.--jsonp — проверяет доступность REST JSONP-обёртки (_jsonp/_envelope),
используемой опубликованной цепочкой.python3 xss2shell_check.py https://example.com
python3 xss2shell_check.py --jsonp --verbose https://example.com
python3 xss2shell_check.py --version https://example.com
python3 xss2shell_check.py --json https://example.com
Python 3.6+, только стандартная библиотека. Без зависимостей.
| Код | Значение |
|---|---|
| 0 | Уязвим (примитив отражения присутствует) |
| 1 | Исправлен / не уязвим |
| 2 | Ошибка (цель недоступна, WAF-челлендж, неожиданный ответ) |
<area id="…">).
Оформление кавычек в атрибутах зависит от поколения KSES (старый кастомный парсер:
<area id=x>; DOMDocument: <area id="x"> / <area id="x" />), поэтому
сопоставляются все формы. Сырой проход < area …> без повторного разбора —
это инертный текст в браузере, а не примитив; он сообщается как RAW_TEXT_ONLY
и не вызывает ложного срабатывания.login_errors
или CDN/WAF переписывают ответы, либо сообщение об ошибке входа никогда
не отражает имя пользователя.Только авторизованное тестирование безопасности. Этот инструмент предназначен исключительно для тестирования систем, которыми вы владеете или на оценку которых имеете явное письменное разрешение. Неавторизованное тестирование незаконно в большинстве юрисдикций.
| Флаг | Назначение |
|---|
--version | определяет версию ядра (тег генератора фида, запасной вариант — мета-тег на главной странице) |
--jsonp | также проверяет доступность REST JSONP-обёртки (_jsonp/_envelope) |
-v, --verbose | выводит фрагменты ответов зондов (доказательства для отчётов) |
--json | машиночитаемый результат в формате JSON (CI / автоматизация) |
| Наблюдаемое поведение | Вердикт | Код выхода |
|---|
<b>marker</b> выводится без экранирования | RAW_HTML — уязвим | 0 |
< area id=marker> заново разбирается в живой <area id="marker"> (любые кавычки / void-форма) | AREA_BYPASS — уязвим | 0 |
| Имя пользователя экранировано в HTML | ESCAPED — не уязвим | 1 |
| Теги удалены, текст остаётся | STRIPPED — не уязвим | 1 |
Сырой < area …> проходит насквозь, но заново не разбирается | RAW_TEXT_ONLY — инертный текст, не уязвим | 1 |
| Отражения нет вовсе | NOT_REFLECTED — не уязвим | 1 |
| Зонд заблокирован (HTTP ≥ 400 / страница-челлендж) или цель недоступна | ERROR | 2 |