Ciberataques com IA: Como detetar, prevenir e defender-se contra ameaças inteligentes

Ler agora
Utilizamos inteligência artificial para as traduções dos sítios e, embora nos esforcemos por garantir a exatidão, estas podem nem sempre ser 100% precisas. Agradecemos a sua compreensão.

Descoberta técnica do Mongoose CVE-2025-23061 e CVE-2024-53900

por OPSWAT
Partilhar esta publicação

Mongoose é uma biblioteca de Modelagem de Dados de Objetos (ODM) para MongoDB que simplifica as interações de banco de dados em aplicativos Node.js. Ao fornecer uma solução baseada em esquema, o Mongoose permite que objetos JavaScript sejam mapeados para documentos MongoDB, atuando como uma camada de abstração que ajuda a estruturar dados para facilitar o gerenciamento e a validação. Com recursos como middleware para execução de lógica personalizada e um sistema intuitivo de construção de consultas, o Mongoose aumenta a eficiência do trabalho com o MongoDB. O Mongoose, descrito como "elegante modelagem de objetos MongoDB para Node.js", ganhou 27 mil estrelas no GitHub, refletindo seu uso generalizado e apreciação entre os desenvolvedores.

Programa de Bolsas de Estudo OPSWAT e Descoberta de Vulnerabilidades Críticas

O Programa de Bolsas de Estudo para Graduados em Cibersegurança de Infra-estruturas Críticas daOPSWAT , sediado no Vietname, proporciona aos estudantes graduados uma experiência prática na segurança de infra-estruturas críticas. Como parte deste programa, os bolseiros têm a oportunidade de analisar e resolver vulnerabilidades de cibersegurança, colaborando com especialistas OPSWAT para enfrentar desafios do mundo real em áreas como a deteção de malware, segurança de ficheiros e prevenção de ameaças. 

Durante o programa OPSWAT Fellowship, os participantes investigam e reproduzem sistematicamente CVEs conhecidos em vários produtos, bibliotecas e sistemas operativos. Como parte desta iniciativa, Dat Phung - um dos nossos distintos bolseiros - escolheu examinar o Mongoose devido à sua adoção generalizada em ambientes de produção. Em novembro de 2024, descobriu uma vulnerabilidade crítica no Mongoose enquanto efectuava uma análise aprofundada da biblioteca. A vulnerabilidade permitia que um atacante explorasse o valor $where, potencialmente levando à Execução Remota de Código (RCE) no servidor de aplicações Node.js. Após a comunicação imediata do problema à Mongoose, foi lançado um patch como parte da versão 8.8.3 e o CVE-2024-53900 foi divulgado na Base de Dados Nacional de Vulnerabilidades (NVD).

CVE-2024-53900 e CVE-2025-23061 Linha de tempo

  • 7 de novembro de 2024: Dat Phung identificou uma vulnerabilidade crítica no Mongoose e submeteu um relatório de segurança à Snyk. 
  • 26 de novembro de 2024: A Mongoose lançou a versão 8.8.3 para resolver e corrigir essa vulnerabilidade. 
  • 2 de dezembro de 2024: A Base de Dados Nacional de Vulnerabilidades (NVD) divulgou o CVE-2024-53900 para esta vulnerabilidade. 
  • 17 de dezembro de 2024: Ao analisar o patch 8.8.3 do Mongoose, Dat Phung encontrou um bypass que ainda permitia RCE (Execução Remota de Código). Um relatório de segurança detalhado foi enviado à Tidelift. 
  • 13 de janeiro de 2025: A Mongoose lançou a versão 8.9.5, introduzindo uma correção melhorada que resolvia eficazmente o desvio. 
  • 15 de janeiro de 2025: A National Vulnerability Database (NVD) divulgou oficialmente o CVE-2025-23061, salientando a gravidade da vulnerabilidade recentemente identificada.

Método Populate() do Mongoose

O Mongoose também fornece um recurso útil chamado populate() que aumenta a capacidade de trabalhar com relacionamentos entre documentos. Enquanto as versões do MongoDB ≥ 3.2 têm o operador de agregação $lookup para junções, o populate() do Mongoose oferece uma alternativa mais poderosa para substituir automaticamente uma referência com os dados correspondentes de documentos relacionados. Isso é particularmente útil para gerenciar relacionamentos entre diferentes coleções do MongoDB, como quando um documento faz referência a outro por seu _id. [2] 

