Skip to content
KitploitKITPLOIT
HerramientasExploitsBlog
Log in
Enviar
HerramientasExploitsBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

FeedsContactoPrivacidad© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
CVE-2026-18963-Exploit — Exploit para Keycloak CVE-2026-18963 que permite la toma de control de cuentas sin autenticación mediante la evasión de reset-credentials. Incluye detección segura, prueba no destructiva, toma de control completa, enumeración de nombres de usuario y un laboratorio con versiones vulnerables y parcheadas. | Kitploit
Herramientas/GitHubGitHub/snizi/cve-2026-18963-exploit
Autenticación y AutorizaciónAnálisis de VulnerabilidadesExplotaciónExplotación de Aplicaciones WebPruebas de Penetración
GitHubsnizi/cve-2026-18963-exploit

CVE-2026-18963-Exploit

Ver Repositorio

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →

Acerca de

431251hace 1 mesRevisado por Kitploit

Exploit para Keycloak CVE-2026-18963 que permite la toma de control de cuentas sin autenticación mediante la evasión de reset-credentials. Incluye detección segura, prueba no destructiva, toma de control completa, enumeración de nombres de usuario y un laboratorio con versiones vulnerables y parcheadas.

Compartir

CVE-2026-18963 — Bypass de reset-credentials en Keycloak → toma de control de cuenta no autenticada

CVE Affected Python Dependencies

Conociendo solo un nombre de usuario o dirección de correo electrónico, un atacante no autenticado establece una contraseña arbitraria en cualquier cuenta de Keycloak. El correo de restablecimiento de contraseña se envía a la víctima real y nunca es necesario — el atacante nunca lee una bandeja de entrada, nunca hace clic en un enlace, y no posee ninguna credencial o sesión previa.

Afectado: Keycloak 26.0.0 – 26.7.1. Corregido en 26.7.2.


¿Soy vulnerable?

Un solo comando. No se requiere un nombre de usuario válido, y sin efectos secundarios — no envía correo, no escribe en ninguna cuenta, y se detiene antes del paso explotable.```bash git clone https://github.com/Snizi/CVE-2026-18963-Exploit cd CVE-2026-18963-Exploit

python3 cve_2026_18963_poc.py
--base https://sso.example.com --realm YOUR_REALM
--client-id account
--redirect-uri https://sso.example.com/realms/YOUR_REALM/account/
--safe-check

Python 3.9+, solo biblioteca estándar. Nada que instalar.

| Salida | Veredicto | Significado |
|:---:|---|---|
| `0` | 🔴 **VULNERABLE** | se sirvió la puerta de correo estacionada — el bug en sí |
| `2` | 🟢 **PARCHEADO** | el flujo se bifurcó al inicio de sesión y se quedó allí (fix #51844 presente) |
| `2` | 🟡 **MITIGADO** | restablecimiento de credenciales inalcanzable — *Forgot password* está desactivado. **No es un parche.** |
| `3` | ⚪ **NO CONCLUYENTE** | respuesta no reconocida — **no lo interpretes como una aprobación** |

Ejecútalo por realm — *Forgot password* es una configuración por realm, y `master` cuenta.
Detalles, y por qué la comprobación no necesita usuario y no toca nada, en
[§4a](#4a-safe-detection---safe-check--start-here).

**¿Ya sabes que estás expuesto?** Salta a [remediación](#8-remediation) y
[detección / threat hunting](#9-detection).

### Pruébalo sin un objetivo

El repositorio incluye un laboratorio que arranca una versión vulnerable **26.7.1** y una parcheada **26.7.2**
lado a lado contra un realm idéntico, además de un buzón para observar cómo llega el correo de restablecimiento
y permanece sin leer mientras la cuenta es tomada:```bash
cd lab && docker compose up -d

python3 ../cve_2026_18963_poc.py --base http://localhost:8080 \
  --realm poc --client-id poc-app --safe-check   # VULNERABLE
python3 ../cve_2026_18963_poc.py --base http://localhost:8100 \
  --realm poc --client-id poc-app --safe-check   # PATCHED

⚠️ Solo pruebas autorizadas

