Em dezembro de 2021, a comunidade e as fundações de tecnologia identificaram uma série de vulnerabilidades na chamada Log4j, uma das bibliotecas de logging mais populares da plataforma Java.
O assunto rapidamente se espalhou pelas redes sociais e essa comoção gerou dúvidas, entre elas: o que pode acontecer com os sistemas que utilizam a biblioteca, quais os impactos dessas vulnerabilidades e o que pode ser feito para mitigá-las.
Neste artigo, vamos discutir todas estas questões em torno do problema e entender, em conjunto, como atacar da melhor maneira possível essa vulnerabilidade.
Agradecemos a contribuição de: Gabriela Moraes, Lucas Fonseca, Otavio Santana e Renato Burton.
Explicando os problemas com Log4J
O que é logging?
No contexto computacional, logging é o ato de manter registro de eventos que ocorrem em um software durante sua execução. Isso significa que cada linguagem e contexto de desenvolvimento de software disponibilizam bibliotecas para melhor atender essa demanda.
São estas bibliotecas que permitem você adicionar marcações de data/hora, acompanhar os estados da aplicação e o andamento de “requests” e “responses”, além de facilitar os processos de como localizar a causa raiz de problemas caso eles ocorram.
O que é o Log4J?
O Log4J é uma biblioteca de logging mantida pela Apache Foundation que fornece uma flexível e amigável forma de registrar mensagens de log em aplicações Java.
Apesar de não ser a biblioteca padrão do Java, sua utilização é bastante popular.
Quais são as vulnerabilidades identificadas e como elas ocorrem?
As vulnerabilidades encontradas até o dia 20 de dezembro de 2021 são:
A vulnerabilidade CVE-2021-44228 ocorre entre as versões 2.0-beta9 até 2.14.1 do Log4j. Ela é do tipo JNDI Injection, em que pode ser acionada caso dados não confiáveis sejam adicionados à execução de escrita do log, o que contribui para aumentar os riscos de vazamento de dados, ataques RCE (Remote Code Execution) e/ou LCE (Local Code Execution).
Correções foram realizadas na versão 2.15.0 para mitigar a vulnerabilidade CVE-2021-44228. No entanto, por ela não ter sido totalmente resolvida, acabou dando brecha para surgir mais uma vulnerabilidade na Log4j, desta vez a CVE-2021-45046, na qual utilizando certas configurações não padrão, é possível explorar as vulnerabilidades de versões anteriores.
Na versão 2.16.0 do Log4j, foi desativado o suporte a chamadas JNDI por padrão, porém foi detectada a possibilidade de executar ataques DoS (Denial of Service), gerando assim uma terceira vulnerabilidade, a CVE-2021-45105, na qual dados maliciosos podem desencadear um problema de recursividade interna durante a interpretação desses tais dados.
Nas versões 2.17.0 e anteriores do Log4j, foi detectada uma nova vulnerabilidade, a CVE-2021-44832, onde através de uma configuração não padrão ou incorreta da biblioteca é possível habilitar a utilização de chamadas JNDI, possibilitando o invasor executar comandos maliciosos provenientes de algum servidor não confiável. Sua ativação está relacionada diretamente a uma má configuração (misconfiguration).
Como essas vulnerabilidades acontecem?
Para explicar como essas vulnerabilidades podem ocorrer, precisamos entender como o Log4J escreve suas mensagens.
Para prover uma forma flexível de enriquecer as mensagens e seu contexto, o Log4J utiliza o Mapped Diagnostic Context (MDC), em que é possível definir informações a serem utilizadas na escrita da mensagem. Isso é possível porque o MDC utiliza uma estrutura de mapa e valor (Thread Context Map) ou buscas em dados em contextos (Context Lookup Pattern) com o intuito de construir o contexto de cada mensagem.
Através do controle do MDC utilizando o Context Lookup Pattern, é possível realizar chamadas JNDI – Java Naming Directory Interface ™ -, que suportam múltiplos protocolos, por exemplo, LDAP, COS, RMI, DNS, entre outros.
Tendo em vista que bibliotecas de logging como o Log4J são amplamente utilizadas para registrar dados de entrada e saída de uma aplicação com objetivo de rastreamento, esta vulnerabilidade abre oportunidade para que cibercriminosos manipulem esses dados de forma que viabilize ataques.
Vendo, na prática, quando aparecem as vulnerabilidades no Log4j
Para compreender como ocorre as vulnerabilidades CVE-2021-44228 e CVE-2021-45046, vamos acompanhar as imagens abaixo com um exemplo prático de como acontece um ataque JNDI em um campo do cabeçalho da requisição HTTP que será provavelmente registrado pelo Log4J como o header HTTP User-Agent.
Neste ataque, ao interpretar essas informações maliciosas, a aplicação pode carregar dados importantes de seu ambiente e publicá-lo em algum servidor malicioso.
Em uma variação desse ataque, a aplicação pode estar sendo orientada a carregar para seu contexto algum código malicioso, como no exemplo a seguir:
Para compreender como ocorre a vulnerabilidade CVE-2021-45105, o processo se inicializa ao passar dados maliciosos em algum campo do cabeçalho da requisição HTTP, que será provavelmente registrado pelo Log4J como o header HTTP User-Agent.
Através do Context Lookup Pattern, a pessoa que está fazendo o ataque insira comandos que, durante a interpolação, irá desencadear uma execução recursiva, causando o estouro de pilha (StackOverflowError) e, assim, derrubando a aplicação.
A imagem abaixo ilustra esse processo:
Na vulnerabilidade CVE-2021-44832, a configuração que contenham “Appenders” customizados que utilizam chamadas JNDI possibilitam que sejam informadas URLs maliciosas. Essa configuração pode ser proveniente de agentes externos ou internos, através de controles de versão de códigos (GIT, SVN, Mercurial, e outros) ou outra vulnerabilidade que possibilita o upload de arquivos irrestritos.
Uma vez que essa configuração for utilizada pela aplicação, a biblioteca irá se conectar ao servidor malicioso e poderá assim carregar códigos não seguros no ambiente, danificando o estado do ambiente ou então abrindo oportunidades para atacantes externos invadir e executar comandos arbitrários comprometendo o sistema. A imagem abaixo ilustra esse cenário:
Qual é o real impacto dessas vulnerabilidades para o meu projeto?
É preciso reforçar que essas vulnerabilidades são de alto risco, pois além de exporem dados sigilosos da empresa, podem adulterá-los ou destruí-los, comprometendo todo o ambiente.
Sua mitigação e resolução imediata são de extrema importância e isso pode exigir uma extensa verificação em todo o ambiente e soluções que utilizam Java como seu principal ecossistema, como middlewares e outros serviços (JBoss, Wildfly, Glassfish, Tomcat, Jetty, AMQ, entre outros).
O que eu faço para resolver as vulnerabilidades no Log4j?
A atualização da versão do Log4j para v2.17.1 é a melhor solução para todas essas vulnerabilidades. Além disso, é importante garantir que todas as bibliotecas da sua aplicação, que também dependam do Log4j, estejam atualizadas.
Caso não seja possível essa atualização, a propriedade log4j2.formatMsgNoLookups=true pode ser adicionada para desabilitar este tipo de lookup. Porém, isso só é possível a partir da versão v2.10.
Lembrando que isso mitiga os problemas relacionados às vulnerabilidades CVE-2021-44228 e CVE-2021-45046 e não as vulnerabilidades CVE-2021-45105 e CVE-2021-44832.
Para mitigar a vulnerabilidade CVE-2021-45105, você deve garantir que os dados que forem interpretados pelo Log4j não desencadeiam chamadas recursivas que possam derrubar sua aplicação (DDoS), utilizando-se de técnicas de sanitização, por exemplo. Lembrando que além disso pode ser um trabalho árduo também não garante a total mitigação dessa vulnerabilidade, um exemplo na imagem abaixo podemos ver posts nas redes sociais com possíveis “bypass” para explorar a vulnerabilidade.
Quanto à vulnerabilidade CVE-2021-44832, é preciso ter em mente que ela é dependente de uma configuração equivocada (misconfiguration), então a verificação quanto a implementação dessas configurações são extremamente necessárias para mitigar esse cenário.
Uma boa notícia é que, hoje, é possível apostar em soluções que ajudem a prevenir vulnerabilidades e outros riscos de segurança. É o caso, por exemplo, do Horusec, nossa ferramenta Open Source de análise estática de código, SAST, que possui, na sua versão mais recente, a possibilidade de análise de código para essas vulnerabilidades e muito mais.
Como o Horusec pode ajudar contra essas e outras vulnerabilidades?
É fundamental que você tenha em sua aplicação ferramentas que façam análises e varredura de vulnerabilidades para garantir a segurança de seu projeto.
Nesse sentido, ferramentas como o Horusec podem ser a solução mais estratégica. No caso das vulnerabilidades do Log4j, o ideal é que você utilize a versão v2.6.9 ou superior.
Ao instalar o Horusec, você pode obter essa informação tal como no trecho abaixo:
/ $ horusec version
Version: v2.6.9
Git commit: b0e752938922fd9cd909fc169aefc3c26c3092ad
Built: Tue Jan 11 16:40:47 2022
Distribution: normal
Você pode, ainda, executar a instalação e/ou atualização da ferramenta em seu ambiente. O comando a seguir executa a instalação em um Linux/MacOS, porém é necessário consultar nossa documentação para verificar a instalação para Windows.
/ $ curl -fsSL https://raw.githubusercontent.com/ZupIT/horusec/main/deployments/scripts/install.sh | bash -s latest
Version set to latest
Installing Horusec for Linux amd64
Downloading horusec...
https://github.com/ZupIT/horusec/releases/latest/download/horusec_linux_amd64
[sudo] password for maximillianarruda:
Horusec was downloaded and moved to /usr/local/bin/horusec
Version: v2.6.9
Git commit: b0e752938922fd9cd909fc169aefc3c26c3092ad
Built: Tue Jan 11 16:40:47 2022
Distribution: normal
Testando o Horusec na prática
Como exemplo, vamos utilizar um projeto Gradle que temos em nosso repositório de exemplos de códigos vulneráveis localizado em java/example2:
/ $ git clone git@github.com:ZupIT/horusec-examples-vulnerabilities.git
Cloning into 'horusec-examples-vulnerabilities'...
remote: Enumerating objects: 672, done.
remote: Counting objects: 100% (672/672), done.
remote: Compressing objects: 100% (368/368), done.
remote: Total 672 (delta 155), reused 639 (delta 133), pack-reused 0
Receiving objects: 100% (672/672), 1.48 MiB | 2.43 MiB/s, done.
Resolving deltas: 100% (155/155), done.
Após realizar o clone do projeto, vamos ao diretório do projeto /java/example2/ na qual iremos trabalhar:
/ $ cd horusec-examples-vulnerabilities/java/example2/
Em seguida, vamos executar o Horusec para identificar vulnerabilidades nos arquivos do projeto:
/ $ horusec start -p=./
WARN[0000] {HORUSEC_CLI} Config file not found
WARN[0000] {HORUSEC_CLI} When starting the analysis WE SKIP A TOTAL OF 3 FILES that are not considered to be analyzed. To see more details use flag --log-level=debug
WARN[0000] Horusec will return a timeout after 600 seconds. This time can be customized in the cli settings.
WARN[0000] {HORUSEC_CLI} PLEASE DON'T REMOVE ".horusec" FOLDER BEFORE THE ANALYSIS FINISH! Don’t worry, we’ll remove it after the analysis ends automatically! Project sent to folder in location: [/home/maximillianarruda/repos/github.com/ZupIT/horusec-examples-vulnerabilities/java/example2/.horusec/08d8c1e6-82dc-421a-95c9-54b3398d983d]
⣻ Scanning code ...
Após a execução, na saída da aplicação deve constar a utilização da versão 2.14.0 do Log4J:
Language: Java
Severity: CRITICAL
Line: 14
Column: 4
SecurityTool: HorusecEngine
Confidence: MEDIUM
File: /home/maximillianarruda/repos/github.com/ZupIT/horusec-examples-vulnerabilities/java/example2/build.gradle
Code: compileOnly 'org.apache.logging.log4j:log4j-api:2.14.0'
RuleID: HS-JAVA-150
Details: Remote code injection Apache Log4j
Log4j versions prior to 2.17.1 are subject to a remote code execution vulnerability via the ldap JNDI parser, uncontrolled recursion from self-referential lookups and some other vulnerabilities. For more information checkout the CVE-2021-44228 (https://nvd.nist.gov/vuln/detail/CVE-2021-44228), CVE-2021-45046 (https://nvd.nist.gov/vuln/detail/CVE-2021-45046), CVE-2021-45105 (https://nvd.nist.gov/vuln/detail/CVE-2021-45105) and CVE-2021-44832 (https://nvd.nist.gov/vuln/detail/CVE-2021-44832) advisories.
Type: Vulnerability
ReferenceHash: ee8669dd7aab9fe05092acfb820979aff709def9f0d784169a3de884c8fd1322
Nesta saída, o Horusec nos informa que temos a vulnerabilidade na linha 14 relacionada à utilização do Log4J na versão 2.14.0, detectada no arquivo build.gradle. No trecho de código na sequência, podemos ver a declaração de dependências apontadas na verificação:
...
13 dependencies {
14 compileOnly 'org.apache.logging.log4j:log4j-api:2.14.0'
15 runtimeOnly 'org.apache.logging.log4j:log4j-core:2.14.0'
16 }
...
O Horusec traz a orientação de como podemos solucionar essa vulnerabilidade que, neste caso, indica a necessidade de atualizar a ferramenta para a versão 2.17.1, descrita no arquivo build.gradle:
...
13 dependencies {
14 compileOnly 'org.apache.logging.log4j:log4j-api:2.17.1'
15 runtimeOnly 'org.apache.logging.log4j:log4j-core:2.17.1'
16 }
...
Após a atualização, podemos executar novamente a verificação do Horusec para garantir se o problema foi mitigado:
/ $ horusec -p=./ start
WARN[0000] {HORUSEC_CLI} Config file not found
WARN[0000] {HORUSEC_CLI} When starting the analysis WE SKIP A TOTAL OF 3 FILES that are not considered to be analyzed. To see more details use flag --log-level=debug
WARN[0000] Horusec will return a timeout after 600 seconds. This time can be customized in the cli settings.
WARN[0000] {HORUSEC_CLI} PLEASE DON'T REMOVE ".horusec" FOLDER BEFORE THE ANALYSIS FINISH! Don’t worry, we’ll remove it after the analysis ends automatically! Project sent to folder in location: [/home/maximillianarruda/repos/github.com/ZupIT/horusec-examples-vulnerabilities/java/example2/.horusec/57c8b662-a7de-4266-8251-d2802c291d51]
⣻ Scanning code ...
==================================================================================
HORUSEC ENDED THE ANALYSIS WITH STATUS OF "success" AND WITH THE FOLLOWING RESULTS:
==================================================================================
Analysis StartedAt: 2022-01-11 14:18:46
Analysis FinishedAt: 2022-01-11 14:18:56
==================================================================================
WARN[0010] {HORUSEC_CLI} No authorization token was found, your code it is not going to be sent to horusec. Please enter a token with the -a flag to configure and save your analysis
WARN[0010] YOUR ANALYSIS HAD FINISHED WITHOUT ANY VULNERABILITY!
WARN[0010] {HORUSEC_CLI} Horusec not show info vulnerabilities in this analysis, to see info vulnerabilities add option "--information-severity=true". For more details use (horusec start --help) command.
A saída mostra a mensagem “YOUR ANALYSIS HAD FINISHED WITHOUT ANY VULNERABILITY!”, o que confirma que resolvemos o problema com as vulnerabilidades CVE-2021-44228, CVE-2021-45046, CVE-2021-45105 e CVE-2021-44832, que comentamos no início deste artigo.
Para esse projeto de exemplo a atualização é algo simples, porém é altamente recomendável e necessário verificar se seu projeto comporta a versão recomendada através da construção e execução dos testes do projeto para, assim, garantir que todos os comportamentos estejam funcionando da maneira esperada.
Outro detalhe é salientar que, por se tratar de uma ferramenta SAST, o Horusec não realiza a análise semântica da árvore de dependências relacionadas a outras aplicações, a menos que isso seja declarado de forma explícita na sua aplicação.
Por isso que, cada vez mais, será necessário apostar em soluções como o Horusec para termos aplicações mais seguras.
E aí, o que achou de todo esse histórico sobre as vulnerabilidades encontradas com o Log4J e como solucioná-las com a ajuda do Horusec? Não deixe de trazer sua visão nos comentários.
Referências
- An update on the Apache Log4j 2.x vulnerabilities
- Apache Log4j 2
- CVE-2021-44228
- CVE-2021-44228 – Log4Shell Vulnerability
- Inside the Log4j2 vulnerability (CVE-2021-44228)
- Log4j2’s Lookups documentation
- Lesson: Overview of JNDI (The Java™ Tutorials > Java Naming and Directory Interface)
- Zero-Day Exploit Targeting Popular Java Library Log4j