Código JavaScript que define um esquema Mongoose para um autor com campos de nome, idade e biografia
Esquema de autores
Código JavaScript que define um esquema Mongoose para livros, incluindo título, descrição, preço e referências de autor
Esquema de livros
Trecho de código JavaScript para uma rota Node.js que recupera detalhes do livro e preenche os campos de autor ou resenha
Nodejs application

Ao definir um esquema no Mongoose, um campo pode ser definido para referenciar outro modelo utilizando a opção ref. O método populate() é então utilizado para substituir o campo referenciado (um ObjectId) pelo documento completo do modelo relacionado. Por exemplo, numa aplicação de loja de livros, o campo author no bookSchema faz referência ao documento Author e o campo review faz referência ao documento Reviews. O método populate() permite aos programadores substituir o campo author (que é um ObjectId) pelo documento Author completo quando consultam o modelo book.

A função populate() permite que os programadores substituam o campo author (que é um ObjectId) pelo documento Author completo quando consultam o modelo de livro:

Representação JSON de um documento MongoDB que armazena detalhes do livro sem informações expandidas sobre o autor
Não utilizar populate()
Representação JSON de um documento MongoDB com detalhes de autor expandidos utilizando a função de preenchimento
Utilizar populate()

Além disso, o método populate() do Mongoose suporta consultas personalizadas para definir que documentos relacionados são obtidos e como são obtidos. Propriedades como match e options permitem aos programadores filtrar, ordenar, limitar e saltar documentos relacionados, oferecendo capacidades flexíveis de obtenção de dados.

Código JavaScript demonstrando uma consulta personalizada usando a função populate do Mongoose para filtrar autores por idade
Consulta personalizada em populate() no Mongoose

Análise CVE-2024-53900

Como parte do programa OPSWAT Cybersecurity Graduate Fellowship, enquanto analisava o Mongoose para reproduzir CVEs conhecidos, Dat Phung realizou uma revisão abrangente do funcionamento interno do método populate(), que desempenha um papel fundamental no tratamento de relações entre documentos MongoDB. O método populate() suporta argumentos de string e objeto, e os desenvolvedores podem usar a opção match para aplicar filtros específicos nos dados que estão sendo recuperados:

Código JavaScript que mostra a utilização do operador $where para filtrar autores por idade numa consulta

No exemplo acima, a opção match é um objeto de filtro que pode incluir operadores de consulta do MongoDB, conforme detalhado no Query and Projection Operators - MongoDB Manual v8.0. Um operador notável é $where, que permite a execução de JavaScript diretamente no servidor MongoDB. No entanto, essa execução no servidor MongoDB é restrita, suportando apenas operações e funções básicas.

Tabela que lista as funções e propriedades JavaScript disponíveis para operações de map-reduce do MongoDB

Dat Phung realizou uma análise aprofundada do código-fonte do Mongoose para entender o fluxo de trabalho do método populate(). Ele determinou que, depois que o aplicativo chama o método populate() no modelo, a função populate() é acionada. Dentro dessa função, o Mongoose chama a função _execPopulateQuery() , que executa a consulta com o operador $where no servidor MongoDB. Em seguida, todos os documentos da coleção estrangeira são recuperados para serem populados nas próximas etapas.

Captura de ecrã de uma sessão de depuração do VS Code que analisa a execução de uma consulta de preenchimento do Mongoose

Depois de recuperar os dados do MongoDB, o Mongoose executa a função de retorno de chamada _done(), que chama _assign() para preparar os dados antes de "juntar" os dois modelos chamando a função assignVals().

Uma sessão de depuração no VS Code que mostra o código JavaScript destacado relacionado com a consulta $where no Mongoose

A vulnerabilidade pode surgir quando os dados recuperados são processados pela função assignVals() do Mongoose. Esta função verifica se a opção de correspondência é uma matriz e, em caso afirmativo, passa cada operador para a função sift(). A função sift() , que é importada de uma biblioteca externa com o mesmo nome, processa essas consultas localmente no servidor de aplicativos. Este processamento local apresenta um risco de segurança, especialmente quando se trata de entradas controladas pelo utilizador.

