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

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

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

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

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

Категории

Все категории
Loading categories
CVE-2026-97332-PoC — Независимый PoC и воспроизводимая лабораторная среда для CVE-2026-97332 — неаутентифицированное раскрытие приватных файлов в User Private Files < 2.2.0 на WordPress Multisite. | Kitploit
Инструменты/GitHubGitHub/kolya080808/cve-2026-97332-poc
Оборонительные ИнструментыАнализ уязвимостейЭксплуатацияЭксплуатация веб-приложенийСбор информацииВеб-безопасностьТестирование на ПроникновениеЛаборатории и Практика

Популярное

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

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

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

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

Смотреть все инструменты →
GitHubkolya080808/cve-2026-97332-poc

CVE-2026-97332-PoC

Независимый PoC и воспроизводимая лабораторная среда для CVE-2026-97332 — неаутентифицированное раскрытие приватных файлов в User Private Files < 2.2.0 на WordPress Multisite.

РепозиторийСайт
411 месяц назадЕщё не проверено
Поделиться

CVE-2026-97332 — WordPress User Private Files < 2.2.0 Раскрытие приватных файлов без аутентификации (Multisite)

CVE Severity Affected Fixed Requires PoC Ethics

[!NOTE] Этот репозиторий представляет собой независимое воспроизведение и Proof of Concept для CVE-2026-97332.

Первоначальное обнаружение уязвимости: Akshat Parikh (SN1PER). CNA / advisory: WPScan. Независимый PoC и воспроизведение: Kolya080808.

Раскрытие приватных файлов других пользователей без аутентификации в WordPress- плагине User Private Files (slug на wp.org user-private-files) до 2.2.0 на multisite-установках. Плагин хранит приватные документы каждого пользователя внутри обычного дерева uploads и защищает их единственным RewriteRule, добавленным в корневой .htaccess, который направляет запросы к файлам через PHP- проверку доступа. В multisite-сети это правило никогда не срабатывает: один обычный GET — без cookies, без заголовков, без входа в систему — возвращает приватный файл другого пользователя как статический контент. Broken Access Control, CWE-284, CVSS 3.1 5.3 (AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N).

Этот репозиторий содержит рабочий эксплойт на Python без зависимостей и двухконтейнерную docker-лабораторию (уязвимая версия 2.1.9 и исправленная 2.2.0, обе — WordPress multisite) для воспроизведения атаки от начала до конца.

[!CAUTION] Этот материал предоставлен исключительно для авторизованных исследований в области безопасности и защитного тестирования (см. дисклеймер внизу). Атака на системы, которыми вы не владеете и не управляете без письменного разрешения, незаконна.

Уязвимость

Плагин хранит приватные файлы как обычные вложения в плоском подкаталоге uploads для каждого сайта — wp-content/uploads/upf-docs/ (основной сайт) и wp-content/uploads/sites/N/upf-docs/ (подсайт N) — без изоляции по пользователям. Контроль доступа находится не на уровне каталога; он реализован в PHP (dl-file.php: 403 для анонимных пользователей, затем проверка автора/списка разрешений) и достигается только через rewrite-правило, добавляемое при активации плагина в корневой .htaccess:

# appended by 2.1.9 (upvf_actdeact.php), AFTER the WordPress block
RewriteRule ^wp-content/uploads/upf-docs/(.*)$ https://site/?file=$1 [QSA,L]

При мультисайте это никогда не срабатывает по двум независимым причинам:

  1. Сетевой .htaccess сначала перехватывает существующие файлы. WordPress multisite записывает свой собственный набор правил в корневой .htaccess:

    RewriteCond %{REQUEST_FILENAME} -f [OR]
    RewriteCond %{REQUEST_FILENAME} -d
    RewriteRule ^ - [L]
    

    Запрос, сопоставленный с физически существующим файлом, прекращает перезапись прямо на этом месте — Apache отдаёт его как статический контент, и mod_rewrite так и не доходит до блока плагина в конце файла. (В односайтовом WordPress используются отрицательные условия !-f/!-d, поэтому тот же плагин работает там.) Это уже раскрывает файлы главного сайта сети.

  2. Пути подсайтов вообще не соответствуют шаблону. В multisite у каждого сайта свои загрузки — wp-content/uploads/sites/N/…, плюс префикс URL /siteN/ в сетях с подкаталогами — тогда как правило жёстко задано как ^wp-content/uploads/upf-docs/ от базового URL главного сайта. Даже после того, как внутренняя перезапись сети убирает префикс /siteN/, сегмент sites/N/ всё равно не совпадает.

