O mês de maio de 2025 marcou a divulgação pública de uma vulnerabilidade de segurança crítica, CVE-2025-1974, apelidada de IngressNightmare, que afecta o controlador Kubernetes ingress-nginx amplamente implementado em infra-estruturas nativas da nuvem. Essa vulnerabilidade permite que invasores não autenticados injetem configurações arbitrárias no NGINX, potencialmente levando a RCE (execução remota de código) não autorizado e comprometimento total do cluster.
Como parte do programa OPSWAT Fellowship, os nossos bolseiros efectuaram uma análise técnica aprofundada para compreender melhor a sua causa principal, o caminho de exploração e as estratégias de mitigação em torno deste problema de elevada gravidade.
Visão geral do CVE-2025-1974
O CVE-2025-1974 é uma vulnerabilidade crítica de injeção de modelos identificada nas versões do ingress-nginx até 1.11.4 e, especificamente, 1.12.0. Os atacantes com acesso em nível de nó a um cluster Kubernetes podem explorar essa falha para executar código arbitrário usando RCE por meio do controlador ingress-nginx que, por padrão, tem privilégios extensos, incluindo acesso a segredos críticos dentro do cluster.
O Comité de Resposta à Segurança da Kubernetes atribuiu a esta vulnerabilidade uma pontuação CVSS v3.1 de 9,8 (gravidade crítica):
Principais componentes desta análise
Visão geral do Kubernetes
O Kubernetes (K8s) é uma plataforma de código aberto para automatizar a implantação, o dimensionamento e o gerenciamento operacional de aplicativos em contêineres. Os clusters do Kubernetes consistem normalmente em várias máquinas, que podem incluir hardware físico e máquinas virtuais, trabalhando coletivamente para fornecer ambientes de aplicações altamente disponíveis, escaláveis e geríveis.
Controlador de entrada NGINX
O controlador de entrada NGINX (ingress-nginx) é um controlador de entrada de código aberto construído sobre o servidor web NGINX. Ele opera dentro de um cluster Kubernetes, funcionando principalmente como um proxy reverso e balanceador de carga. Este controlador interpreta os recursos Ingress definidos pelos utilizadores e converte-os em configurações NGINX acionáveis para encaminhar o fluxo de tráfego para e dentro do cluster.
Revisão da admissão e seu papel
O Ingress-nginx se integra ao Kubernetes usando um serviço de webhook chamado AdmissionReview. Esse serviço é crucial para processar objetos nativos do Kubernetes Ingress e traduzi-los em configurações NGINX validadas e sintaticamente corretas. Embora o AdmissionReview garanta a precisão da configuração, ele opera de forma independente do controlador ingress-nginx e geralmente não possui controles de autenticação rigorosos. Esta falta de autenticação rigorosa é um fator chave que contribuiu para a explorabilidade do CVE-2025-1974.
Exploração de vulnerabilidades e análise técnica
Mecanismo de exploração
Na sua essência, a exploração do CVE-2025-1974 começa com um pedido malicioso. Os atacantes criam um pedido malicioso para o webhook AdmissionReview, forçando o NGINX a carregar dinamicamente uma biblioteca partilhada em tempo de execução. Com base nesse mecanismo, nossos colegas analisaram o webhook do AdmissionReview e o fluxo de trabalho do NGINX para entender esse caminho de exploração.
Vulnerabilidade de injeção de modelos
No webhook AdmissionReview, ao processar os pedidos de entrada, a função CheckIngress transforma os objectos Kubernetes Ingress em ficheiros de configuração NGINX válidos. O fluxo procede da seguinte forma:
- Cada configuração é analisada e passada para generateTemplate para ser formatada de acordo com modelos NGINX predefinidos.
- Posteriormente, o testTemplate valida a configuração gerada em relação ao binário NGINX subjacente.
Todas as configurações do NGINX são baseadas em modelos predefinidos encontrados no ficheiro nginx.tmpl no código-fonte do ingress-nginx:
Na função generateTemplate, a configuração é processada como mostra o seguinte trecho de código:
No entanto, a validação e a higienização da entrada são insuficientes. Especificamente, o campo uid de um objeto Ingress é diretamente inserido no modelo de configuração do NGINX, criando um ponto de injeção. Um atacante pode explorar isto fornecendo uma entrada criada como uid="1234#;\n\n}\n}\n}\n injection_value".
Esta entrada maliciosa permite a injeção de âmbito global no modelo NGINX, permitindo aos atacantes desencadear diretivas NGINX arbitrárias e, potencialmente, obter RCE.
Da injeção de modelos à execução remota de código
Explicação da função testTemplate()
Depois de a configuração do NGINX ser gerada pela função generateTemplate, a função testTemplate cria um ficheiro de configuração temporário e executa a biblioteca NGINX com o comando nginx -c {config_file} -t. Isso força o binário do NGINX a analisar e validar a configuração.
Para explorar a vulnerabilidade, um atacante precisa de identificar uma diretiva capaz de executar código malicioso. Inicialmente, os nossos colegas identificaram a diretiva load_module como potencialmente útil, porque esta diretiva permite ao NGINX carregar plugins externos. No entanto, esta diretiva só é permitida na fase inicial da análise da configuração, o que não corresponde ao nosso ponto de injeção.
Para resolver este desafio, continuámos a investigar mais, o que levou à diretiva ssl_engine, descrita como "O módulo pode ser carregado dinamicamente pelo OpenSSL durante o teste de configuração". Isso despertou curiosidade devido à sua capacidade de carregar módulos dinamicamente, exigindo uma análise mais profunda.
Compreender a diretiva ssl_engine
Para entender melhor como o NGINX lida com a diretiva ssl_engine, bem como determinar as condições sob as quais o NGINX permite o carregamento dinâmico de módulos adicionais por meio dessa diretiva, examinamos o código-fonte do NGINX.
Na inicialização, o NGINX carrega seu estado inicial e, em seguida, analisa os arquivos de configuração linha por linha. Cada diretiva é tratada pela estrutura nginx_command_t, com a diretiva ssl_engine invocando diretamente o ngx_openssl_commands.
Ao analisar a função ngx_openssl_commands, nossos colegas descobriram que ela depende do suporte OpenSSL, especificamente a função ENGINE_by_id que é usada para módulos SSL acelerados por hardware.
E ao analisar a função ENGINE_by_id, determinámos que esta permite o carregamento dinâmico de bibliotecas partilhadas. Além disso, se a biblioteca for compilada com a extensão __attribute__ ((constructor)), a função associada pode ser executada imediatamente após o carregamento. Isto indica que, ao explorar a diretiva ssl_engine, um atacante pode carregar bibliotecas partilhadas arbitrárias no anfitrião, conduzindo potencialmente a RCE.
Visar bibliotecas partilhadas e estratégia de ataque
Para facilitar a execução do código de forma confiável, a próxima etapa envolve a identificação de uma biblioteca compartilhada. Em vez de depender de bibliotecas externas, uma abordagem mais viável e controlada emerge do próprio comportamento do NGINX: o mecanismo de buffer do corpo do cliente. Esse recurso permite que o NGINX descarregue grandes solicitações de entrada em arquivos temporários, abrindo oportunidades de exploração com base no comportamento previsível de manipulação de arquivos.
Por predefinição, quando um pedido de entrada excede 8 KB, o NGINX escreve o corpo do pedido num ficheiro temporário localizado em /tmp/nginx/client-body, utilizando um nome de ficheiro no formato cfg-{random_value}. Esses arquivos temporários são mantidos por até 60 segundos entre partes bem-sucedidas de uma mensagem recebida.
Depois de escrever um corpo de pedido parcial num ficheiro temporário, o NGINX adia a eliminação até que o corpo completo seja recebido. Se o pedido permanecer incompleto e não forem recebidos dados durante 60 segundos, o ficheiro é eventualmente eliminado. No entanto, ao reter intencionalmente a parte final dos dados, um atacante pode manter o ficheiro temporário em utilização, tornando-o explorável.
Embora o conteúdo do ficheiro carregado possa ser controlado, a sua localização no sistema de ficheiros é difícil devido ao nome de ficheiro aleatório. O caminho de armazenamento pode ser configurado usando client_body_temp_path, mas o nome do arquivo é gerado aleatoriamente em tempo de execução, tornando-o imprevisível. Essa aleatoriedade dificulta significativamente o acesso direcionado, mesmo por meio de força bruta. Para ultrapassar isto, a equipa aproveitou comportamentos inerentes ao sistema operativo Linux. Considere o seguinte exemplo:
This code opens a file and keeps it in an active state, closely mimicking the behavior of NGINX's client body buffer mechanism. Using /proc/{pid}/fd directory, attackers can find symbolic links created by the Linux kernel that map open file descriptors to their corresponding file paths. This route allows attackers to reduce the brute-force space to only two variables: the process ID (pid) and the file descriptor (fd).
Simulação de exploração
Com base na análise acima, uma abordagem prática de exploração para RCE dentro do pod Ingress-NGINX é:
- Carregar uma biblioteca partilhada maliciosa utilizando o mecanismo de buffer do corpo do cliente do NGINX para a armazenar temporariamente no sistema de ficheiros.
- Utilizar a injeção de modelos para iniciar uma tentativa de força bruta que obriga o NGINX a carregar a biblioteca partilhada previamente carregada através de diretivas vulneráveis.
Criação da carga útil que contém a biblioteca partilhada
Para garantir a execução do código aquando do carregamento, é definida uma função de ponto de entrada com extensão de construtor na biblioteca partilhada maliciosa. Esta função é executada após o carregamento pelo NGINX e foi concebida para estabelecer uma ligação reverse shell a um anfitrião remoto.
Após a compilação, o tamanho da biblioteca compartilhada resultante excedeu confortavelmente 8 KB, permitindo que ela fosse armazenada em buffer pelo NGINX sem exigir preenchimento adicional.
Os nossos colegas criaram então um pedido com um valor de Content-Length inflacionado (por exemplo, 1MB) para introduzir uma incompatibilidade de tamanho. Isso fez com que o NGINX colocasse o corpo inteiro em buffer em vez de processá-lo imediatamente, garantindo que o objeto compartilhado fosse gravado em um local previsível.
Acionamento da biblioteca compartilhada por meio de injeção
Com a biblioteca compartilhada no lugar, nós injetamos uma diretiva maliciosa na configuração do NGINX usando o campo uid vulnerável. Esta diretiva incluía ssl_engine apontando para o caminho do ficheiro armazenado em buffer:
O RCE bem-sucedido requer que a diretiva ssl_engine faça referência ao caminho correto para o arquivo armazenado em buffer. Isto pode ser conseguido através de um script automatizado de força bruta que itera sistematicamente sobre possíveis combinações de IDs de processos e descritores de ficheiros para identificar a ligação simbólica válida que aponta para o objeto partilhado em buffer.
Segue-se uma amostra do modelo NGINX gerado que acionou a exploração.
Após uma exploração bem-sucedida, o atacante poderia obter acesso ao shell sob o contexto do pod ingress-nginx, que por padrão tinha acesso a segredos sensíveis do cluster Kubernetes.
Mitigação e reparação
Para mitigar eficazmente os riscos associados ao CVE-2025-1974, as organizações necessitam de uma solução que forneça visibilidade e controlo sobre os seus componentes de código aberto.
OPSWAT SBOM, uma tecnologia fundamental dentro da plataforma MetaDefender®, atende a essa necessidade fornecendo um inventário de todos os componentes de software, bibliotecas, contêineres Docker e dependências em uso. Ele permite que as organizações rastreiem, protejam e atualizem seus componentes de forma proativa.
No exemplo acima, a tecnologia SBOM no MetaDefender Core™ escaneou o pacote nginx-ingress-controller que continha a vulnerabilidade CVE-2025-1974. O sistema sinalizou automaticamente o problema como Crítico e forneceu orientação sobre as versões corrigidas disponíveis, permitindo que as equipes priorizassem e corrigissem rapidamente a vulnerabilidade antes que ela pudesse ser explorada.
OPSWAT SBOM está disponível no MetaDefender Core e no MetaDefender Software Supply Chain™, permitindo que as equipas de segurança identifiquem e actuem sobre as vulnerabilidades mais rapidamente. Com o OPSWAT SBOM, as equipas de segurança podem:
- Localize rapidamente os componentes vulneráveis - Identifique imediatamente os componentes de código aberto afectados por ataques de desserialização. Isto garante uma ação rápida na aplicação de correcções ou na substituição das bibliotecas vulneráveis.
- Garanta a aplicação proactiva de patches e actualizações - Monitorize continuamente os componentes de código aberto através do OPSWAT SBOM para se manter à frente das vulnerabilidades de desserialização. OPSWAT SBOM pode detetar componentes desactualizados ou inseguros, permitindo actualizações atempadas e uma exposição reduzida a ataques.
- Manter a conformidade e os relatórios - OPSWAT SBOM ajuda as organizações a cumprir os requisitos de conformidade, uma vez que as estruturas regulamentares exigem cada vez mais transparência nas cadeias de fornecimento de software.