Uma sessão de depuração do VS Code que mostra atribuições de variáveis dentro de uma função JavaScript

Para aprofundar esta questão, Dat Phung modificou os valores na opção match para garantir que as condições eram satisfeitas, invocando assim a função sift() para uma análise adicional do fluxo de dados.

Um trecho de código JavaScript que demonstra uma consulta Mongoose com uma condição de filtro $where

Com a condição implementada, o operador $where foi subsequentemente passado para a função sift().

Uma sessão de depuração do VS Code mostrando valores filtrados em uma função JavaScript

A biblioteca sift é um utilitário JavaScript leve projetado para filtrar e consultar coleções de dados, como arrays ou objetos JSON, usando sintaxe semelhante à do MongoDB. De acordo com a documentação oficial, "Sift é uma pequena biblioteca para usar consultas MongoDB em JavaScript". A função sift() avalia as operações de filtragem do tipo MongoDB no servidor de aplicações em vez de no servidor de bases de dados, o que pode expor o sistema a riscos de segurança significativos ao processar entradas não confiáveis.

Um simples snippet JavaScript usando Sift.js para filtrar uma matriz de objectos com base em critérios de idade
Um exemplo de código Sift

Continuando a sua análise, o nosso colaborador identificou um problema na função createDefaultQueryTester() da biblioteca sift. Esta função converte cada operação da matriz de correspondências em funções JavaScript executáveis, que são depois utilizadas para filtrar e processar localmente os dados do documento MongoDB. Para conseguir isso, createDefaultQueryTester() invoca a função createNamedOperation(), passando operações como $where da matriz de correspondências como argumentos. 

Uma sessão de depuração do VS Code centrada em operações de consulta e execução de funções

Para cada operação na matriz de correspondências, createNamedOperation verifica se a operação é suportada e, em seguida, transmite-a à função correspondente.

Uma sessão de depuração de JavaScript que mostra operadores de consulta como $where, $eq e $exists

Se a operação for $where, é gerada uma função JavaScript utilizando o valor "params" em bruto, que é derivado do operador $where na matriz de correspondência e pode ser controlado pelo utilizador.

Um trecho de JavaScript destacado que demonstra a execução da função quando a CSP (Política de segurança de conteúdo) está activada

CVE-2024-53900: Detalhes da exploração

Embora o MongoDB limite a execução de funções JavaScript através da operação $where, como analisado anteriormente, a função sift() permite que essas funções sejam executadas sem tais restrições. Essa falta de validação e restrição de entrada introduz uma vulnerabilidade de segurança significativa, pois o valor "params" - controlado diretamente pela entrada do usuário - pode ser explorado, potencialmente levando a ataques de injeção de código. Para examinar este problema mais detalhadamente, Dat Phung construiu a seguinte consulta:

Um trecho de JavaScript que mostra uma consulta do Mongoose usando a condição $where com uma execução de função potencialmente insegura

Inicialmente, a consulta não conseguiu executar outro processo, o que resultou no seguinte erro:

Um registo de erros do MongoDB que apresenta uma falha de execução do servidor devido a uma referência global indefinida

Este erro indica que o Mongoose tenta executar a operação $where no servidor MongoDB antes de passar o controlo para a função sift(). No entanto, devido às restrições das funções JavaScript na cláusula $where do MongoDB, ocorre um erro que impede a execução da consulta. Como resultado, o Mangusto interrompe o processo antes que ele possa alcançar a função sift() .

Para contornar a limitação, nosso colega aproveitou a variável "global" presente no servidor de aplicativos, que não existe no servidor MongoDB. Esta abordagem permitiu-lhe contornar a restrição no servidor MongoDB e permitir que a consulta chegasse à função sift():

Um monitor de computador que mostra o texto "o código não está a funcionar", assinalando um problema no processo de codificação

Com este valor, quando o Mongoose executa a operação $where no MongoDB, a ausência da variável "global" faz com que o operador ternário (typeof global != "undefined" ?global.process.mainModule.constructor._load("child_process").exec("calc") : 1) para retornar 1, evitando que o MongoDB lance um erro. Consequentemente, a consulta é executada no servidor MongoDB sem problemas.

No entanto, quando o mesmo valor chega à função sift(), que é executada no servidor de aplicações onde a variável "global" está disponível, desencadeia a criação da seguinte função:

