Por Eduardo Müller
Existe uma sensação de segurança ilusória, que acredita na utilização de firewall, ou outro recurso acessível apenas pela rede interna, como sendo suficiente à proteção contra ataques externos. Para os que já possuem alguma familiaridade com a área de cibersegurança, nosso título já é esclarecedor. Porém, nosso objetivo é, justamente, o de apresentar e explicar, para aqueles que não têm essa familiaridade, um tipo de vulnerabilidade que deve acabar com essa falsa sensação de segurança.
Server Side Request Forgery, mais conhecido como SSRF, é uma vulnerabilidade que permite ao atacante realizar requisições através de um servidor vulnerável. Seus alvos podem ser redes externas ou internas. Também é possível realizar comunicação com serviços de outros protocolos, ou seja, o atacante consegue induzir o servidor da aplicação vulnerável a realizar requisições de maneira arbitrária.
A imagem abaixo demonstra a ideia principal de um ataque do tipo SSRF:
Vale salientar que a técnica de SSRF não é limitada apenas ao protocolo HTTP, podendo ser utilizada por diferentes tipos de protocolos, como FTP, SMB, SMTP, etc. O uso de schemes distintos também é viável no SSRF, tais como, data://, file://, etc. Sendo assim, tanto o uso do protocolo, quanto do scheme, dependerão exclusivamente dos requerimentos da aplicação.
Para exemplificar melhor o que estamos dizendo, vamos supor que a aplicação a ser testada seja um blog. Nesse blog imaginário, os usuários podem publicar, bem como, comentar, curtir e compartilhar publicações de outros usuários. Especificamente na funcionalidade de postar uma publicação, é possível enviar um arquivo de imagem ou carregar uma imagem através de uma URL. Quando o segundo recurso é utilizado — — carregar uma imagem via URL — — a aplicação realiza a seguinte requisição:
Um eventual atacante, ao ver essa requisição, tentará alterar o valor do parâmetro load_picture, a fim de realizar uma requisição para um servidor sob seu controle. A requisição alterada terá a seguinte forma:
O atacante espera que a aplicação realize uma requisição para seu servidor. Caso isso aconteça, é bastante provável que a mesma possa estar vulnerável a ataques de SSRF; já que foi possível forjar uma requisição HTTP para um servidor específico através da aplicação blog de maneira arbitrária.
Tipos de SSRF
O SSRF pode apresentar-se de duas maneiras, Basic ou Blind.
O Basic é o mais evidente de detectar para ser explorado, pois é o caso em que a aplicação exibe o conteúdo da resposta: seja ela uma mensagem de erro, um json ou até mesmo uma outra página.
Já no Blind, não há a exibição do conteúdo da resposta por parte da aplicação. Entretanto, isso não significa que não esteja vulnerável a SSRF. O que ocorre é que o processo de exploração será diferente. Assim, teremos que nos atentar ao tempo de resposta da requisição e aos códigos de resposta HTTP, para buscar alguma lógica ou padrão que nos ajude a entender o funcionamento da aplicação. Somente assim será possível explorar a vulnerabilidade nos casos de SSRF do tipo Blind.
Acessando Arquivos Internos
Retomando nosso exemplo do envio de fotos para o blog, quando vimos ser possível carregar um objeto externo à aplicação, indagamos: O que aconteceria se o servidor não fizesse a distinção entre objetos externos e internos? Seria possível acessar arquivos internos? Sim, isso mesmo: a técnica de Server Side Request Forgery viabiliza acessar arquivos internos através de fuzzing. Com esse método, o atacante pode verificar a existência de arquivos de seu interesse para obter acesso aos mesmos. Desta maneira, seria preciso realizar a seguinte requisição para obter acesso a um possível arquivo passwd:
Escaneando Portas
Uma vez que o firewall foi ultrapassado, pela realização de requisições para a rede interna, baseando-se no tempo de resposta das requisições, pode-se escanear as portas para descobrir quais estão abertas ou fechadas. Por exemplo, a seguinte requisição possui código de resposta HTTP 200 (OK):
Em consequência da alteração da porta, esta outra requisição possui código de resposta HTTP 500 (Internal Server Error):
Sendo assim, pode-se deduzir que a porta 20 está aberta, enquanto que a 25 está fechada.
Enumerando Serviços
Ao escanear portas, também é possível enumerar serviços obtendo suas respectivas versões. Com estas informações em mãos, pode-se desenvolver ataques direcionados a serviços específicos, aumentando assim as chances de sucesso. Valendo-se da utilização de exploits públicos, essa técnica torna um eventual ataque contra um serviço específico (com a versão específica) mais eficiente.
A seguinte requisição ilustra um exemplo da obtenção da versão de um serviço utilizado:
Descobrimos assim a versão 6.7 do serviço OpenSSH através da resposta:
Atacando Aplicações Internas
É comum no ambiente empresarial a utilização de aplicações internas, que são acessadas somente através da rede interna, ou pelo menos assim deveriam ser, pois fazem parte da intranet da empresa. Infelizmente, também é comum que tais aplicações tenham um nível de segurança baixo, quando comparadas às aplicações externas. Isso acontece porque, devido ao fato de estarem na intranet, trazem uma sensação de segurança falsa e ilusória, que as acompanha desde a fase de desenvolvimento. Por isso mesmo, através de um SSRF, ataques a tais aplicações são possíveis.
Para este cenário vulnerável, vamos supor que exista uma interface administrativa acessível através de http://localhost/admin. Como a maioria das aplicações internas, esta também possui diversas outras vulnerabilidades, que permitem a execução da seguinte requisição de maneira não autenticada:
Deste modo, torna-se possível remover um usuário de uma aplicação interna de forma não autenticada através de uma vulnerabilidade em uma aplicação externa, burlando regras de firewall. Pois bem, com estes poucos exemplos, acreditamos já ter sido possível atestar o perigo dos ataques com SSRF. Sendo assim, vejamos o que pode ser feito para minimizar os riscos.
Mitigando o SSRF
De forma geral existem dois casos em que um SSRF pode acontecer:
- A aplicação apenas envia requisições para outras aplicações confiáveis (este método se aproxima bastante de uma Allow-List);
- A aplicação permite o envio de requisições para qualquer IP externo ou domínio.
No primeiro caso, é possível pensar em um cenário onde essa situação ocorra. Como exemplo, imaginemos uma primeira aplicação que precise realizar uma requisição para uma segunda, localizada em outra rede, a fim de buscar algum tipo de informação. A primeira medida a ser considerada, são as validações de input. Nesse cenário, a aplicação vai esperar receber um determinado conjunto de informações sobre a URL a ser requisitada. Essas informações seriam: endereço de IP; nome de domínio; URL e alguma string específica que precise estar na requisição. Vejamos, rapidamente, como tornar mais seguras as três primeiras:
Endereço de IP
Deve ser garantido que estão sendo inseridos valores válidos de endereços IPV4 ou IPV6; além disso, é preciso que o IP fornecido seja identificado como confiável pela aplicação. O endereço de IP deve ser confirmado com uma allow-list de IPs cuja permissão de realizar comunicação com a aplicação interna seja devidamente validada.
Nome de Domínio
É possível realizar uma resolução DNS a fim de verificar a existência de um domínio. Sendo necessário que haja uma validação do domínio para saber se é um domínio válido, confiável e identificado pela aplicação. Tal como para com o endereço de IP, é necessário realizar uma allow-list com todos os nomes de domínios a serem identificados. Ressaltamos que, mesmo assim, é preciso ter cuidado ao realizar esse tipo de checagem, pois a aplicação ainda pode estar vulnerável a DNS pinning. Por isso, é importante garantir que os domínios façam parte da sua organização e que sejam resolvidos internamente por servidores DNS internos. Além disso, deve-se monitorar a lista de domínios válidos a fim de detectar quando um desses resolver para um IP local.
URL
Não é recomendado o uso de URLs completas vindas do usuário, porque validar e realizar parser em URLs torna-se mais complicado.
Sobre quando a aplicação permite o envio de requisições para qualquer IP externo ou domínio, este segundo caso acontece quando um usuário pode controlar uma URL externa e a aplicação vulnerável realiza a requisição para essa URL. Como não há nenhum tipo de controle nesse segundo caso, as allow-list não são consideradas, dado não haver uma lista de IP ou de domínios que validem esse input. Esse é o pior caso a ser defendido, tornando o bloqueio de URLs dinâmicas na camada da aplicação uma tarefa desafiadora.
Recomendações de Segurança
Resumindo, seguem algumas recomendações de segurança, de acordo com nosso objetivo de contribuir para um mundo digital mais seguro:
- Realizar validação e filtragem dos dados recebidos pelo usuário;
- Desabilitar URL schemas não utilizados, como ftp://, sftp:// e http://;
- Utilizar uma allow-list com os IPs necessários para o funcionamento da aplicação.
REFERÊNCIAS
- https://portswigger.net/web-security/ssrf
- https://www.hackerone.com/blog-How-To-Server-Side-Request-Forgery-SSRF
- https://www.netsparker.com/blog/web-security/server-side-request-forgery-vulnerability-ssrf/
- https://medium.com/swlh/intro-to-ssrf-beb35857771f
- https://medium.com/@vickieli/exploiting-ssrfs-b3a29dd7437
- https://medium.com/@madrobot/ssrf-server-side-request-forgery-types-and-ways-to-exploit-it-part-1-29d034c27978
- https://medium.com/@madrobot/ssrf-server-side-request-forgery-types-and-ways-to-exploit-it-part-2-a085ec4332c0
- https://medium.com/@gupta.bless/exploiting-ssrf-for-admin-access-31c30457cc44