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

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

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

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

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

Категории

Все категории
Loading categories
CVE-2026-18322 — Анализ первопричины, пассивный чекер версий и лабораторный PoC для CVE-2026-18322 — неаутентифицированного повышения привилегий в WordPress-плагине Smart Popup от Supsystic. | Kitploit
Инструменты/GitHubGitHub/i3it/cve-2026-18322
Повышение привилегийСканеры уязвимостейАнализ уязвимостейЭксплуатацияЭксплуатация веб-приложенийВиртуализация для безопасностиВеб-безопасностьТестирование на ПроникновениеСтатьи и ИсследованияЛаборатории и Практика
GitHub
226 дней назадЕщё не проверено

Популярное

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

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

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

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

Смотреть все инструменты →
Поделиться
i3it/cve-2026-18322

CVE-2026-18322

Анализ первопричины, пассивный чекер версий и лабораторный PoC для CVE-2026-18322 — неаутентифицированного повышения привилегий в WordPress-плагине Smart Popup от Supsystic.

Репозиторий

CVE-2026-18322 — Повышение привилегий в Smart Popup by Supsystic

CVE Severity Affected Fixed in CWE Python Tests License

Исследование безопасности CVE-2026-18322 — уязвимости повышения привилегий без аутентификации в WordPress-плагине Smart Popup by Supsystic (popup-by-supsystic). Этот репозиторий содержит анализ первопричины, основанный на diff исходного кода upstream, извлечённые патчи, инструмент обнаружения (пассивный фингерпринтер версий) для выявления уязвимых установок и лабораторию для PoC эксплуатации.

Уязвимость публична и исправлена. Эта работа опубликована для защитного использования: чтобы помочь администраторам находить и устранять уязвимые хосты.


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

Диапазон версийСтатус
< 1.13.0Уязвима
>= 1.13.0Исправлена

1.13.0 (выпущена 31.07.2026) — первый исправленный релиз; он устраняет все три звена описанной ниже цепочки. См. §1 анализа.


Краткое описание уязвимости

Три независимые слабости складываются в создание администратора без аутентификации:

1. Коллизия карт разрешений — havePermissions() объединяла две карты разрешений с помощью array_merge(). Обе используют строковый ключ PPS_USERLEVELS ('userlevels'), а array_merge() перезаписывает строковые ключи, поэтому короткий список по умолчанию базового контроллера полностью заменял список модуля popup — молча лишая ограничения администратора метод save и девять других методов:

root@kitploit:~
$permissions     = $mod->getController()->getPermissions();      // [... 'save' ...]
$permissionsBase = $mod->getController()->getBasePermissions();  // ['getListForTbl','removeGroup','clear']
$permissions     = array_merge($permissions, $permissionsBase);  // base wins — 'save' is gone

Проверка отказывает открыто: действие, отсутствующее в карте, никогда не запрещается.

2. Многоразовый nonce, отправляемый по почте посторонним — save всё ещё требовал pps_nonce, но письмо с подтверждением подписки содержало именно это действие nonce. Для неавторизованных пользователей WordPress nonce привязан к uid=0, поэтому токен, созданный для анонимного подписчика, проходит проверку для любого анонимного атакующего.

3. Отсутствие серверного списка разрешённых ролей — createWpSubscriber() передавал настроенную роль напрямую в WP_User::set_role(). Безопасный список ролей плагина (который исключает administrator) применялся только при отрисовке выпадающего списка в админке — контроль только на уровне UI.

В цепочке: подписаться, чтобы получить nonce → воспроизвести его против popup::save, чтобы установить sub_wp_create_user_role=administrator → запустить поток подписки → постоянная учётная запись администратора.

Полный разбор со ссылками на файлы/строки: docs/ANALYSIS.md.


Обнаружение — пассивный чекер

poc/cve_2026_18322_check.py определяет, работает ли сайт на уязвимой версии. Он никогда не пытается эксплуатировать уязвимость: он отправляет обычные HTTP GET-запросы и читает версию, которую установка сообщает о себе.

Установка

root@kitploit:~
git clone <this-repo> && cd CVE-2026-18322
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt

requests рекомендуется, но необязателен — инструмент переключается на стандартную библиотеку.

Использование

root@kitploit:~
# Single target
python3 poc/cve_2026_18322_check.py https://example.com

# With supporting evidence
python3 poc/cve_2026_18322_check.py https://example.com -v

# Many targets, concurrently, exporting results
python3 poc/cve_2026_18322_check.py -f targets.txt -t 20 --json results.json
python3 poc/cve_2026_18322_check.py -f targets.txt --csv results.csv --only-vulnerable

# Through a proxy, ignoring TLS errors (lab use)
python3 poc/cve_2026_18322_check.py https://staging.internal -k --proxy http://127.0.0.1:8080

Цели можно указывать как аргументы или через -f (- читает stdin). Голое имя хоста предполагается как https://.

Пример