Um ecrã monocromático com a frase "hello world" em texto a negrito

Prova de conceito de execução remota de código (RCE)

No exemplo de aplicação apresentado no início do blogue, se um atacante enviasse o seguinte pedido, poderia executar com êxito um ataque de execução remota de código (RCE):

Ecrã a preto e branco com o texto "the new york times" em destaque num tipo de letra a negrito
Diagrama que ilustra os pormenores técnicos das vulnerabilidades CVE do Mongoose, mostrando o fluxo de dados e os pontos de violação da segurança

O vídeo demonstra a Prova de Conceito para o CVE-2024-53900 que afecta as versões do Mongoose anteriores à 8.8.3, que não possui uma validação de entrada adequada para evitar a utilização indevida do operador $where juntamente com a biblioteca sift.

Correção incompleta e CVE-2025-23061

Com base no relatório de segurança de Dat Phung, a Mongoose introduziu uma correção destinada a resolver a vulnerabilidade anteriormente identificada (CVE-2024-53900) antes da sua divulgação pública. O patch relevante(Automattic/mongoose@33679bc) adicionou uma verificação para não permitir o uso de $where dentro da propriedade match passada para populate().

Este snippet verifica se a propriedade match passada para populate() é um array. Se for, o código itera através de cada objeto na matriz para ver se contém o operador $where. Se $where for detectado, é gerado um erro, impedindo que o payload malicioso se propague para a arriscada função sift().  

Como resultado, o payload que explora o CVE-2024-53900 falha esta verificação porque um objeto na matriz de correspondência contém $where, impedindo-o efetivamente de chegar a sift().

Enquanto esta atualização bloqueia corretamente o uso direto de $where dentro de um único nível de aninhamento, ela falha em detetar $where quando embutido dentro de um operador $or - uma estrutura que tanto o MongoDB quanto a biblioteca sift suportam totalmente.

MongoDB suporta o operador $or
A biblioteca Sift suporta o operador $or

Como resultado, um atacante pode aninhar $where sob $or para evitar a verificação de nível único do patch. Como o Mongoose inspeciona apenas as propriedades de nível superior de cada objeto no array de correspondência, o payload de desvio permanece sem ser detectado e eventualmente alcança a biblioteca sift, permitindo o RCE malicioso.

Carga útil usada para contornar a correção no mongoose 8.8.3

Prova de conceito para CVE-2025-23061

Para ilustrar a natureza incompleta da correção, Dat Phung reconstruiu o aplicativo de exemplo usando uma versão do Mongoose 8.9.4 (posterior à 8.8.3). Ao aninhar $wheredentro de uma cláusula $or, um atacante pode contornar a verificação e obter RCE.

A exploração de prova de conceito demonstra como o CVE-2025-23061 pode ser acionado nas versões do Mongoose anteriores à 8.9.5, permitindo a um atacante executar código arbitrário no servidor:

Mitigação e orientação

Para atenuar as vulnerabilidades que discutimos acima, certifique-se de que o seu sistema está atualizado com a versão mais recente do Mongoose.

MetaDefender Core usando o mecanismo SBOM pode detetar esta vulnerabilidade

OPSWAT MetaDefender CoreO MetaDefender Core, equipado com capacidades avançadas de SBOMSoftware Bill of Materials), permite que as organizações adoptem uma abordagem proactiva na abordagem dos riscos de segurança. Ao analisar as aplicações de software e as suas dependências, MetaDefender Core identifica vulnerabilidades conhecidas, tais como CVE-2024-53900 e CVE-2025-23061, dentro dos componentes listados. Isto permite que as equipas de desenvolvimento e segurança priorizem os esforços de correção, mitigando os potenciais riscos de segurança antes que estes possam ser explorados por agentes maliciosos. 

Abaixo está uma captura de ecrã do CVE-2024-53900 e do CVE-2025-23061, que foram detectados pelo MetaDefender Core com o SBOM:

Além disso, os CVEs também podem ser detectados pelo MetaDefender Software Supply Chainque utiliza MetaDefender Core com SBOM para identificar essas vulnerabilidades.

Mantenha-se atualizado com OPSWAT!

Inscreva-se hoje para receber as últimas actualizações da empresa, histórias, informações sobre eventos e muito mais.