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
WEASEL — Implant de canal caché DNS pour les équipes rouges. | Kitploit
Outils/GitHubGitHub/facebookarchive/weasel
Outils de Chiffrement/DéchiffrementMécanismes de PersistancePost-ExploitationTests d'IntrusionCommandement et ContrôleRed TeamingDéveloppement de Charges UtilesAnalyse DNSArchived
GitHubfacebookarchive/weasel

WEASEL

Implant de canal caché DNS pour les équipes rouges.

73166il y a 6 ansVérifié par Kitploit

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
Voir le dépôt

WEASEL : Une balise DNS furtive

WEASEL est un petit implant en mémoire utilisant Python 3 sans dépendances. Le client de la balise envoie une petite quantité d'informations d'identification de son hôte vers une zone DNS que vous contrôlez. Le serveur WEASEL peut ordonner aux clients d'exécuter des commandes pré-définies ou arbitraires.

WEASEL est une charge utile de stade 1, conçue pour être difficile à détecter et utile pour retrouver un accès lorsque vos étapes complètes et bruyantes sont détectées.

Statut

  • A été utilisé avec succès lors d'une opération et a échappé aux détections.
  • Le client peut initialiser une session avec le serveur et établir une communication bidirectionnelle.
  • Le serveur dispose d'une CLI entièrement fonctionnelle.
  • Le client prend en charge un certain nombre de fonctions que le serveur peut ordonner.
  • Le client fait 5,2 Ko une fois minifié + obfusqué.
  • L'obfuscation automatique est insuffisante et nécessite des corrections manuelles (voir Limitations dans le README du client).
  • Le serveur ne prend pas en charge le multi-joueur (plusieurs opérateurs simultanés).

Exemples

Voir l'utilisation dans le README du client et le README du serveur pour des instructions spécifiques.

Pour démarrer le serveur ou le client, exécutez les scripts directement ou passez-les à l'interpréteur Python.

Assurez-vous que chaque domaine C2 possède un enregistrement NS pointant vers l'adresse IP de l'hôte exécutant server.py.

Prérequis

WEASEL nécessite Python 3.6+.

Le client est autonome et n'utilise que des bibliothèques standard, il peut donc être exécuté sur macOS, Linux, etc.

Le serveur a quelques dépendances pip, incluses dans requirements.txt du serveur. Le serveur doit être exécuté sur Linux, mais rien n'empêche de le faire fonctionner sur macOS ou d'autres *nix.

Test / Exécution en développement

Pas besoin d'obfusquer et de minimiser la balise dans ce cas. Les instructions print sont conservées. Comme pour l'utilisation ci-dessus, assurez-vous que les enregistrements NS pour le(s) domaine(s) dans servers de beacon.py pointent vers l'adresse IP de server.py.

Sur l'hôte serveur :

sudo python3 server.py

Sur l'hôte victime (peut être le même que le serveur) :

python3 beacon.py

Architecture

Vous n'avez pas besoin de comprendre tout cela pour utiliser WEASEL.

La balise communique via DNS en utilisant des requêtes et réponses AAAA. Elle n'utilise pas d'enregistrements TXT car ceux-ci sont connus pour être utilisés par les malwares et tunnels DNS. Les équipes bleues ont souvent des détections de tunneling DNS qui alertent sur les grandes requêtes TXT.

Le côté client n'a pas besoin de root pour fonctionner, n'utilise pas de sockets bruts et ne crée pas de paquets DNS malformés. Il utilise des interfaces système et linguistiques standard pour effectuer des requêtes DNS. Les informations sont encodées + chiffrées dans les enregistrements eux-mêmes.

  • Un seul enregistrement A (adresse IPv4) peut contenir 4 octets d'information.
  • Un seul enregistrement AAAA (adresse IPv6) peut contenir 16 octets d'information.
  • Les enregistrements CNAME et les noms d'hôte utilisés dans les requêtes peuvent contenir jusqu'à 64 octets par sous-domaine et ne doivent pas dépasser 255 octets au total selon la RFC. Cependant, les directives de détection DNS de SANS indiquent que les sous-domaines de plus de 52 caractères sont suspects. Pour cette raison, nous limitons les sous-domaines à 52 caractères (configurable dans le code) et nous essayons d'utiliser le moins de sous-domaines et de requêtes possible.
  • Une réponse peut contenir plusieurs enregistrements, jusqu'à la limite de taille d'un datagramme UDP (65 507 octets).

