terça-feira, dezembro 14, 2021

Ruminações sobre o "log4Shell" (CVE-2021-44228)

Domingo, estou desligando a TV para dormir e o celular dispara: mensagem, email e chamada de voz! É um cliente preocupado com a vulnerabilidade no log4j descrita no CVE-2021-44228. Neste post vou falar um pouco sobre o que é, porque preocupa (e porque não), como resolver e algumas divagações filosóficas sobre como essas falhas surgem.

"Foi o Java que me deu"

Mas, Daniel, Você Programa Back-end em Java?

falei sobre isso antes. Longa história, mas acabei ficando responsável pela manutenção de um back-end escrito em Java (e depois fui mexer com um pouco de front-end). No fundo é tudo programar...

O Que É o log4Shell?

log4Shell é o nome popular ("engraçadinho") para uma vulnerabilidade na biblioteca log4j. log4j é uma biblioteca muito usada para gravação de log por aplicações Java. É uma biblioteca cheia de recursos, entre os quais suporte a JNDI - Java Naming and Directory Interface. A JNDI permite fazer consultas a objetos através de diversos serviços, inclusive recebendo um objeto remoto serializado. O uso do JNDI no log4j é feito colocando marcações especiais dentro do texto a ser registrado. Por exemplo, se a sua aplicação escrever no log o texto

    ${jndi:ldap://127.0.0.1/a}

Nas versões a partir da 2 (e dependendo de configuração), a log4j fará uma consulta ao serviço ldap da máquina local. Trocando 127.0.0.1 por um IP ou URL, a consulta será feita a um servidor remoto.

Porque Isso é Uma Vulnerabilidade e Como Provocar?

Suponhamos que você tenha uma aplicação acessível através da internet (via http, tcp, etc) que use o log4j e o atacante consiga fazer com que a aplicação log um texto contendo uma consulta JNDI a um servidor que ele controla. Isto permite que:

  • Informações sigilosas sejam enviadas para o servidor remoto (o log4j permite, por exemplo, consultar as variáveis de ambiente).
  • Um objeto malicioso seja retornado. Se o Java executar o código de iniciação o atacante pode executar qualquer coisa (a chamada execução remota de código ou RCE).
Portanto para provocar a vulnerabilidade (em um sistema susceptível), basta conseguir que ele grave no log (via log4j) o texto malicioso. Como fazer isso vai depender de como a aplicação recebe textos e quais textos são logados. Uma situação muito comum são aplicações web que registram no log informações recebidas nos cabeçalhos, como o "user-agent" (identificação do navegador). APIs também costuma registrar no log parâmetros recebidos.

Quando Isso Não Preocupa?

Caso óbvio: se você não usar a log4j (duh!).  Ou se estiver usando a versão 1 (que não tinha suporte a JNDI). Se você estiver usando uma versão entre 2.10 e 2.14 e a propriedade formatMsgNoLookups foi alterada para true. Ou se você estiver usando a versão 2.15 que assume por default formatMsgNoLookups=true.

Se você estiver usando Java 8u121 ou mais recente, por default a execução de código remoto está desabilitada (mas isso não impede a divulgação de informações sigilosas).

Se a sua aplicação permite acesso através de uma API proprietária fica mais difícil o atacante formatar uma chamada válida com o texto malicioso.

Como Resolver?

Eu recomendo você procurar uma fonte mais autoritária que eu (que sou mais um curioso que um especialista em segurança), mas aqui vão as ideias básicas. Note que elas pressupõe que você não precisa usar a JNDI.

A melhor solução é atualizar a log4j para a versão mais recente (2.15 no momento) e confirmar que a propriedade formatMsgNoLookups não está sendo forçada para false.

Se você está usando uma versão posterior a 2.10 e não pode (ou não quer atualizar), garanta que formatMsgNoLookups é true.

Se você estiver preso a uma versão após a 2 e antes da 2.10, você pode forçar a carga de uma versão vazia da classe org.apache.logging.log4j.core.lookup.JndiLookup, que é quem faz a consulta. É um hack feio, mas tapa o buraco.

A não ser que você precise deste recurso, garanta que a execução remota de código está desabilitada no Java.

Uma sugestão comum que não recomendo é tentar "limpar" os textos que serão logados. A chance de alguém conseguir burlar a limpeza ou de você estragar textos legítimos é muito alta.

O Lado Filosófico

A primeira pergunta filosófica é como foi que essa vulnerabilidade surgiu. Existem dois componentes nisso. O primeiro é a tendência a se incluir mais e mais recursos no código. Lembrem-se "todo novo recurso começa com 100 pontos negativos". O segundo é a dificuldade em lembrar que toda informação externa é potencialmente perigosa. No caso está se tratando de forma especial certas construções do texto a gravar que muitas vezes foi obtido externamente. Faria mais sentido que o recurso JNDI precisa-se ser habilitado explicitamente a cada chamada (e o programador deveria tomar o cuidado de só habilitá-lo quando ele construiu o texto e tomou cuidado com as informações externas).

A outra questão surge quando se tenta descobrir se uma aplicação usa a log4j. As aplicações atuais são tão complexas que são impossíveis de serem desenvolvidas sem o uso de módulos externos, que por sua vez exigem outros módulos externos. Sistemas automáticos gerenciam estas dependências (e, às vezes, até a atualização das versões). O resultado é que a maioria dos desenvolvedores não sabe mais o que está rodando.

No Final, Você Perdeu a Noite Toda?

Não. Bastou uma hora para verificar que o log4j não era usado. Os medicamentos na foto são meramente ilustrativos.

Referências



Um comentário:

Luiz Carlos G. Filho disse...
Este comentário foi removido pelo autor.