Apache Log4j2 does not always protect from infinite recursion in lookup evaluation
Prioritize patching. It exploitation observed by VulnCheck and has a public proof of concept.
Summary
DoS por recursão descontrolada (CWE-674/CWE-835) no processamento de lookups do Log4j2. Ao contrário do Log4Shell (CVE-2021-44228), não leva a RCE: um atacante que controle dados do Thread Context Map (MDC) e uma configuração de logging não padrão pode provocar StackOverflowError e derrubar o processo. O EPSS próximo de 1.0 reflete a onda de varredura em massa da família Log4j, não a facilidade real desta falha específica, que exige pré-condições que a maioria dos ambientes não tem.
Technical detail
A falha está na classe StrSubstitutor do Log4j2, responsável pela substituição de variáveis em lookups. Quando uma variável aninhada é substituída, o método substitute() é chamado recursivamente. O problema surge quando a variável aninhada referencia a própria variável sendo substituída: a recursão é chamada repetidamente com a mesma string, sem terminar. Segundo a análise da Zero Day Initiative (equipe da Trend Micro), quando uma variável aninhada é substituída pela classe StrSubstitutor, ela chama recursivamente substitute(); porém, quando a variável aninhada referencia a variável sendo substituída, a recursão é chamada com a mesma string, levando a recursão infinita e uma condição de DoS no servidor.
O resultado prático é um StackOverflowError que encerra o processo. É importante entender que esta vulnerabilidade não deve ser considerada uma variante do Log4Shell (CVE-2021-44228), embora abuse de vetor de ataque similar: ambas abusam de lookups controlados pelo atacante em dados logados, mas neste caso lookups não-JNDI podem ser abusados. Ou seja, o vetor de entrada (dados atacante-controlados que chegam ao mecanismo de lookup) é o mesmo do Log4Shell, mas a consequência é indisponibilidade, não execução de código.
O NVD classifica a falha sob CWE-20 (validação imprópria de entrada) e CWE-674 (recursão descontrolada); outras bases usam CWE-835 (loop com condição de saída inatingível). Todas descrevem o mesmo defeito: o produto não controla adequadamente a quantidade de recursão que ocorre, consumindo recursos excessivos como memória alocada ou a pilha do programa.
Apenas o componente log4j-core é afetado. Somente o pacote org.apache.logging.log4j:log4j-core é diretamente afetado por esta vulnerabilidade; o log4j-api deve ser mantido na mesma versão do log4j-core para garantir compatibilidade, se estiver em uso.
How it’s exploited
A pré-condição decisiva — frequentemente omitida das manchetes — é a configuração de logging. Um Pattern Layout não padrão na configuração de logging é necessário para acionar a CVE-2021-45105. Concretamente, quando a configuração de logging usa um Pattern Layout não padrão com um Context Lookup (por exemplo, $${ctx:loginId}), atacantes com controle sobre os dados de entrada do Thread Context Map (MDC) podem criar entrada maliciosa contendo um lookup recursivo, resultando em um StackOverflowError que encerra o processo — um ataque de negação de serviço.
O fluxo de exploração demonstrado pela ZDI ilustra os pré-requisitos concretos: a aplicação de exemplo é configurada com um Pattern Layout customizado contendo um Context Lookup (${ctx:apiversion}); implementa um servidor HTTP e define o valor do cabeçalho X-Api-Version recebido como o valor da variável apiversion no Thread Context Map. Sem essa combinação — Context Lookup presente no pattern E um campo do MDC alimentado por entrada externa — não há gatilho. Ambientes com a configuração padrão do Log4j2 não são exploráveis por este caminho.
O impacto final é estritamente disponibilidade: derrubar o processo Java com StackOverflowError. O vetor CVSS AV:N/AC:H reflete isso — rede, mas complexidade alta, sem impacto em confidencialidade ou integridade. O EPSS de ~1.0 deve ser lido com ceticismo: ele é inflado pela varredura indiscriminada por strings `${...}` que caracterizou a crise Log4j em dezembro de 2021, quando qualquer sonda pode aparecer nos mesmos logs. A exploração dirigida desta CVE específica requer conhecimento da configuração-alvo e de qual campo do MDC é atacante-controlável.
Versions
How to protect
A correção é atualizar o log4j-core. O problema foi corrigido no Log4j 2.17.0, 2.12.3 e 2.3.1. Usuários de Java 8 (ou posterior) devem atualizar para a release 2.17.0; 2.12.3 é o backport para o ramo Java 7 e 2.3.1 para o ramo Java 6. Na 2.17.0 a raiz foi eliminada arquiteturalmente: foram criadas duas classes que herdam de StrSubstitutor — ConfigurationStrSubstitutor, que só interpreta substituições em parâmetros de configuração, e RuntimeStrSubstitutor, que interpreta strings que podem conter entrada do usuário; com RuntimeStrSubstitutor, nenhuma avaliação recursiva é permitida.
Se a atualização não for imediata, há paliativos de configuração que atacam o pré-requisito, não a raiz. Segundo o advisory da Apache: alternativamente, isso pode ser mitigado na configuração — no PatternLayout, substitua Context Lookups como ${ctx:loginId} ou $${ctx:loginId} por padrões do Thread Context Map (%X, %mdc ou %MDC); caso contrário, remova referências a Context Lookups onde elas se originam de fontes externas à aplicação, como cabeçalhos HTTP ou entrada do usuário. O custo é operacional: exige inventariar cada configuração de logging e revisar cada uso de Context Lookup, o que em ambientes grandes é mais trabalhoso que o upgrade.
Sobre mitos: as mitigações amplamente divulgadas para o Log4Shell — remover a classe JndiLookup ou setar `log4j2.formatMsgNoLookups=true` — NÃO endereçam esta CVE, pois o abuso aqui é de lookups não-JNDI e não passa pela formatação de mensagem. Além disso, atualizar apenas para 2.16.0 é insuficiente: a 2.16.0 corrigiu CVE-2021-44228/45046 mas ainda contém este defeito. Log4j 1.x não é afetado por esta falha (mas está fora de suporte e tem outros problemas).
How to detect
Não há assinatura de rede confiável específica desta CVE. O gatilho é uma string com lookup auto-referencial chegando por um campo que alimenta o MDC (ex.: cabeçalho HTTP), e à primeira vista se parece com o tráfego de varredura genérico da família Log4j — as próprias assinaturas de IPS de fornecedores para este período detectavam o padrão amplo de exploração Log4j, não este DoS em particular. O sinal mais confiável é do lado do host, não da rede.
O indicador de exploração bem-sucedida é a terminação do processo Java por java.lang.StackOverflowError com stack traces mostrando chamadas recursivas repetidas a org.apache.logging.log4j...StrSubstitutor.substitute. Procure por crashes/reinícios inesperados de JVMs correlacionados com entrada externa incomum em campos que sabidamente alimentam o Thread Context Map. Ausência desse StackOverflowError nos logs, combinada com configuração de PatternLayout sem Context Lookups externos, é forte evidência de que o ambiente não é explorável por este vetor.