root@kitploit:~
$ python3 poc/cve_2026_18322_check.py https://example.com -v
[VULNERABLE] https://example.com/  (Smart Popup by Supsystic 1.11.2)  < 1.13.0 affected by CVE-2026-18322; upgrade to 1.13.0+
      - asset-version: plugin asset enqueued with ?ver=1.11.2  (https://example.com/)
      - homepage-reference: references /plugins/popup-by-supsystic/  (https://example.com/)
      - readme: plugin readme.txt is publicly readable  (https://example.com/wp-content/plugins/popup-by-supsystic/readme.txt)
      - readme-stable-tag: Stable tag: 1.11.2  (.../readme.txt)

Статусы

Коды выхода: 0 = уязвимых целей нет, 1 = как минимум одна уязвима, 2 = ошибка использования.

Как он обнаруживает

Два пассивных сигнала, оба — обычные HTTP GET-запросы к публичным ресурсам:

  1. Cache-busters ресурсов — плагин подключает свои CSS/JS с ?ver=PPS_VERSION (classes/frame.php:410,473), поэтому главная страница часто раскрывает точную версию.
  2. readme.txt — Stable tag: авторитетен и имеет приоритет над потенциально устаревшим кэшированным ресурсом; changelog служит запасным вариантом.

Сканирование главной страницы также обнаруживает переименованные каталоги wp-content (например, /app/ в Bedrock), поэтому поиск readme следует реальной структуре сайта.


Безопасность

Инструмент обнаружения не пытается эксплуатировать уязвимость. Никакого боевого эксплойта для этой CVE здесь не публикуется: единственный код, выполняющий полную цепочку, жёстко ограничен локальной лабораторией (см. ниже).

Пассивный чекер выполняет только фингерпринтинг версий. Его HttpClient не предоставляет никакого HTTP-метода, кроме GET — это обеспечено конструкцией и проверяется в наборе тестов, поэтому он не может отправить изменяющий состояние запрос даже по ошибке. Он никогда не вызывает popup::save, не отправляет параметр sub_wp_create_user_role, не отправляет форму подписки, не инициирует письмо с подтверждением и не создаёт и не изменяет ни пользователя, ни popup, ни настройку. Он читает два публичных ресурса — главную страницу и readme.txt — и ничего больше.

У этой безопасности есть цена, и о ней сказано прямо: вердикт настолько хорош, насколько хороши метаданные версии, публикуемые хостом. Компромиссы и режимы отказа: §9.

Эксплойт лаборатории запускается только в лаборатории

lab/exploit_full_chain.py — единственный фрагмент кода здесь, выполняющий реальную атаку, и он создаёт администратора WordPress. Он опубликован, чтобы анализ можно было воспроизвести, а не принимать на веру — утверждение об ошибке авторизации, которое нельзя продемонстрировать, является заявлением, а не находкой. Он написан для одноразового стека в lab/ и ни для чего другого:

  • Нелокальные цели отклоняются. Имя хоста цели разрешается, и каждый возвращённый адрес должен быть loopback или частным RFC1918. Публичное DNS-имя отклоняется, даже если в данный момент оно разрешается в частный адрес — это известный способ нацелить «лабораторный» инструмент на продакшен.
  • --lab-confirm обязателен. Обе проверки выполняются в assert_lab_target() до первого HTTP-запроса, поэтому отклонённый вызов вообще не касается цели.
  • Он может читать только почтовый ящик лаборатории. Фаза 1 извлекает многоразовый pps_nonce из письма с подтверждением подписки через API Mailpit лаборатории (http://localhost:8025/api/v1/…). Нет никакого пути в коде для получения этого письма откуда-либо ещё, поэтому у цепочки нет первого шага против хоста вне лаборатории.
  • Лаборатория, на которую он нацелен, недоступна извне машины. Каждый сервис в lab/docker-compose.yml привязан к 127.0.0.1.

В поставляемом виде его поэтому нельзя нацелить на реальный сайт — он останавливается на REFUSING TO RUN до отправки запроса:

root@kitploit:~
$ python3 exploit_full_chain.py https://example.com --lab-confirm
REFUSING TO RUN: example.com resolves to non-local address(es) 104.20.23.154, ...
This script creates a WordPress administrator and is for the local lab only.
To test a real site, use the non-destructive checker in ../poc/.

Эти защиты несут нагрузку, а не служат украшением: скрипт и есть реальная цепочка, и именно то, что он не запустится вне одноразового локального стека, делает его демонстрацией. Пожалуйста, не удаляйте их, и см. SECURITY.md — изменения, ослабляющие их, или автономный эксплойт, предназначенный для запуска вне лаборатории, выходят за рамки этого репозитория. Чтобы узнать, уязвим ли реальный сайт, используйте poc/ — чекер отвечает на тот же вопрос, ничего не затрагивая.

Для авторитетного ответа на хосте, который вы контролируете:

root@kitploit:~
grep -n "array_merge(\$permissions, \$permissionsBase)" \
     wp-content/plugins/popup-by-supsystic/classes/frame.php

Любой вывод означает, что хост уязвим — именно эту строку заменила 1.13.0.

Используйте только против систем, которыми вы владеете или на тестирование которых у вас есть явное разрешение. См. SECURITY.md.


Воспроизведение — демонстрационная лаборатория

lab/ содержит одноразовый стек Docker, который прогоняет уязвимость от начала до конца, чтобы анализ можно было проверить, а не принимать на веру:

root@kitploit:~
cd lab
./setup.sh                                                    # WordPress + plugin 1.12.0
../.venv/bin/python exploit_full_chain.py http://localhost:8080 --lab-confirm
./verify.sh                                                   # confirm from the database
./teardown.sh

Его самый полезный вывод — сравнение версий: идентичные запросы против трёх релизов:

root@kitploit:~
./setup.sh --plugin-version 1.11.2    # exploit succeeds
./setup.sh --plugin-version 1.12.0    # exploit succeeds
./setup.sh --plugin-version 1.13.0    # exploit fails at phase 2

Лаборатория намеренно уязвима, и её скрипт эксплойта создаёт администратора WordPress. Всё привязано к 127.0.0.1, и скрипт не запустится ни против чего, кроме локальной лаборатории — см. эксплойт лаборатории запускается только в лаборатории. Это не сканер; чтобы проверить реальный сайт, используйте poc/.


Устранение

  1. Обновитесь до 1.13.0 или более поздней версии.
  2. Если вы не можете обновиться, отключите плагин. Частичные меры слабы — уязвимое действие достижимо любым анонимным запросом.
  3. Если вы использовали уязвимую версию с включёнными popup-подписками, проверьте систему на компрометацию: неожиданные учётные записи администратора, popup с sub_wp_create_user_role, установленным в привилегированную роль, и POST-запросы к admin-ajax.php с pl=pps&mod=popup&action=save.

Запросы и grep по логам: §10.


Структура репозитория

root@kitploit:~
.
├── README.md
├── SECURITY.md                  Scope, authorized-use policy, disclosure
├── LICENSE                      MIT
├── requirements.txt
├── docs/
│   └── ANALYSIS.md              Full root-cause analysis and fix rationale
├── patches/
│   ├── 01-frame-permission-merge.diff              array_merge() → _mergePermissions()
│   ├── 02-subscribe-role-allowlist-and-nonce.diff  Role allowlist + dedicated nonce
│   └── 03-v1.12.0-confirmation-page-hardening.diff Unrelated hardening added in 1.12.0
├── poc/
│   └── cve_2026_18322_check.py  Passive version fingerprint (GET only)
├── lab/                         Disposable Docker lab — INTENTIONALLY VULNERABLE
│   ├── docker-compose.yml       MariaDB + WordPress 1.12.0 + Mailpit (loopback only)
│   ├── setup.sh / teardown.sh   Bring the lab up / destroy it
│   ├── exploit_full_chain.py    Full attack chain — CREATES AN ADMIN; lab-gated
│   └── verify.sh                Independent confirmation from the database
├── scripts/
│   └── fetch_versions.sh        Export plugin versions from SVN and regenerate diffs
└── tests/
    └── test_check.py            Offline unit tests for the passive checker

Разработка

root@kitploit:~
pip install -r requirements.txt pytest
python3 -m pytest tests/ -v

Набор тестов полностью офлайн — он использует записанные фикстуры, никогда не живые цели. Он покрывает триаж версий через границу 1.13.0, нормализацию целей и правила доказательств, определяющие каждый статус.

Свойства безопасности утверждаются, а не просто документируются: что полное сканирование не отправляет изменяющих состояние запросов и что HttpClient не предоставляет никакого HTTP-метода, кроме GET.

Зафиксированы две регрессии, найденные во время разработки: readme.txt с CRLF, ломающий парсинг с привязкой к строкам, и страница ошибки HTTP, ошибочно засчитанная как свидетельство плагина.

Чтобы воспроизвести анализ из источников upstream:

root@kitploit:~
./scripts/fetch_versions.sh          # exports 1.11.2 / 1.12.0 / 1.13.0 and regenerates patches/

Лицензия

MIT — см. LICENSE. Анализируемый плагин распространяется под GPLv2-or-later и не распространяется здесь; scripts/fetch_versions.sh получает его из официального SVN-репозитория WordPress.

Скачать инструмент
СтатусЗначение
VULNERABLEПлагин обнаружен версии < 1.13.0
NOT_VULNERABLEПлагин обнаружен версии >= 1.13.0
PLUGIN_DETECTED_VERSION_UNKNOWNПлагин присутствует, версию определить не удалось — проверьте вручную
PLUGIN_NOT_DETECTEDНет свидетельств наличия плагина (не доказательство отсутствия)
ERRORЦель недоступна или некорректна