
Herramienta automatizada de verificación de defectos para 6 CVEs de dnsmasq (CVE-2026-2291, 4890, 4891, 4892, 4893, 5172)
Herramienta automatizada de caja negra para verificar 6 vulnerabilidades de dnsmasq (mayo de 2026). Envía paquetes de ataque a un DUT en vivo e informa PASS/FAIL — sin necesidad de acceso al código fuente.
# Configure el DNS del DUT con la IP WAN de su portátil a través de la GUI primero, luego:
sudo python3 dnsmasq_cve_verify.py --laptop <SU_IP_WAN> --dut <IP_LAN_DUT> --dut-pass <CONTRASEÑA_SSH>
# Ejemplo:
sudo python3 dnsmasq_cve_verify.py --laptop 10.0.0.211 --dut 192.168.1.1 --dut-pass '12345Asdf@'
| CVE | CVSS | Tipo | Vector de ataque | Función afectada |
|---|---|---|---|---|
| CVE-2026-2291 | 9.2 | Desbordamiento de búfer en el heap | Remoto | extract_name() — siempre activo |
| CVE-2026-5172 | 7.5 | Lectura fuera de límites / caída | Remoto | extract_addresses() — siempre activo |
| CVE-2026-4890 | 7.5 | Bucle infinito DoS | Remoto | Análisis de mapa de bits NSEC (--dnssec) |
| CVE-2026-4891 | 5.3 | Lectura OOB en heap | Remoto | Validación RRSIG (--dnssec) |
| CVE-2026-4892 | 8.4 | Desbordamiento de heap → raíz | Local/Adyacente | CLID DHCPv6 (--dhcp-script + DHCPv6) |
| CVE-2026-4893 | 5.3 | Omisión de validación | Remoto | Verificación de fuente ECS (--add-subnet) |
Causa raíz: union bigname declara char name[MAXDNAME] pero los caracteres escapados pueden expandir un nombre a 2*MAXDNAME+1 bytes, causando desbordamiento de heap.
Método de prueba: Envía consultas DNS que contienen nombres de dominio con caracteres de bit alto (0x80+) que se escapan internamente como \DDD (4 bytes por byte de entrada). Si dnsmasq se cuelga o deja de responder, es vulnerable.
Comportamiento corregido: Rechaza nombres sobredimensionados correctamente (FORMERR/REFUSED) o usa un búfer ampliado.
Causa raíz: Un campo rdlen falsificado permite que extract_name() avance el puntero más allá del final del registro. El desbordamiento negativo de los bytes restantes produce un valor enorme → lectura OOB masiva → caída.
Método de prueba: Envía respuestas DNS con registros CNAME donde rdlen es menor que el nombre codificado real. Si dnsmasq se cuelga, es vulnerable.
Comportamiento corregido: Valida que el puntero se mantenga dentro del límite declarado de rdlen después de extract_name().
Causa raíz: El análisis del mapa de bits NSEC avanza según p[1] en lugar de p[1]+2 (falta el tamaño del encabezado de ventana). Con bitmap_length=0, el puntero nunca avanza → bucle infinito.
Método de prueba: Envía un registro NSEC manipulado con window=0, bitmap_length=0. Si dnsmasq deja de responder a TODAS las consultas (se cuelga, no se cuelga), es vulnerable. Explotable ANTES de la validación RRSIG.
Comportamiento corregido: Avanza según p[1]+2 y omite mapas de bits de longitud cero.
Causa raíz: rdlen en RRSIG no se valida contra el tamaño mínimo (18 + nombre del firmante). La longitud de firma calculada se desborda negativamente → se trata como enorme → lectura OOB.
Método de prueba: Envía registros RRSIG con rdlen=10 (muy por debajo del mínimo de 31+ bytes). Caída = vulnerable.
Comportamiento corregido: Valida que rdlen >= campos_fijos + longitud_nombre_firmante antes de calcular la longitud de la firma.
Causa raíz: Los CLID DHCPv6 (hasta 65535 bytes) se codifican en hexadecimal mediante sprintf("%.2x") en daemon->packet (5131 bytes). CLID de 3000 bytes → cadena hexadecimal de 6000 bytes → desbordamiento. El proceso auxiliar se ejecuta como root.
Método de prueba: Envía SOLICIT DHCPv6 con un identificador de cliente de 3000 bytes. Requiere adyacencia IPv6 y --dhcp-script configurado. Caída del auxiliar = vulnerable.
Comportamiento corregido: Trunca o valida la longitud del CLID antes de la codificación hexadecimal.
Nota: Algunas compilaciones se compilan con -DNO_DHCP6 y NO se ven afectadas por esta CVE.
Causa raíz: process_reply() pasa la longitud del registro OPT (~23 bytes) en lugar de la longitud completa del paquete a check_source(). Todas las comprobaciones de límites fallan → la función siempre devuelve 1 (válido).
Método de prueba: Envía consultas DNS con la opción EDNS Client Subnet que contiene prefijos de origen falsificados. Si dnsmasq devuelve ECS sin validación, es vulnerable.
Comportamiento corregido: Pasa la longitud completa del paquete a check_source(), lo que permite comprobaciones de límites adecuadas según RFC 7871 Sección 9.2.
Actualice a dnsmasq 2.92rel2 (recomendado)
dnsmasq_cve_verify.py)La herramienta QA principal. Se ejecuta en la computadora de pruebas, envía paquetes de ataque al DUT, e informa PASS/FAIL claro para cada CVE. No se necesita modificación del DUT más allá del acceso SSH de solo lectura para la inspección del estado.
┌─────────────────────────────────────────────────────────────────────┐
│ Computadora de pruebas │
│ │
│ Interfaz LAN Interfaz WAN │
│ <IP_LAN_PORTATIL> <IP_WAN_PORTATIL> │
│ │ │ │
│ │ ┌────┴──────────────┐ │
│ │ │ Servidor DNS │ │
│ │ │ malicioso (puerto │ │
│ │ │ 53) │ │
│ │ └────┬──────────────┘ │
│ │ │ │
└────────┼───────────────────────────────┼────────────────────────────┘
│ Subred LAN │ Subred WAN
│ │
┌────────┼───────────────────────────────┼────────────────────────────┐
│ │ │ │
│ LAN: <IP_LAN_DUT> WAN: <IP_WAN_DUT> │
│ (puerta de enlace LAN) (enlace WAN) │
│ │
│ DUT (Router Linksys) │
│ dnsmasq (cualquier versión < 2.92rel2) │
│ │
│ resolv-file=/etc/resolv.conf │
│ → nameserver <IP_WAN_PORTATIL> ← establecido mediante GUI, nos reenvía │
│ │
└─────────────────────────────────────────────────────────────────────┘
Flujo de datos:
1. La herramienta envía una consulta DNS a la IP LAN del DUT (puerto 53)
2. El dnsmasq del DUT no puede resolver localmente → reenvía a IP_WAN_PORTATIL
3. Nuestro servidor malicioso en la interfaz WAN responde con el payload de exploit
4. El dnsmasq del DUT procesa la respuesta maliciosa → caída/cierre/supervivencia
5. La herramienta verifica el estado del DUT mediante SSH (solo lectura)
Ejemplo de configuración (sus IPs serán diferentes):
| Rol | IP (ejemplo) |
|---|---|
| LAN del portátil | 192.168.1.254 |
| WAN del portátil | 10.0.0.211 |
| LAN del DUT | 192.168.1.1 |
| WAN del DUT | 10.0.0.214 |
El requisito clave: La IP WAN del portátil y la IP WAN del DUT deben estar en la misma subred, para que el DUT pueda alcanzar el portátil como servidor DNS ascendente.
┌──────────┐ ┌───────────┐ ┌──────────────────┐ ┌──────────┐
│ CONFIG. │ ──► │ DISPARO │ ──► │ INSPECCIÓN DE │ ──► │ VEREDICTO│
│ │ │ │ │ ESTADO │ │ │
│ Iniciar │ │ Enviar │ │ SSH al DUT: │ │ PASS: │
│ servidor │ │ consulta │ │ - pidof dnsmasq │ │ sobrevivió│
│ DNS │ │ DNS al │ │ - ¿PID cambió? │ │ │
│ malicioso│ │ DUT→DUT │ │ - dmesg crash? │ │ FAIL: │
│ en WAN │ │ reenvía │ │ - /var/log/msg │ │ se colgó/ │
│ (10.0.0. │ │ a nosotros │ │ │ │ colgó │
│ 211:53) │ │ → resp. │ │ Consulta de │ │ │
│ │ │ con │ │ vitalidad │ │ │
│ │ │ payload │ │ (version.bind) │ │ │
│ │ │ exploit │ │ │ │ │
└──────────┘ └───────────┘ └──────────────────┘ └──────────┘
NOTA: La herramienta NO modifica la configuración del DUT. El usuario debe establecer el DNS en 10.0.0.211 mediante la GUI.
paramiko instalado (pip install paramiko)Conecte la computadora de pruebas al DUT con dos cables:
| Puerto del portátil | Se conecta a | Propósito |
|---|---|---|
| Puerto LAN | Puerto LAN del DUT | Acceso SSH + envío de consultas DNS al DUT |
| Puerto WAN | Subred WAN del DUT (ej., puerto del switch/módem ascendente) | Actuar como servidor DNS ascendente |
Después de la conexión, anote las IPs de su portátil:
# Encuentre sus IPs
ip addr show | grep "inet "
# Ejemplo de salida:
# inet 192.168.1.254/24 ... ← esta es su IP LAN
# inet 10.0.0.211/24 ... ← esta es su IP WAN (úsela para --laptop)
http://192.168.1.1 o http://miRouter.local10.0.0.211)cd /ruta/a/dnsmasq-cve-2026/
# Ejecutar las 6 pruebas CVE:
sudo python3 dnsmasq_cve_verify.py --laptop <SU_IP_WAN> --dut <IP_LAN_DUT> --dut-pass <CONTRASEÑA_SSH>
# Ejemplo:
sudo python3 dnsmasq_cve_verify.py --laptop 10.0.0.211 --dut 192.168.1.1 --dut-pass '12345Asdf@'
La herramienta hará lo siguiente:
Todos los routers Linksys probados no son explotables en la práctica para ninguna de las 6 CVE en sus configuraciones de compilación de producción. Las funciones peligrosas (DNSSEC, DHCPv6 vía dnsmasq) no están compiladas o no están configuradas. Aún así, se recomiendan los parches como defensa en profundidad.
Antes de la corrección (dnsmasq 2.78, compilación sin DNSSEC):
Antes de la corrección (dnsmasq 2.90 con DNSSEC habilitado):
Después de la corrección (dnsmasq 2.92rel2 o parches retroportados aplicados): Todas las 6 CVE → PASS
paramiko (pip install paramiko)test_dnsmasq_cve_remote.py)Solo verificación de versión ligera — consulta version.bind para determinar si la versión de dnsmasq
está por debajo de la corrección. Sin SSH, sin configuración, sin payloads de exploit.
python3 test_dnsmasq_cve_remote.py 192.168.1.1
test_dnsmasq_cve_on_device.sh)Se ejecuta directamente en el DUT mediante SSH/serie. Comprueba la versión binaria y las opciones de compilación.
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 exploit independiente para pruebas manuales. Ejecútelo, apunte el DNS ascendente del DUT hacia él,
luego active consultas a crash-5172.evil.test, crash-2291.evil.test, etc.
sudo python3 malicious_dns_server.py --port 53
# Luego en el DUT: configure ascendente → este host
# Luego active: dig @192.168.1.1 crash-5172.evil.test
Después de aplicar parches y actualizar el firmware, vuelva a ejecutar:
sudo python3 dnsmasq_cve_verify.py --laptop <SU_IP_WAN> --dut <IP_LAN_DUT> --dut-pass <CONTRASEÑA_SSH>
# Esperado: todas las 6 PASS
| Problema | Solución |
|---|
| "El DUT no nos reenvía consultas" | Verifique que el Paso 2 se realizó correctamente. Compruebe que la IP WAN del portátil coincide con la ingresada en la GUI. |
| "No se puede conectar al DUT" | Verifique las credenciales SSH. Intente manualmente: ssh [email protected]. |
| "No se puede vincular el puerto 53" | Ejecute con sudo. O use --dns-port 5353 (requiere configuración manual del DUT). |
| "Versión: desconocida" | Es posible que el DUT no tenga dnsmasq en la ruta estándar. La herramienta aún realiza las pruebas correctamente. |
| CVE | Resultado | Razón |
|---|
| CVE-2026-2291 | PASS | DNSSEC no compilado |
| CVE-2026-4890 | PASS | DNSSEC no compilado |
| CVE-2026-4891 | PASS | DNSSEC no compilado |
| CVE-2026-4892 | PASS | dnsmasq no sirve DHCPv6 (se usa un servidor DHCPv6 separado) |
| CVE-2026-4893 | PASS | Solo error lógico — sin caída |
| CVE-2026-5172 | PASS | Sobrevivió al exploit (ruta de código vulnerable no presente en 2.78) |
| CVE | Resultado | Razón |
|---|
| CVE-2026-2291 | PASS | DNSSEC no compilado |
| CVE-2026-4890 | PASS | DNSSEC no compilado |
| CVE-2026-4891 | PASS | DNSSEC no compilado |
| CVE-2026-4892 | PASS | DHCPv6 no compilado |
| CVE-2026-4893 | PASS | Solo error lógico — sin caída |
| CVE-2026-5172 | PASS | Sobrevivió a variantes de exploit |
| CVE | Resultado | Razón |
|---|
| CVE-2026-2291 | PASS | DNSSEC no compilado — no explotable |
| CVE-2026-4890 | PASS | DNSSEC no compilado — no explotable |
| CVE-2026-4891 | PASS | DNSSEC no compilado — no explotable |
| CVE-2026-4892 | PASS/FAIL | DHCPv6 compilado + dhcp-script activo |
| CVE-2026-4893 | PASS | Error lógico — sin caída (solo basado en versión) |
| CVE-2026-5172 | PASS | Ruta blockdata_expand no presente en 2.78 |
| CVE | Resultado | Razón |
|---|
| CVE-2026-2291 | FAIL | Desbordamiento de heap mediante nombres escapados |
| CVE-2026-4890 | FAIL | Bucle infinito (se cuelga) |
| CVE-2026-4891 | FAIL | Caída por lectura OOB en RRSIG |
| CVE-2026-4892 | PASS/FAIL | Depende de DHCPv6 + configuración de script |
| CVE-2026-4893 | PASS | Error lógico — sin caída |
| CVE-2026-5172 | FAIL | Lectura OOB mediante rdlen falsificado |
| Banderas | Predeterminado | Descripción |
|---|
--laptop | (obligatorio) | IP WAN del portátil (vincula el servidor DNS malicioso aquí) |
--dut | 192.168.1.1 | IP LAN del DUT (las consultas SSH y DNS se envían aquí) |
--dut-user | root | Usuario SSH del DUT |
--dut-pass | (solicitado) | Contraseña SSH del DUT |
--dns-port | 53 | Puerto para el servidor DNS malicioso |
--cve | las 6 | CVE(s) específicos a probar (repetible) |
| Herramienta | Python | Root | SSH | Red |
|---|
dnsmasq_cve_verify.py | 3.6+ paramiko | Sí (puerto 53) | Sí (solo lectura) | LAN + WAN al DUT |
test_dnsmasq_cve_remote.py | 3.6+ stdlib | No | No | UDP 53 al DUT |
test_dnsmasq_cve_on_device.sh | N/A (shell) | No | Se ejecuta en el DUT | N/A |
malicious_dns_server.py | 3.6+ stdlib | Sí (puerto 53) | No | DUT reenvía hacia nosotros |