Uma retrospectiva do Log4j parte 1: Histórico de vulnerabilidades
Linhas do tempo
Em 24 de novembro de 2021, a Apache Foundation foi notificada de forma privada pela equipe de Segurança na nuvem da Alibaba que o Log4j, uma biblioteca de logs baseada em Java amplamente utilizada, continha uma vulnerabilidade importante que poderia resultar no vazamento de informações privadas, bem como na execução remota de código (RCE). Esta vulnerabilidade estava presente desde 2013.
No dia seguinte, a Apache Foundation reservou CVE-2021-44228 e começou a pesquisar uma correção. Nos próximos 12 dias, várias alterações foram introduzidas no código-fonte para resolver o problema, e assim em 9 de dezembro de 2021, a vulnerabilidade foi divulgada publicamente.
Isso resultou em uma infinidade de tentativas de exploração que vêm crescendo a um ritmo alarmante desde então.
O que é Log4j?
Para realmente entender a vulnerabilidade, precisamos entender o que é o Log4j. Log4j é uma biblioteca que desfruta de uso generalizado entre desenvolvedores na comunidade Java. Ela fornece uma estrutura simples, porém robusta, para o registro de mensagens de erro, informações de diagnóstico e muito mais.
Entre alguns de seus recursos impressionantes está a capacidade de registrar em vários destinos, incluindo, entre outros, o console, um arquivo, um servidor remoto usando TCP, Syslog, NT Event Logs e e-mail. Além disso, ela permite a filtragem hierárquica de mensagens de registro, níveis de registro, layouts personalizados e muito mais.
Em resumo, ela tem um conjunto abrangente de recursos que a tornam uma biblioteca muito atraente para os desenvolvedores utilizarem, o que levou à sua popularidade em tudo, desde aplicações Web até dispositivos incorporados.
Pesquisas e aninhamento
Um dos recursos bastante poderosos suportados pelo Log4j é conhecido como pesquisas. As pesquisas permitem que um desenvolvedor incorpore variáveis ou expressões em texto que são automaticamente avaliadas pelo Log4j antes da saída. Por exemplo, um desenvolvedor pode escrever um código que registre o seguinte texto:
“${date:MM-dd-yyyy} Todos os sistemas operantes”
O Log4j reconhece o padrão ${date:MM-dd-yyyy} como uma pesquisa de data e substitui devidamente essa expressão pela data de hoje. Por exemplo, se a data fosse 20 de dezembro de 2021, ele modificaria o texto para o seguinte antes de colocá-lo em um destino:
"20-2021-12 Todos os sistemas operantes"
Isso é extremamente útil para os desenvolvedores. Sem essa funcionalidade, eles precisariam gravar manualmente o código que procura a data, formatá-la em uma string, anexá-la na linha de log e, em seguida, gerar a saída. E embora o código acima não seja particularmente difícil ou trabalhoso de escrever, ele não está relacionado à lógica de negócios principal do software e acaba sendo repetido de um projeto para o outro.
Ao aproveitar a funcionalidade já codificada na biblioteca Log4j, os desenvolvedores podem se concentrar na diferenciação que é importante para o projeto e deixar que o Log4j lide com todas as tarefas relacionadas ao registro em log.
Há muitos desses tipos de expressões de pesquisa compatíveis com o Log4j. Vamos examinar mais dois recursos que serão fortemente incluídos neste artigo: env e lower. env permite a inclusão de variáveis de ambiente no sistema host em linhas de log. Por exemplo, um desenvolvedor que registra o texto:
"O usuário atual é ${env:USER}"
produziria a seguinte saída, supondo que o software esteja sendo executado como administrador do usuário.
"O usuário atual é Administrator"
Diferentemente do env e da data que injetam novos dados no texto, lower pode ser usado para manipular o que já está presente. O Log4j simplesmente rebaixará o que aparece dentro da expressão. Como exemplo:
“O texto em caixa baixa é ${lower:ABCDEFG}”
produziria:
"O texto em minúsculas é abcdefg"
Este exemplo por si só não é muito interessante. Por que não apenas reduzir a string por conta própria? O poder observado torna-se mais óbvio quando consideramos que o Log4j permite o aninhamento de expressões de pesquisa.
Podemos combinar as duas expressões anteriores da seguinte forma:
“O atual usuário em caixa baixa é ${lower:${env:USER}}”
Isso faz com que o Log4j avalie primeiro a expressão ${env:USER} como Administratore, em seguida, envia isso ao lower, o que produziria administrator, resultando na seguinte linha:
"O usuário atual em minúsculas é administrator"
JNDI
Enquanto data, env e lower sejam todos interessantes e muito úteis, essa vulnerabilidade não seria possível sem a pesquisa de JNDI (Sistema de Nomes de Domínio). JNDI, ou Java Naming and Directory Interface, é um mecanismo construído nativamente nos ambientes de desenvolvimento e de tempo de execução Java que permite a consulta simplificada de vários serviços de diretório para obter informações usando uma interface comum.
Acontece que há muitos tipos diferentes de serviços de diretório suportados. Por exemplo, o JNDI permite a consulta de servidores DNS para detectar o endereço IP de um host, bem como a consulta de AD e LDAP para entradas de diretório. Ele permite até mesmo a consulta do próprio ambiente Java em execução em relação a Entradas Ambientais, que podem ser consideradas opções de configuração especializadas para o software em execução atual.
A expressão de pesquisa JNDI no Log4j permite que os desenvolvedores acessem esse subsistema extremamente poderoso diretamente com expressões incorporadas no texto registrado. Por exemplo, se um desenvolvedor tentar registrar a seguinte string:
“The current mail host is ${jndi:java:comp/env/mailhost}”
Log4j reconhecerá a expressão ${jndi:java:comp/env/mailhost} como uma pesquisa JNDI e passar a pseudo URL de java:comp/env/mailhost para o subsistema do JNDI. O JNDI reconheceria esse tipo de URL específico como uma consulta para pesquisar uma opção de configuração chamada mailhost com base no componente em execução atual.
Vamos imaginar que isso esteja configurado como mymailserver.example.com. O JNDI passaria essas informações de volta para o Log4j, que substituiria a expressão de pesquisa por mymailserver.example.com, resultando na seguinte saída:
"O host de e-mail atual é mymailserver.example.com"
Entenda como a vulnerabilidade existe
Em suma, a vulnerabilidade do Log4j do Apache apresentou uma grande oportunidade para os invasores devido à ampla popularidade da biblioteca e seus recursos de pesquisa, aninhamento e o JNDI em particular. Essa funcionalidade, embora poderosa para os desenvolvedores, também cria oportunidades para passar solicitações que podem exfiltrar dados ou causar RCE. Com esse conhecimento, agora podemos começar a entender melhor a vulnerabilidade e como os invasores podem explorar o sistema.
O que está por vir
Na parte 2 desta série, veremos como os invasores começaram a explorar essa vulnerabilidade para exfiltração de dados e RCE.