
Ferramenta automatizada de verificação de defeitos para 6 CVEs do dnsmasq (CVE-2026-2291, 4890, 4891, 4892, 4893, 5172)
Ferramenta automatizada de caixa-preta para verificar 6 vulnerabilidades do dnsmasq (maio de 2026). Envia pacotes de ataque para um DUT ativo e reporta PASS/FAIL — sem necessidade de acesso ao código-fonte.
# Defina o DNS do DUT para o IP WAN do seu laptop via GUI primeiro, depois:
sudo python3 dnsmasq_cve_verify.py --laptop <YOUR_WAN_IP> --dut <DUT_LAN_IP> --dut-pass <SSH_PASS>
# Exemplo:
sudo python3 dnsmasq_cve_verify.py --laptop 10.0.0.211 --dut 192.168.1.1 --dut-pass '12345Asdf@'
| CVE | CVSS | Tipo | Vetor de Ataque | Recurso Afetado |
|---|
| CVE-2026-2291 | 9.2 | Estouro de buffer no heap | Remoto | extract_name() — sempre ativo |
| CVE-2026-5172 | 7.5 | Leitura fora dos limites / falha | Remoto | extract_addresses() — sempre ativo |
| CVE-2026-4890 | 7.5 | DoS por loop infinito | Remoto | Parsing de bitmap NSEC (--dnssec) |
| CVE-2026-4891 | 5.3 | Leitura fora dos limites no heap | Remoto | Validação RRSIG (--dnssec) |
| CVE-2026-4892 | 8.4 | Estouro de heap → root | Local/Adjacente | CLID DHCPv6 (--dhcp-script + DHCPv6) |
| CVE-2026-4893 | 5.3 | Bypass de validação | Remoto | Verificação de origem ECS (--add-subnet) |
Causa raiz: union bigname declara char name[MAXDNAME], mas caracteres de escape podem expandir um nome para 2*MAXDNAME+1 bytes, causando estouro de heap.
Método de teste: Envia consultas DNS contendo nomes de domínio com caracteres de bit alto (0x80+) que são escapados internamente como \DDD (4 bytes por byte de entrada). Se o dnsmasq falhar ou parar de responder, está vulnerável.
Comportamento corrigido: Rejeita nomes superdimensionados de forma graciosa (FORMERR/REFUSED) ou usa um buffer ampliado.
Causa raiz: Um campo rdlen falsificado permite que extract_name() avance o ponteiro além do fim do registro. O underflow dos bytes restantes produz um valor enorme → leitura fora dos limites massiva → falha.
Método de teste: Envia respostas DNS com registros CNAME onde rdlen é menor que o nome realmente codificado. Se o dnsmasq falhar, está vulnerável.
Comportamento corrigido: Valida que o ponteiro permaneça dentro do limite declarado de rdlen após extract_name().
Causa raiz: O parsing do bitmap de tipos NSEC avança por p[1] em vez de p[1]+2 (falta o tamanho do cabeçalho da janela). Com bitmap_length=0, o ponteiro nunca avança → loop infinito.
Método de teste: Envia um registro NSEC malicioso com window=0, bitmap_length=0. Se o dnsmasq parar de responder a TODAS as consultas (trava, não falha), está vulnerável. Explorável ANTES da validação RRSIG.
Comportamento corrigido: Avança por p[1]+2 e ignora bitmaps de comprimento zero.
Causa raiz: rdlen em RRSIG não é validado contra o tamanho mínimo (18 + nome do assinante). O comprimento calculado da assinatura sofre underflow para negativo → tratado como enorme → leitura fora dos limites.
Método de teste: Envia registros RRSIG com rdlen=10 (muito abaixo do mínimo de 31+ bytes). Falha = vulnerável.
Comportamento corrigido: Valida rdlen >= fixed_fields + signer_name_length antes de calcular o comprimento da assinatura.
Causa raiz: CLIDs DHCPv6 (até 65535 bytes) são codificados em hexadecimal via sprintf("%.2x") em daemon->packet (5131 bytes). CLID de 3000 bytes → string hex de 6000 bytes → estouro. O processo auxiliar é executado como root.
Método de teste: Envia DHCPv6 SOLICIT com Client Identifier de 3000 bytes. Requer adjacência IPv6 e --dhcp-script configurado. Falha do auxiliar = vulnerável.
Comportamento corrigido: Trunca ou valida o comprimento do CLID antes da codificação hexadecimal.
Nota: Alguns builds são compilados com -DNO_DHCP6 e NÃO são afetados por este CVE.
Causa raiz: process_reply() passa o comprimento do registro OPT (~23 bytes) em vez do comprimento total do pacote para check_source(). Todas as verificações de limites falham → a função sempre retorna 1 (válido).
Método de teste: Envia consultas DNS com a opção EDNS Client Subnet contendo prefixos de origem falsificados. Se o dnsmasq devolver o ECS sem validação, está vulnerável.
Comportamento corrigido: Passa o comprimento total do pacote para check_source(), permitindo verificações de limites adequadas conforme a RFC 7871, Seção 9.2.
Atualize para dnsmasq 2.92rel2 (recomendado)
dnsmasq_cve_verify.py)A principal ferramenta de QA. É executada no laptop de teste, envia pacotes de ataque ao DUT e reporta PASS/FAIL claro para cada CVE. Nenhuma modificação do DUT é necessária além de acesso SSH somente leitura para inspeção de estado.
┌─────────────────────────────────────────────────────────────────────┐
│ Laptop de Teste │
│ │
│ Interface LAN Interface WAN │
│ <LAPTOP_LAN_IP> <LAPTOP_WAN_IP> │
│ │ │ │
│ │ ┌────┴──────────────┐ │
│ │ │ Servidor DNS │ │
│ │ │ Malicioso (porta 53)│ │
│ │ └────┬──────────────┘ │
│ │ │ │
└────────┼───────────────────────────────┼────────────────────────────┘
│ Sub-rede LAN │ Sub-rede WAN
│ │
┌────────┼───────────────────────────────┼────────────────────────────┐
│ │ │ │
│ LAN: <DUT_LAN_IP> WAN: <DUT_WAN_IP> │
│ (gateway LAN) (uplink WAN) │
│ │
│ DUT (Roteador Linksys) │
│ dnsmasq (qualquer versão < 2.92rel2) │
│ │
│ resolv-file=/etc/resolv.conf │
│ → nameserver <LAPTOP_WAN_IP> ← definido via GUI, encaminha para nós │
│ │
└─────────────────────────────────────────────────────────────────────┘
Fluxo de dados:
1. A ferramenta envia consulta DNS ao IP LAN do DUT (porta 53)
2. O dnsmasq do DUT não consegue resolver localmente → encaminha para LAPTOP_WAN_IP
3. Nosso servidor malicioso na interface WAN responde com o payload de exploração
4. O dnsmasq do DUT processa a resposta maliciosa → falha/trava/sobrevive
5. A ferramenta verifica o estado do DUT via SSH (somente leitura)
Exemplo de configuração (seus IPs serão diferentes):
| Papel | IP (exemplo) |
|---|---|
| LAN do laptop | 192.168.1.254 |
| WAN do laptop | 10.0.0.211 |
| LAN do DUT | 192.168.1.1 |
| WAN do DUT | 10.0.0.214 |
O requisito principal: O IP WAN do laptop e o IP WAN do DUT devem estar na mesma sub-rede, para que o DUT consiga alcançar o laptop como servidor DNS upstream.
┌──────────┐ ┌───────────┐ ┌──────────────────┐ ┌──────────┐
│ SETUP │ ──► │ TRIGGER │ ──► │ INSPECIONAR │ ──► │ VEREDITO│
│ │ │ │ │ ESTADO │ │ │
│ Iniciar │ │ Enviar │ │ SSH para o DUT: │ │ PASS: │
│ servidor │ │ consulta │ │ - pidof dnsmasq │ │ sobreviveu│
│ DNS │ │ DNS para │ │ - PID mudou? │ │ │
│ malicioso│ │ DUT→DUT │ │ - dmesg com │ │ FAIL: │
│ na WAN │ │ encaminha │ │ falha? │ │ falhou/ │
│ interface│ │ para nós→ │ │ - /var/log/msg │ │ travou │
│ (10.0.0. │ │ nós │ │ │ │ │
│ 211:53) │ │ respondemos│ │ Consulta de │ │ │
│ │ │ com │ │ atividade │ │ │
│ │ │ payload │ │ (version.bind) │ │ │
│ │ │ de │ │ │ │ │
│ │ │ exploração│ │ │ │ │
└──────────┘ └───────────┘ └──────────────────┘ └──────────┘
NOTA: A ferramenta NÃO modifica as configurações do DUT. O usuário deve definir o DNS para 10.0.0.211 via GUI.
paramiko instalado (pip install paramiko)Conecte o laptop de teste ao DUT com dois cabos:
| Porta do Laptop | Conecta-se a | Finalidade |
|---|---|---|
| Porta LAN | Porta LAN do DUT | Acesso SSH + envio de consultas DNS ao DUT |
| Porta WAN | Sub-rede WAN do DUT (ex.: porta do switch/modem upstream) | Atuar como servidor DNS upstream |
Após conectar, anote os IPs do seu laptop:
# Descubra seus IPs
ip addr show | grep "inet "
# Exemplo de saída:
# inet 192.168.1.254/24 ... ← este é seu IP LAN
# inet 10.0.0.211/24 ... ← este é seu IP WAN (use este para --laptop)
http://192.168.1.1 ou http://myrouter.local10.0.0.211)cd /path/to/dnsmasq-cve-2026/
# Execute todos os 6 testes de CVE:
sudo python3 dnsmasq_cve_verify.py --laptop <YOUR_WAN_IP> --dut <DUT_LAN_IP> --dut-pass <SSH_PASSWORD>
# Exemplo:
sudo python3 dnsmasq_cve_verify.py --laptop 10.0.0.211 --dut 192.168.1.1 --dut-pass '12345Asdf@'
A ferramenta irá:
| Problema | Solução |
|---|---|
| "DUT não está encaminhando consultas para nós" | Verifique se o Passo 2 foi feito corretamente. Confira se o IP WAN do laptop corresponde ao que você inseriu na GUI. |
| "Não foi possível conectar ao DUT" | Verifique as credenciais SSH. Tente: ssh [email protected] manualmente. |
| "Não foi possível vincular a porta 53" | Execute com sudo. Ou use --dns-port 5353 (requer configuração manual do DUT). |
| "Versão: desconhecida" | O DUT pode não ter o dnsmasq no caminho padrão. A ferramenta ainda testa corretamente. |
| CVE | Resultado | Motivo |
|---|---|---|
| CVE-2026-2291 | PASS | DNSSEC não compilado |
| CVE-2026-4890 | PASS | DNSSEC não compilado |
| CVE-2026-4891 | PASS | DNSSEC não compilado |
| CVE-2026-4892 | PASS | dnsmasq não está servindo DHCPv6 (servidor DHCPv6 separado em uso) |
| CVE-2026-4893 | PASS | Apenas bug de lógica — sem falha |
| CVE-2026-5172 | PASS | Sobreviveu à exploração (caminho de código vulnerável não está no 2.78) |
| CVE | Resultado | Motivo |
|---|---|---|
| CVE-2026-2291 | PASS | DNSSEC não compilado |
| CVE-2026-4890 | PASS | DNSSEC não compilado |
| CVE-2026-4891 | PASS | DNSSEC não compilado |
| CVE-2026-4892 | PASS | DHCPv6 não compilado |
| CVE-2026-4893 | PASS | Apenas bug de lógica — sem falha |
| CVE-2026-5172 | PASS | Sobreviveu às variantes de exploração |
Todos os roteadores Linksys testados não são praticamente exploráveis para nenhum dos 6 CVEs em suas configurações de build de produção. Os recursos perigosos (DNSSEC, DHCPv6-via-dnsmasq) ou não são compilados ou não estão configurados. Patches ainda são recomendados como defesa em profundidade.
Pré-correção (dnsmasq 2.78, build sem DNSSEC):
| CVE | Resultado | Motivo |
|---|---|---|
| CVE-2026-2291 | PASS | DNSSEC não compilado — não explorável |
| CVE-2026-4890 | PASS | DNSSEC não compilado — não explorável |
| CVE-2026-4891 | PASS | DNSSEC não compilado — não explorável |
| CVE-2026-4892 | PASS/FAIL | DHCPv6 compilado + dhcp-script ativo |
| CVE-2026-4893 | PASS | Bug de lógica — sem falha (apenas baseado em versão) |
| CVE-2026-5172 | PASS | Caminho blockdata_expand não está no 2.78 |
Pré-correção (dnsmasq 2.90 com DNSSEC habilitado):
| CVE | Resultado | Motivo |
|---|---|---|
| CVE-2026-2291 | FAIL | Estouro de heap via nomes escapados |
| CVE-2026-4890 | FAIL | Loop infinito (trava) |
| CVE-2026-4891 | FAIL | Falha por leitura fora dos limites em RRSIG |
| CVE-2026-4892 | PASS/FAIL | Depende da configuração de DHCPv6 + script |
| CVE-2026-4893 | PASS | Bug de lógica — sem falha |
| CVE-2026-5172 | FAIL | Leitura fora dos limites via rdlen falsificado |
Pós-correção (dnsmasq 2.92rel2 ou patches de backport aplicados): Todos os 6 CVEs → PASS
paramiko (pip install paramiko)| Flag | Padrão | Descrição |
|---|---|---|
--laptop | (obrigatório) | IP WAN do laptop (vincula o servidor DNS malicioso aqui) |
--dut | 192.168.1.1 | IP LAN do DUT (consultas SSH e DNS enviadas aqui) |
--dut-user | root | Nome de usuário SSH do DUT |
--dut-pass | (solicitado) | Senha SSH do DUT |
--dns-port | 53 | Porta do servidor DNS malicioso |
--cve | todos os 6 | CVE(s) específico(s) a testar (repetível) |
test_dnsmasq_cve_remote.py)Apenas verificação leve de versão — consulta version.bind para determinar se a versão
do dnsmasq está abaixo da correção. Sem SSH, sem configuração, sem payloads de exploração.
python3 test_dnsmasq_cve_remote.py 192.168.1.1
test_dnsmasq_cve_on_device.sh)É executado diretamente no DUT via SSH/serial. Verifica a versão do binário e as opções de compilação.
scp test_dnsmasq_cve_on_device.sh [email protected]:/tmp/
ssh [email protected] "sh /tmp/test_dnsmasq_cve_on_device.sh"
malicious_dns_server.py)Servidor de exploração autônomo para testes manuais. Execute-o, aponte o DNS upstream do DUT para ele
e depois dispare consultas para crash-5172.evil.test, crash-2291.evil.test, etc.
sudo python3 malicious_dns_server.py --port 53
# Depois no DUT: configure o upstream → este host
# Depois dispare: dig @192.168.1.1 crash-5172.evil.test
Após aplicar os patches e gravar o novo firmware, execute novamente:
sudo python3 dnsmasq_cve_verify.py --laptop <YOUR_WAN_IP> --dut <DUT_LAN_IP> --dut-pass <SSH_PASS>
# Esperado: todos os 6 PASS
| Ferramenta | Python | Root | SSH | Rede |
|---|---|---|---|---|
dnsmasq_cve_verify.py | 3.6+ paramiko | Sim (porta 53) | Sim (somente leitura) | LAN + WAN para o DUT |
test_dnsmasq_cve_remote.py | 3.6+ stdlib | Não | Não | UDP 53 para o DUT |
test_dnsmasq_cve_on_device.sh | N/A (shell) | Não | Executar no DUT | N/A |
malicious_dns_server.py | 3.6+ stdlib | Sim (porta 53) | Não | DUT encaminha para nós |