
PoC de bucle local para una falla del broker SAML de Keycloak 26.8.1: un nombre SAMLResponse duplicado con codificación porcentual omite la verificación de firma de redirección, permitiendo iniciar sesión como otro usuario.
Alguien sin cuenta de Keycloak puede completar el inicio de sesión SAML de una empresa como otra persona. Inicia sesión una vez en el proveedor de identidad upstream, conserva esa redirección firmada y coloca un segundo documento SAML delante de ella bajo un nombre codificado en porcentaje. Keycloak verifica la firma legítima y luego inicia sesión con el nombre del documento falsificado. Esto requiere un broker SAML que firme respuestas HTTP-Redirect, con la validación de firma activada y las firmas de aserción desactivadas, que es lo que configura la importación de metadatos. No es el split por punto y coma de la issue #53354.
Clase: OAuth leftover Alcance: Remoto (sin autenticación en Keycloak; requiere un broker SAML que firme redirecciones)
Keycloak 26.8.1 (24ed1dad) - Red Hat
| ID | aún sin CVE |
| Clase | OAuth leftover |
| Alcance | Remoto (sin cuenta de Keycloak; requiere una firma HTTP-Redirect genuina del IdP) |
| CWE | CWE-287 / CWE-347 / CWE-116 |
| CVSS | Alto: 7.4 CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N |
| Producto | Keycloak |
| Afectado | 26.8.1 (24ed1dadf3f246a555adb6d3d4a99e9b3003fb3b); Quarkus 3.40.1; imagen quay.io/keycloak/keycloak:26.8.1 |
| Autenticación | ninguna en Keycloak. Requiere un broker de proveedor de identidad SAML con validateSignature=true y wantAssertionsSigned ausente o en false. |
| Licencia | GNU Affero GPL v3.0 |
| Laboratorio | solo 127.0.0.1:18084 |
Necesita el NameID de la víctima (normalmente un correo electrónico) y una redirección HTTP-Redirect firmada real de ese IdP. No necesita una contraseña de Keycloak. No necesita un buzón de correo. Un IdP solo-POST no entrega esa firma. El ACS GET permanece montado incluso cuando la importación de metadatos prefiere POST.
| Privilegio | Método / sink | Reconocimiento / integridad / disponibilidad | Probado en laboratorio o inferido |
|---|---|---|---|
| Vincular un documento SAML falsificado mientras la firma legítima aún se verifica | ACS del broker por GET con SAML%52esponse=<falsificado> delante de SAMLResponse firmado | Integridad (autenticación) | Probado en laboratorio. Correo de control [email protected]. Correo de ataque [email protected] |
| Crear el usuario víctima mediante el primer inicio de sesión del broker | callback.authenticated sobre el NameID falsificado | Integridad (creación de cuenta) | Probado en laboratorio. Recuento de víctimas 0 antes de la consulta dividida, 1 después |
| Sesión como un usuario existente del broker, incluido un administrador que usa el mismo IdP | Mismo ACS, NameID de ese usuario | Integridad (toma de control de cuenta) | Inferido. El laboratorio creó la víctima en el primer inicio de sesión |
| Conservar RelayState y la sesión de autenticación | RelayState permanece con el valor firmado | Integridad | Código fuente. La firma cubre RelayState |
| Control negativo | Redirección firmada legítima, sin parámetro adicional | n/a | Probado en laboratorio. El control finaliza como el correo del atacante |
Permanece cerrado en este leftover
| Eje | Método / sink | Por qué está cerrado |
|---|---|---|
| Integridad | Split por punto y coma SAMLResponse=...;SAMLResponse=... | issue #53354. quarkus.http.use-semicolon-as-query-param-delimiter=false |
| Integridad | Aserción sin firmar cuando wantAssertionsSigned=true | handleLoginResponse entonces exige una firma de aserción |
| Integridad | Sin broker SAML, o IdP solo-POST sin firma de redirección | El atacante nunca obtiene SigAlg + Signature en un GET |
| Integridad | RCE en el host, Admin REST sin autenticación | Fuera de clase |
| Integridad | Formulario de nombre VERIFY_PROFILE por defecto | Probado en laboratorio como paso de finalización, no como refutación. El formulario ya contiene el correo del broker |
Fijé Keycloak 26.8.1. RESTEasy Reactive toma @QueryParam("SAMLResponse") de Vert.x, que decodifica percent-encoding en los nombres de los parámetros de consulta, por lo que SAML%52esponse colapsa sobre SAMLResponse y gana el primer valor. verifyRedirectSignature reconstruye la cadena firmada a partir de getQueryParameters(false) sobre la consulta sin procesar, donde ese nombre permanece como una clave distinta.
Falsos caminos ya registrados: tratar #53354 como este remanente (nombre con percent-encoding, no punto y coma); seguir los 302 del ACS en el cliente de laboratorio y descartar AUTH_SESSION_ID; interpretar firstName/lastName vacíos en VERIFY_PROFILE como un fallo (el correo ya es el NameID federado); una reverse shell. Teatro.
Python 3.11+ con cryptography. Se requiere Docker.
python3 keycloak-saml-redirect-param-split-Abraxas-Labs.py
o:
cd lab
./run.sh
Dirígete solo a http://127.0.0.1:18084. Imagen quay.io/keycloak/keycloak:26.8.1. El lanzador hace chdir a lab/ y ejecuta run.sh. El IdP del laboratorio es in-process. Nunca se comunica con un proveedor de identidad real.
IOC image=quay.io/keycloak/keycloak:26.8.1 label-version=26.8.1
IOC serverinfo-version=26.8.1
IOC validate-signature=true want-assertions-signed=absent
IOC review-profile=DISABLED
IOC [email protected]
IOC victim-before=0
IOC [email protected]
IOC victim-after=1
SUCCESS KC-H04-SAML-REDIRECT kcs04b8n1
Verifique el mismo documento de consulta que analiza el endpoint. Decodifique los nombres de los parámetros con percent-decoding antes de reconstruir la firma, o rechace una consulta que contenga más de un SAMLResponse tras la decodificación. Active wantAssertionsSigned para los brokers de redirección, incluida la ruta de importación de metadatos.
24ed1dadf3f246a555adb6d3d4a99e9b3003fb3b)SAMLEndpoint.redirectBinding (SAMLEndpoint.java:182-183, :779-813, :896-914)SamlProtocolUtils.verifyRedirectSignature (SamlProtocolUtils.java:216-249)KeycloakUriInfo.getQueryParameters (KeycloakUriInfo.java:147-163)GNU Affero GPL v3.0. Consulte LICENSE. Solo para laboratorio en loopback. Sin garantía.
Abraxas Labs [email protected]
Atribuya el CVE a Abraxas Labs.