Cette balise est conçue pour être lente et discrète, avec peu de bande passante. Elle doit nous indiquer sur quels hôtes elle se trouve et nous donner un moyen de lancer d'autres étapes si nécessaire, et rien de plus. Bien qu'elle prenne en charge les commandes arbitraires, elle n'est pas destinée à être utilisée comme un shell interactif régulier ou un canal de communication.

WEASEL est un stade 1 que vous laissez tourner, garantissant un accès continu pendant que vos étapes complètes (et donc plus bruyantes) sont détectées.

Persistance

WEASEL était initialement ciblé pour des serveurs à haute disponibilité où nous avions un point d'appui/vecteur d'exploitation fiable. Éviter les analyses forensiques était une priorité élevée. En conséquence, il n'a pas de fonctionnalités de persistance natives.

Vous pouvez le rendre persistant en ajoutant son exécution à votre technique de persistance préférée, ce qui est laissé comme exercice au lecteur :)

Protocole et format des messages

Requête client

Une requête (du client) est une simple requête AAAA pour un nom formaté comme suit :

<préambule><données>.<flux>.<session>.domaine.tld

Le préambule fait 2 octets. Préambule[0] est le numéro de séquence de ce paquet. Préambule[1] est le nombre total de paquets dans ce flux.

Les données sont limitées à 50 octets (configurable) et contiennent la charge utile. La charge utile est encodée en base32 avec un alphabet personnalisé.

Encodage de la charge utile

Tout d'abord, tous les caractères 'w' sont remplacés par '-'.

Ensuite, le caractère de remplissage est remplacé de '=' à 'w' pour se conformer au jeu de caractères DNS : [a-z0-9] et [-].

Nous ne remplaçons pas '=' par '-' directement car le remplissage sera toujours à la fin de la chaîne, et terminer un nom d'hôte par '---' est à la fois suspect et contraire à la RFC DNS. De cette façon, lorsqu'une chaîne a un remplissage, elle se termine par 'www', ce qui est à la fois moins suspect et conforme à la RFC.

Réponse du serveur

Une réponse (du serveur) est composée d'une ou plusieurs réponses AAAA.

Chaque réponse AAAA est une charge utile chiffrée de 16 octets représentée comme une adresse IPv6 en utilisant socket.inet_ntop. Les réponses dans une réponse DNS ne conservent pas leur ordre en transit, elles sont donc séquencées et réassemblées comme les requêtes client.

La charge utile de transport est une chaîne d'éléments de données séparés par un caractère ^.

Format de transport

Les requêtes et réponses suivent ce format :

<type>|<données>

Sessions

Les sessions sont de longue durée : un client initie une session lorsque la balise est exécutée pour la première fois et cette session doit durer tout le temps que la balise est active sur ce client. Notez que comme la balise est en mémoire et non persistante, les données de session sont stockées dans la mémoire de ce processus Python. Toute nouvelle invocation de la balise initiera une nouvelle session.

