
Python CLI, который обнаруживает и эксплуатирует CVE-2026-90907 — обход авторизации в Joomla! com_users, позволяющий создавать учётные записи без аутентификации; неразрушающий режим проверки плюс PoC.
ТОЛЬКО ДЛЯ АВТОРИЗОВАННОГО ТЕСТИРОВАНИЯ БЕЗОПАСНОСТИ. Запуск режима эксплуатации против систем, которыми вы не владеете или на тестирование которых у вас нет явного письменного разрешения, является незаконным. Режим по умолчанию (
CHECK) неразрушающий и ничего не создаёт.
CLI-инструмент, который обнаруживает и (опционально, с флагом -U)
эксплуатирует CVE-2026-90907 —
уязвимость обхода авторизации средней степени опасности (CVSS 6.9) в ядре
Joomla! CMS, позволяющую неаутентифицированному удалённому злоумышленнику
инициировать несанкционированное создание учётной записи пользователя через
контроллер com_users → profile.save — даже когда публичная регистрация
отключена в глобальной конфигурации.
| Поле | Значение |
|---|---|
| CVE ID | CVE-2026-90907 |
| Степень опасности | Средняя — CVSS 6.9 |
| Тип | Обход авторизации / некорректный контроль доступа (CWE-862) |
| Компонент | Компонент com_users, задача profile.save |
| Вектор атаки | Удалённый, неаутентифицированный, двухшаговый POST в рамках одной сессии |
| Исправлено в | Joomla! 5.4.9 и 6.1.4 (релиз безопасности, 2026-09-29) |
Согласно бюллетеню безопасности Joomla! (2026-09-29) и публичным источникам уведомлений:
Joomla! 3.x также уязвима, но находится в статусе End-of-Life: официальный патч для неё не будет выпущен — планируйте миграцию. Проверка версии по баннеру в инструменте носит информационный характер; вердикт основан на поведении (см. ниже).
Созданная злоумышленником учётная запись — это учётная запись фронтенда с низкими привилегиями, без административного доступа или доступа к бэкенду. Тем не менее это позволяет злоумышленнику:
ProfileModel::save() выполняет unset() для $data['username'] только
когда имя пользователя считается соответствующим требованиям.
isUsernameCompliant выводится из состояния пользователя
com_users.edit.profile.data, которое контроллер заполняет полным
запросом при неудачной валидации формы. Контроллер также не проверяет
состояние входа входящего запроса. Поэтому в рамках одной гостевой сессии:
privacyconsent → валидация не проходит →
«грязное» имя пользователя сохраняется в состоянии пользователя сессии
(пока ничего не создаётся).jform[privacyconsent][privacy]=1 → проверка
unset() пропускается → INSERT INTO #__users → редирект 303 с
user_id > 0.user.login (имя поля —
password, а не passwd) с правильным и неправильным паролем и чтение
flash-сообщения: правильный → "you cannot access the private section"
(аутентификация OK, ACL блокирует) / неправильный → "do not match".
Разница в ответах и есть доказательство.git clone https://github.com/aorozco-sys/CVE-2026-90907.git
cd CVE-2026-90907
pip install -r requirements.txt # only dependency: requests
# CHECK mode (default) — non-destructive: never sends consent, never creates an account
python3 joomla_cve_2026_90907.py https://ejemplo.com
# Verbose CHECK (full request/response log on stderr)
python3 joomla_cve_2026_90907.py https://ejemplo.com --no-color -v
# EXPLOIT mode (-U) — creates a real account in #__users (authorized targets only!)
python3 joomla_cve_2026_90907.py https://ejemplo.com \
-U audit.user -E [email protected] -N "CVE Audit"
# Through a proxy (e.g. Burp Suite) with a custom timeout
python3 joomla_cve_2026_90907.py https://ejemplo.com -U audit.user \
--proxy http://127.0.0.1:8080 --timeout 30
# Exploit without the differential login verification
python3 joomla_cve_2026_90907.py https://ejemplo.com -U audit.user \
--no-verify-login
| Флаг | Описание |
|---|---|
TARGET | Базовый URL (нормализованный; без завершающего слэша) |
-U/--username | Включает режим EXPLOIT. Без -U → неразрушающая проверка CHECK |
-P/--password | По умолчанию: генерируется с помощью secrets, 16 символов (буквы, цифры и символы), всегда выводится |
-E/--email | По умолчанию: <username>@example.invalid |
-N/--name | По умолчанию: CVE Audit |
-o/--output | Каталог для доказательств (по умолчанию evidence_cve90907_<ts> в текущем рабочем каталоге) |
--proxy URL | Прокси для запросов (Burp: http://127.0.0.1:8080) |
--timeout | По умолчанию 20 с |
--ua | User-Agent (по умолчанию cve-2026-90907-audit/1.0) |
--no-verify-login | Пропускает дифференциальную проверку входа (режим exploit) |
--verify-ssl | Проверять TLS (по умолчанию: не проверять) |
--no-color | Без ANSI-цветов |
-v/--verbose | Полный журнал запросов/ответов в stderr |
| Код | Значение |
|---|---|
0 | Ok / не уязвим / неизвестно |
1 | Уязвим (LIKELY в режиме check, CONFIRMED в режиме exploit) |
2 | Операционная ошибка (сеть, зависимость и т. п.) |
profile в Location, без перенаправления на вход) + flash-сообщение
об ошибке валидации (например, сообщение о необходимости принять политику
конфиденциальности). Окончательное подтверждение = режим exploit.summary.json.Location с user_id > 0 после W2.Каждый запуск записывает в каталог -o с меткой времени файлы 00_token.txt,
01_version.txt, 02_w1_seed.txt, 03_w2_exploit.txt,
04_login_correct.txt, 05_login_wrong.txt и summary.json. Каждый файл
фиксирует полный REQUEST (метод/URL/ключевые заголовки/тело), RESPONSE (статус,
Location, Server, извлечённый flash, первые 500 байт тела) и метки времени
ISO — готово к приложению к отчёту о пентесте.
privacyconsent и использует
несоответствующее правилам имя пользователя (probe()): сохранение
завершается ошибкой валидации формы, и ничего не сохраняется.user_id > 0 (чего быть не
должно), режим exploit прерывается до W2.user_usergroup_map).