Таким образом, для любой сети multisite (как с подкаталогами, так и с поддоменами) неаутентифицированный атакующий напрямую получает приватные файлы:

GET /wp-content/uploads/upf-docs/victim.pdf HTTP/1.1            (main site)
GET /site2/wp-content/uploads/sites/2/upf-docs/victim.pdf HTTP/1.1  (subsite)

Ответ — 200 с телом файла, отдаваемый Apache напрямую из uploads/; проверка доступа плагина при этом никогда не выполняется.

Имена файлов предсказуемы

В URL нет ничего секретного. Плагин формирует имена из числового идентификатора пользователя-владельца и unix-времени загрузки:

Генератор (2.1.9)Имя на диске
современный UI, inc/functions-file.php:73-77usr{ID}_{unixtime}_{original}
классический шаблон, inc/classic-user-functions.phpuser_{ID}_doc_{unixtime}.{ext}

Идентификаторы пользователей в мультисайтовой сети — это небольшие последовательные целые числа из одной общей таблицы wp_users, поэтому атакующему нужно лишь приблизительное время загрузки (окно ±2 минуты — это ≈240 запросов) и либо исходное имя файла, либо только его расширение. Суффиксы при коллизиях (-1, -2) существуют, но встречаются редко.

Исправление (2.2.0)

Версия 2.2.0 заменила перезапись корневого файла на .htaccess на уровне папки upf-docs/.htaccess — RewriteRule ^(.*)$ {home}/?file=$1 [R=302,QSA,L], плюс Require all denied, когда mod_rewrite отсутствует, — пересоздаваемый при каждом admin_init (самовосстанавливающийся, для каждого подсайта). Правило для каталога срабатывает для любого физического пути внутри upf-docs/ независимо от префикса URL, поэтому прямой GET теперь превращается в 302 на проверку доступа и, для анонимных пользователей, в 403. Файлы не перемещаются; меняется только механизм перехвата. Это различие между 302 и статической отдачей также используется эксплойтом как поведенческий детектор.

Уязвимые версии

  • User Private Files < 2.2.0 (проверено на исходниках 2.1.9; теги SVN 1.0.1–2.1.9 содержат ту же схему с перезаписью в корне)
  • Только мультисайтовые развёртывания (подкаталог и поддомен). Односайтовые установки защищены корневым правилом, пока Apache читает .htaccess и файл был доступен для записи при активации (nginx требует ручной перезаписи от вендора — см. readme плагина).
  • Ссылка: рекомендация WPScan d6a144b3-84e3-43eb-92d3-fd4505dd0e1c (опубликовано 2026-10-02, исследователь Akshat Parikh / SN1PER).

Как работает эксплойт

exploit.py использует только стандартную библиотеку Python 3 (http.client), не следует за перенаправлениями и не отправляет cookies:

  1. Проверка версии (шаг 1, до любой атаки): GET /wp-content/plugins/user-private-files/readme.txt, разбор Stable tag:. < 2.2.0 → продолжить; >= 2.2.0 → красное поле NOT VULNERABLE - plugin 2.2.0+ (patched) и код выхода 6. Если readme.txt недоступен для чтения, выполняется поведенческая проверка несуществующего имени в upf-docs/ (302 = перезапись на месте, 404 = статическая отдача), она отображается, и запуск продолжается (--skip-check отключает весь этот шаг).
  2. Построение URL (шаг 2): основной сайт {base}/wp-content/uploads/upf-docs/{file} или, с --site site2 --site-id 2, {base}/site2/wp-content/uploads/sites/2/upf-docs/{file}.
  3. Запрос (шаг 3): один обычный GET, без Cookie, без Authorization.
  4. Вердикт (шаг 4):
    • 200 → * LEAKED с первыми строками файла в качестве доказательства, код выхода 0;
    • 302 → "redirected to the access check - not vulnerable / patched", код выхода 1;
    • 404 → "file not found (wrong name?)" — попробуйте --guess, код выхода 1.
Скачать инструмент