Este repositorio existe para defensores, respondedores de incidentes y probadores de penetración autorizados. Ejecútalo contra sistemas que poseas o para los que tengas permiso por escrito para probar. Todo lo que hay aquí incluye un laboratorio vulnerable autocontenido (lab/), por lo que no es necesario tocar nada externo para aprender cómo funciona el fallo. Apuntarlo a infraestructura de terceros sin autorización es ilegal en la mayoría de las jurisdicciones y no es algo que este proyecto respalde.

Referencias: keycloak#51833 · GHSA-4gv3-mc9p-5wqc · fix keycloak#51844


Contenido

  • 1. Causa raíz
  • 2. Versiones afectadas (incluidas líneas heredadas)
  • 3. El laboratorio
  • 4. Uso
    • 4a. Detección segura (--safe-check) — empieza aquí
    • 4b. Prueba no destructiva (--check)
    • 4c. Toma de control total
    • 4d. Enumeración de nombres de usuario (--enum)
  • 5. Temas de inicio de sesión personalizados
  • 6. Brecha conocida — PKCE
  • 7. Validación realizada
  • 8. Remediación
  • 9. Detección
  • Autor

1. Causa raíz

Dos defectos encadenados. Ninguno es explotable por sí solo.

Defecto 1 — una bandera sin alcance y persistente

services/src/main/java/org/keycloak/authentication/DefaultAuthenticationFlow.java

processAction() — cualquier POST que lleve la clave de formulario tryAnotherWay:```java processor.getAuthenticationSession().setAuthNote( AuthenticationProcessor.AUTHENTICATION_SELECTOR_SCREEN_DISPLAYED, "true"); return createSelectAuthenticatorsScreen(model);

La nota es un **booleano simple sin registro de a qué conjunto de ejecución pertenece**. Solo se limpia en la rama que maneja un parámetro `authenticationExecution` enviado. Si se omite ese parámetro — como hace este PoC en todo momento —, la marca permanece activa durante toda la vida de la sesión de autenticación.

`processFlow()` — mientras la marca sea verdadera, se omite la evaluación normal del flujo:```java
if (Boolean.parseBoolean(authSession.getAuthNote(AUTHENTICATION_SELECTOR_SCREEN_DISPLAYED))) {
    String lastExecutionId = authSession.getAuthNote(CURRENT_AUTHENTICATION_EXECUTION);
    if (lastExecutionId != null) {
        AuthenticationExecutionModel executionModel =
            realm.getAuthenticationExecutionById(lastExecutionId);
        if (executionModel != null)
            return createSelectAuthenticatorsScreen(executionModel);   // <-- attacker-usable form
    }
}

It renders a submittable form aimed at whatever execution is currently parked, instead of keeping the session pinned on "waiting for the e-mail".

The glue is processResult() case FORK: — when Send Reset Email fires it stamps CURRENT_AUTHENTICATION_EXECUTION = <reset-credential-email execution id> and forks the browser to the login page. The parked execution is precisely the e-mail gate.

Defect 2 — the e-mail gate never checks the action token

`services/src/main/java/org/keycloak/authentication/authenticators/resetcred/ResetCredentialEmail.java````java @Override public void action(AuthenticationFlowContext context) { context.getUser().setEmailVerified(true); context.success(); }

Unconditional. Nothing verifies that the flow was resumed by a valid action token,
so *reaching* `action()` is treated as equivalent to proving mailbox control.

### The chain```
tryAnotherWay POST            → sticky AUTHENTICATION_SELECTOR_SCREEN_DISPLAYED="true"
submit victim identifier      → mail sent to victim, e-mail execution parked (FORK)
re-enter reset-credentials    → sticky flag serves a form targeting the parked e-mail execution
POST that form                → ResetCredentialEmail.action() → success() → gate bypassed
                              → flow advances to UPDATE_PASSWORD → attacker sets the password

Seis solicitudes HTTP, sin autenticación, sin parámetro authenticationExecution en ningún punto.

La corrección (PR #51844)

  • La nota ahora almacena model.getId(), y processFlow() lo respeta solo cuando es igual a CURRENT_AUTHENTICATION_EXECUTION; de lo contrario, lo elimina. En el ataque, los dos difieren (id de choose-user vs. id de e-mail-gate), exactamente lo que detecta el parche, y exactamente la señal en la que se basa --safe-check.
  • ResetCredentialEmail.action() ahora requiere context.getUser().getId().equals(authNote(ACTION_TOKEN_USER_ID)) y, de lo contrario, falla con INVALID_USER.

Descargar herramienta