L'initiation d'une session implique que le client crée un message avec un préambule non-données unique (pour signaler au serveur qu'il s'agit d'une nouvelle session) : la concaténation d'une clé publique Diffie-Hellman de 32 octets et d'un IV AES aléatoire de 16 octets.

Le serveur reçoit ceci et répond avec sa propre clé publique de 32 octets. À ce stade, le client et le serveur ont établi une clé de session partagée qui sera utilisée pour la durée de cette session pour chiffrer les charges utiles de données en utilisant AES-128 en mode CTR. L'échange Diffie-Hellman éphémère garantit que chaque connexion client-serveur utilise une clé de session unique avec une confidentialité persistante.

Faiblesse du chiffrement

Le chiffrement est volontairement mauvais pour plusieurs raisons :

  • Nous imitons les attaquants réels qui n'ont généralement aucune idée de la façon de construire des systèmes de chiffrement robustes et aiment créer les leurs
  • La bande passante de la balise est aussi faible que possible, ce qui signifie que notre échange DHE doit être maintenu très petit
  • La non-attribution est importante, nous n'authentifions pas le serveur
  • C'est moins amusant pour les intervenants si nous utilisons un chiffrement de pointe qu'ils ne peuvent pas espérer casser

Voici quelques problèmes connus du schéma de chiffrement :

  1. Le module Diffie-Hellman p est le groupe 5 de la RFC 3526 tronqué aux 32 premiers octets. Cela limite non seulement les clés publiques et privées à 32 octets, mais le groupe 5 est déjà déprécié et déconseillé. J'appelle cette mauvaise décision "Groupe 1".
  2. Nous utilisons random.randint() pour l'exposant a au lieu d'un CSPRNG.
  3. Nous utilisons une petite quantité de données provenant de os.urandom() pour la génération d'ID de session et d'ID de flux au lieu d'un UUID, ce qui signifie que les collisions sont probables. Nous en tenons compte en réessayant jusqu'à obtenir un ID qui n'est pas utilisé.
  4. Le chiffrement AES-CTR est réinitialisé avec le même IV (qui est de longue durée comme la clé de session) pour chaque flux. Cela signifie que le même texte clair dans la même position à travers les flux produira le même texte chiffré.
  5. En AES-CTR, l'IV est correctement appelé nonce, mais dans notre implémentation, nous n'utilisons pas le numéro une seule fois, il serait donc un peu impoli de l'appeler ainsi.

Flux

Chaque message envoyé entre un client et un serveur doit être encapsulé en paquets de 50 octets maximum, afin de rester en dessous de cette limite de 52 octets pour les détections courantes de canaux cachés DNS. Tous les paquets d'un message particulier font partie du même flux. Message == Flux.

Les flux sont identifiés par un nombre hexadécimal aléatoire de 2 octets. Rappelez-vous que le format de requête client est : <préambule><données>.<flux>.<session>.domaine.tld

Le préambule de 2 octets de chaque paquet du flux contient un numéro de séquence et le nombre total de paquets de ce flux. Cela permet au serveur de savoir quand tout est arrivé.

Parce que nous faisons cela via DNS sur UDP, qui ne fournit aucune garantie sur l'ordre d'arrivée des datagrammes. C'est pourquoi WEASEL doit prendre en compte le séquençage, le réassemblage et le suivi de plusieurs flux provenant de nombreuses balises.

Chaque flux réinitialise un chiffrement AES-128-CTR globalement partagé pour chiffrer/déchiffrer les charges utiles.

La charge utile ne peut être déchiffrée qu'une fois le flux terminé (tous les paquets sont arrivés). Si ce n'était pas pour le base32, nous pourrions déchiffrer ce que nous avons du message même si nous manquions des paquets (car AES-CTR est un chiffrement de flux) mais nous ne pouvons pas décoder partiellement des flux base32. Tant pis. Par la nature des clients DNS, les requêtes sont faites plusieurs fois (généralement 2 ou 4 fois) jusqu'à ce qu'une réponse soit reçue, donc nous avons une bonne probabilité de recevoir tous les paquets d'un flux car chaque paquet devrait être envoyé par le client au moins deux fois. Si nous perdons des paquets ou des flux, ce n'est pas grave, la balise se reconnectera plus tard et aura probablement plus de chance à ce moment-là.

Rejoignez la communauté WEASEL

Consultez le fichier CONTRIBUTING pour savoir comment aider.

Licence

WEASEL est sous licence MIT, comme indiqué dans le fichier LICENSE.

Télécharger l’outil
TypeSignification (expéditeur)Aussi appeléDonnées
0Accusé de réceptionACKHexadécimal aléatoire
1Enregistrement (client)PINGHexadécimal aléatoire
2Terminez-vous (serveur), je me termine (client)FIN
3Message d'initialisation (client)SYN`version
4Reconnexion (serveur)RST
5Définir l'intervalle de rappel (serveur)secondes
6Obtenir les données d'interface réseaueth0 1.2.3.4/24\neth1 fe80:::/64\n...
8Évaluer du code Python3 arbitraire jusqu'à 666 octets (serveur), retourner les 400 premiers octets de la sortie (client)EVALscript One-liner Python3
9Exécuter une commande arbitraire jusqu'à 666 octets (serveur), retourner les 400 premiers octets de la sortie (client)EXECcommande bash