来源:https://activecm.github.io/threat-hunting-labs/dns/
一、目标
利用频率分析识别使用DNS进行 C2的系统。
二、工具使用
dig
Zeek
Tshark
Wireshark
RITA
三、背景
许多指挥和控制(C2)通道直接与攻击者控制的系统通信。这使得它更容易被检测和跟踪。基于DNS的C2不同,因为通信使用DNS基础设施进行通信。
通常DNS对google.com的请求是这样的:
缓存DNS查询
所有正在发生的事情可能还不清楚,但首先要注意两件事。
客户端(您的计算机)只与它配置的递归名称服务器(NS)通信。当您的计算机通过DHCP连接到网络时,通常将此名称服务器提供给它。当然你也可以手动设置DNS服务器。例如,您可以选择使用Cloudflare(1.1.1.1)或谷歌(8.8.8.8)等大公司提供的服务器之一。
在幕后,递归NS为你做了很多工作。如果每次都这样做,所有这些请求将很快淹没服务器,所以上面的事件序列只会在递归NS不知道答案的情况下发生。一旦它完成了这项工作,它就会把答案缓存一段时间。因此,下次您或任何其他客户端进行相同的DNS查询时,NS将从其本地缓存回答,而不是查询其他名称服务器。
缓存DNS查询
在考虑将DNS作为C2通道时,这两点都非常重要。
首先,递归NS有效地在客户端和远程名称服务器之间代理通信。由于DNS对于正常的网络操作非常重要,大多数网络都会隐式地信任任何用DHCP配置的递归NS。攻击者利用这种信任在受限网络之外进行通信。
其次,由于名称服务器将缓存后续请求的结果,攻击者需要防止缓存,以便让NS与C2服务器通信。如果最近响应了相同的请求,名称服务器将使用它的缓存。为了解决这个问题,攻击者确保他们不会发出相同的请求。实际上,这意味着攻击者发出的请求越多,他们需要使用的子域就越多。防御者可以使用此行为检测DNS上的C2流量。
四、练习:遵循DNS查询的顺序
让我们浏览一下上面的序列图,并理解正在发生的每个步骤。我们将使用dig命令来模拟幕后发生的事情。
注意:当您运行这些相同的命令时,您可能会收到不同的IP地址。这是因为像谷歌这样的大型网站将在许多不同的服务器上托管他们的内容。他们使用DNS结果来指导您到最近的地理服务器和负载平衡,以便没有一个服务器超载。
1、客户端向递归名称服务器请求google.com的一条A记录。
我们将大量使用dig的+norecurse选项,以防止名称服务器通常为您发出的后台请求。
你选择的域名服务器很可能已经缓存了google.com的答案。在找到一个未缓存的域之前,您可能需要尝试几个不同的域。下面是一个使用do-not-respond.org的例子。
dig do-not-respond.org A +norecurse
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 51547
;; flags: qr ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1452
;; QUESTION SECTION:
;do-not-respond.org. IN A
您可以看到没有提供答案,标题显示答案:0。
在不使用+norecurse标志的情况下再次尝试查询。
dig do-not-respond.org A
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 43574
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1452
;; QUESTION SECTION:
;do-not-respond.org. IN A
;; ANSWER SECTION:
do-not-respond.org. 7200 IN A 99.81.40.78
这一次提供了一个答案,因为本地解析器为您进行了递归调用。如果我们用+norecurse标志再次尝试第一个命令,我们会看到答案现在被缓存了。
dig do-not-respond.org A +norecurse
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 14157
;; flags: qr ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1452
;; QUESTION SECTION:
;do-not-respond.org. IN A
;; ANSWER SECTION:
do-not-respond.org. 7198 IN A 99.81.40.78
让我们从递归名称服务器的角度研究如果结果不在缓存中会发生什么。
1、递归名称服务器向根名称服务器请求com NS记录。
DNS基础结构建立在树形层次结构中,顶部有13个根名称服务器。根名称服务器的IP地址是众所周知的,很少改变。递归名称服务器将已经拥有这些信息,以便它知道将下一个请求发送到何处。
根名称服务器将查询它的区域文件并返回com顶级域(TLD)的NS记录。区域文件可以在这里找到:https://www.internic.net/zones/root.zone
它包含每个顶级域名(例如com、net、org、shop、fitness等)的NS记录,以及每个NS记录的A & AAAA记录。这是为了让递归解析器知道要查询的下一个名称服务器的IP地址。下载根区域文件,看看是否可以找到下面显示的com名称服务器的条目。
@198.41.0.4告诉dig使用该IP地址作为要查询的域名服务器,它是根名称服务器之一。我们向名称服务器询问ns record for com。
dig @198.41.0.4 com NS +norecurse
;; QUESTION SECTION:
;com. IN NS
;; AUTHORITY SECTION:
com. 172800 IN NS e.gtld-servers.net.
com. 172800 IN NS b.gtld-servers.net.
com. 172800 IN NS j.gtld-servers.net.
com. 172800 IN NS m.gtld-servers.net.
com. 172800 IN NS i.gtld-servers.net.
com. 172800 IN NS f.gtld-servers.net.
com. 172800 IN NS a.gtld-servers.net.
com. 172800 IN NS g.gtld-servers.net.
com. 172800 IN NS h.gtld-servers.net.
com. 172800 IN NS l.gtld-servers.net.
com. 172800 IN NS k.gtld-servers.net.
com. 172800 IN NS c.gtld-servers.net.
com. 172800 IN NS d.gtld-servers.net.
;; ADDITIONAL SECTION:
e.gtld-servers.net. 172800 IN A 192.12.94.30
e.gtld-servers.net. 172800 IN AAAA 2001:502:1ca1::30
b.gtld-servers.net. 172800 IN A 192.33.14.30
b.gtld-servers.net. 172800 IN AAAA 2001:503:231d::2:30
j.gtld-servers.net. 172800 IN A 192.48.79.30
j.gtld-servers.net. 172800 IN AAAA 2001:502:7094::30
m.gtld-servers.net. 172800 IN A 192.55.83.30
m.gtld-servers.net. 172800 IN AAAA 2001:501:b1f9::30
i.gtld-servers.net. 172800 IN A 192.43.172.30
i.gtld-servers.net. 172800 IN AAAA 2001:503:39c1::30
f.gtld-servers.net. 172800 IN A 192.35.51.30
f.gtld-servers.net. 172800 IN AAAA 2001:503:d414::30
a.gtld-servers.net. 172800 IN A 192.5.6.30
a.gtld-servers.net. 172800 IN AAAA 2001:503:a83e::2:30
g.gtld-servers.net. 172800 IN A 192.42.93.30
g.gtld-servers.net. 172800 IN AAAA 2001:503:eea3::30
h.gtld-servers.net. 172800 IN A 192.54.112.30
h.gtld-servers.net. 172800 IN AAAA 2001:502:8cc::30
l.gtld-servers.net. 172800 IN A 192.41.162.30
l.gtld-servers.net. 172800 IN AAAA 2001:500:d937::30
k.gtld-servers.net. 172800 IN A 192.52.178.30
k.gtld-servers.net. 172800 IN AAAA 2001:503:d2d::30
c.gtld-servers.net. 172800 IN A 192.26.92.30
c.gtld-servers.net. 172800 IN AAAA 2001:503:83eb::30
d.gtld-servers.net. 172800 IN A 192.31.80.30
d.gtld-servers.net. 172800 IN AAAA 2001:500:856e::30
1、递归名称服务器向com的权威名称服务器询问google.com的NS记录。
接下来,我们将获取返回的com NS记录之一的IP, a.gtld-servers.net: 192.5.6.30,并询问google.com使用哪个名称服务器。
dig @192.5.6.30 google.com NS +norecurse
;; QUESTION SECTION:
;google.com. IN NS
;; AUTHORITY SECTION:
google.com. 172800 IN NS ns2.google.com.
google.com. 172800 IN NS ns1.google.com.
google.com. 172800 IN NS ns3.google.com.
google.com. 172800 IN NS ns4.google.com.
;; ADDITIONAL SECTION:
ns2.google.com. 172800 IN AAAA 2001:4860:4802:34::a
ns2.google.com. 172800 IN A 216.239.34.10
ns1.google.com. 172800 IN AAAA 2001:4860:4802:32::a
ns1.google.com. 172800 IN A 216.239.32.10
ns3.google.com. 172800 IN AAAA 2001:4860:4802:36::a
ns3.google.com. 172800 IN A 216.239.36.10
ns4.google.com. 172800 IN AAAA 2001:4860:4802:38::a
ns4.google.com. 172800 IN A 216.239.38.10
1、递归名称服务器向google.com的域名服务器询问google.com的A记录。
最后,我们可以使用返回的名称服务器询问google.com的IP地址。
dig @216.239.32.10 google.com A +norecurse
;; QUESTION SECTION:
;google.com. IN A
;; ANSWER SECTION:
google.com. 300 IN A 172.217.1.46
然后你可以把172.217.1.46放到你的浏览器里,谷歌的主页就会被加载。
五、狩猎
我们将利用这一事实,即通过使用唯一的子域名,C2通过DNS击败名称服务器缓存。
六、Zeek
6.1 子域频率分析
在开始之前,一定要使用Zeek分析pcap。
您的Zeek日志应该包含一个名为dns-log的文件。您可以使用head命令检查该文件中的内容。
head dns.log
#separator \x09
#set_separator ,
#empty_field (empty)
#unset_field -
#path dns
#open 2019-10-16-15-13-09
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto trans_id rtt query qclass qclass_name qtype qtype_name rcode rcode_name AA TC RD RA Z answers TTLs rejected
#types time string addr port addr port enum count interval string count string count string count string bool bool bool bool count vector[string] vector[interval] bool
1517336042.279652 ComPBK1vso3uDC8KS2 192.168.88.2 55638 165.227.88.15 53 udp 42937 0.069982 6dde0175375169c68f.dnsc.r-1x.com 1 C_INTERNET 16 TXT 0NOERROR F F T T 0 TXT 18 302f017537c68f5169 60.000000 F
1517336043.354471 CyZ4x32ytwoKUgqozf 192.168.88.2 28736 165.227.88.15 53 udp 16556 0.078779 0b320175375169c68f.dnsc.r-1x.com 1 C_INTERNET 16 TXT 0NOERROR F F T T 0 TXT 18 c27a017537c68f5169 60.000000 F
这本身不是很好读。在一行中显示太多的列。让我们用zeek-cut把列简化成我们想看的。
head dns.log | zeek-cut -c id.orig_h query qtype_name answers
#separator \x09
#set_separator ,
#empty_field (empty)
#unset_field -
#path dns
#open 2019-10-16-15-13-09
#fields id.orig_h query qtype_name answers
#types addr string string vector[string]
192.168.88.2 6dde0175375169c68f.dnsc.r-1x.com TXT TXT 18 302f017537c68f5169
192.168.88.2 0b320175375169c68f.dnsc.r-1x.com TXT TXT 18 c27a017537c68f5169
这样更好了,但是到目前为止我们只处理文件的前几行。使用cat而不是head将显示整个文件滚动。
cat dns.log | zeek-cut -c id.orig_h query qtype_name answers
...
192.168.88.2 5fd2011239458783cf.dnsc.r-1x.com TXT TXT 18 054101123983cf4587
10.55.200.10 a849.dscg2.akamai.net A -
10.55.200.10 target-opus.map.fastly.net A -
10.55.200.10 accdn.lpsnmedia.net A -
10.55.200.10 dc.ads.linkedin.com A -
10.55.200.10 us-scproxy.alibaba.com.gds.alibabadns.com A -
10.55.200.10 va.v.liveperson.net A -
192.168.88.2 36a80176d2f1ce66e2.dnsc.r-1x.com TXT TXT 18 77210176d266e2f1ce
10.55.200.10 www.target.com.edgekey.net A -
10.55.200.10 e10583.dspg.akamaiedge.net A -
192.168.88.2 66b00176d2f1ce66e2.dnsc.r-1x.com TXT TXT 18 f95e0176d266e2f1ce
192.168.88.2 7d0e0176d2f1ce66e2.dnsc.r-1x.com TXT TXT 18 7cb50176d266e2f1ce
10.55.200.10 lptag.liveperson.cotcdb.net.livepersonk.akadns.net A -
192.168.88.2 3573011239458783cf.dnsc.r-1x.com TXT TXT 18 983c01123983cf4587
仅仅浏览一下滚动的数据,您可能会注意到一些您想要调查的奇怪的查询。首先,让我们看看能否更好地总结我们的数据。下面的命令计算每个基本域的惟一子域的数量。
cat dns.log | zeek-cut query | sort | uniq | rev | cut -d '.' -f 1-2 | rev | sort | uniq -c | sort -nr | head
62468 r-1x.com
154 akamaiedge.net
125 akadns.net
121 edgekey.net
101 amazonaws.com
67 microsoft.com
51 dynect.net
45 parsely.com
44 akam.net
43 cloudfront.net
下面是上述命令的一个分解:
cat dns-log | zeek-cut查询——忽略除了查询字段以外的所有内容,查询字段告诉我们被请求的域是什么。
sort | uniq -删除所有重复的查询。
rev——获取每个查询并反转字符串,这样www.google.com就变成了moc.elgoog.www。这样做的原因是将查询剥离到顶级域(TLD),比如。com或。net,以及域的下一部分。
cut -d '-' -f 1-2 - 在每个句点上分割完整查询,并保留第一个和第二个元素(e。g moc.elgoog。www - > moc.elgoog)。
rev -反向字符串再次把它恢复正常。
sort | uniq -c-删除和计数重复。
sort -nr | head-输出重复最多的条目。
建议您尝试一下这个命令的形式,以便更好地理解它,并看看还可以从数据中得到什么。例如,您可以从末尾删除每个命令,然后看看会发生什么。或者你可以改变cut -d '.' -f 1-2命令中的数字2。看看你是否能在更深的层次上理解每个步骤的目的。
让我们想想我们刚刚做了什么,以及它如何应用于威胁狩猎。我们删除了所有重复的DNS查询,这意味着处理的每个查询都是针对一个唯一的域。接下来,我们将每个长域名简化为它的基域名。然后我们计算每个基本域的重复条目。最后,我们所做的是计算每个基本域的子域数量,并显示子域数量最多的域。
在考虑了我们在背景部分所学到的内容之后,很明显r-1x.com领域中发生了一些可疑的事情。我们的下一步可能是:
1、看看这个领域的一些查询示例
cat dns.log | zeek-cut id.orig_h query answers | grep 'r-1x\.com'
...
192.168.88.2 6dde0175375169c68f.dnsc.r-1x.com TXT 18 302f017537c68f5169
192.168.88.2 0b320175375169c68f.dnsc.r-1x.com TXT 18 c27a017537c68f5169
192.168.88.2 344b0175375169c68f.dnsc.r-1x.com TXT 18 67f2017537c68f5169
192.168.88.2 0f370175375169c68f.dnsc.r-1x.com TXT 18 8759017537c68f5169
192.168.88.2 251e0175375169c68f.dnsc.r-1x.com TXT 18 cf5d017537c68f5169
192.168.88.2 31610175375169c68f.dnsc.r-1x.com TXT 18 4a42017537c68f5169
192.168.88.2 1a600175375169c68f.dnsc.r-1x.com TXT 18 50fa017537c68f5169
192.168.88.2 69a60175375169c68f.dnsc.r-1x.com TXT 18 a7be017537c68f5169
192.168.88.2 06540175375169c68f.dnsc.r-1x.com TXT 18 6d55017537c68f5169
192.168.88.2 4bff0175375169c68f.dnsc.r-1x.com TXT 18 414c017537c68f5169
现在,这些查询看起来不像我们习惯的查询。大多数查询都有一个奇怪的十六进制字符串,后面跟着.dnsc.r-1x.com。这些查询大部分(如果不是全部的话)是TXT类型的,而响应也大部分是固定长度的十六进制字符串。查看更多的结果,看看是否可以发现其他类型的查询和答案,并确定任何模式。
1、查找执行此域查询的所有IP地址
cat dns.log | zeek-cut id.orig_h query | grep 'r-1x\.com' | cut -f 1 | sort | uniq -c
109227 192.168.88.2
幸运的是,对已识别的可疑域名的所有查询都来自一个IP: 192.168.88.2。不那么幸运的是,这个IP地址恰好是我们网络的本地DNS代理,这意味着所有的查询实际上都来自其他IP,而要找出哪些IP,我们必须查阅我们的DNS服务器的日志。注意这一点很重要,因为网络捕获点可以影响您在追捕威胁时拥有的信息量。
我们可以从Zeek日志中收集到更多的数据。这个命令将取出所有包含IP地址的答案。在本例中,只有一个:165.227.88.15。
cat dns.log | zeek-cut query answers | grep 'r-1x\.com' | cut -f 2 | cut -d ' ' -f 3 | egrep '([0-9]{0,3}\.)[0-9]{0,3}' | sort | uniq
165.227.88.15
然后我们可以使用这个IP查看是否有任何内部系统直接连接到这个服务器。
cat conn.log | zeek-cut id.orig_h id.resp_h id.resp_p proto service | grep '165.227.88.15' | sort | uniq -c
2 165.227.88.15 192.168.88.2 3 icmp -
2 192.168.88.2 165.227.88.15 53 tcp -
108856 192.168.88.2 165.227.88.15 53 udp dns
在这里,我们可以看到有三种独特的连接类型涉及可疑IP:
165.227.88.15响应icmp消息的2个连接
192.168.88.2连接到tcp/53的2个连接
有108,856个连接,其中192.168.88.2连接到udp/53
下一步最好的做法是查阅我们的DNS服务器的日志,如果可用,找出我们的哪些内部主机可能被破坏。
6.2查询类型分析
DNS C2通道的另一个告警信号是某个查询类型的异常多。我们预计正常的DNS流量主要是A / AAAA和CNAME类型,其余的相对少见。
下面的示例取自一个没有基于DNS的C2的数据集。
224390 A
8711 AAAA
446 PTR
271 DS
121 DNSKEY
65 TXT
10 SRV
10 SOA
6 -
2 NS
其他类型的记录在某些场景中可能更普遍。知道是否期望某种类型的请求是很重要的,这样您就可以确定它们是否被C2滥用了。
当邮件服务器、web服务器或网络监控站查找与连接IP地址相关联的主机名时,PTR查找也很常见。
当实现或验证DNSSEC时,使用DNSKEY和DS记录。
TXT记录主要用于域名所有权验证或打击垃圾邮件。
下面介绍如何为相关示例生成类似的输出。这是每种查询类型的唯一查询的数量。
cat dns.log | zeek-cut qtype_name | sort | uniq -c | sort -nr
199818 A
108911 TXT
6751 AAAA
91 SRV
46 SOA
8 DNSKEY
7 DS
2 NS
请注意异常大量的TXT查询。这些类型的查询允许攻击者使用比A记录更高的带宽,因为每个回复可以包含更多的字符。
支持几种DNS请求类型,其中NULL和PRIVATE类型有望提供最大的下游带宽。其他可用的类型是TXT、SRV、MX、CNAME和A(返回CNAME),按带宽递减顺序排列。
一种流行的开源恶意软件dnscat2默认使用TXT, CNAME, & MX类型查询,尽管这取决于客户端实现。
七、Tshark
您还可以使用tshark直接从pcap提取DNS查询。下面的命令将计算每个基本域的唯一子域的数量。
tshark -r sample.pcap -T fields -e dns.qry.name udp.dstport==53 | sort | uniq | rev | cut -d '.' -f 1-2 | rev | sort | uniq -c | sort -nr | head -10
62468 r-1x.com
154 akamaiedge.net
125 akadns.net
121 edgekey.net
104 amazonaws.com
67 microsoft.com
51 dynect.net
45 parsely.com
44 akam.net
43 cloudfront.net
有关整个命令的解释,请参阅上面的Zeek部分。关于tshark的争论在此进行解释:
-r sample.pcap -到pcap文件的路径。
-T fields-告诉tshark输出指定字段的值。
-e dns.qry.name -从每个DNS包打印的字段。该语法与Wireshark中使用的语法相同。您可以在wireshark的文档中找到其他与dn相关的字段列表。
udp.dstport==53 -要使用的过滤器。这使用了Wireshark的显示过滤器语法。在这种情况下,我们告诉tshark只处理发送到UDP端口53的数据包。
八、Wireshark
打开你的pcap在Wireshark。这将加载主窗口中的每个数据包。
在“统计”菜单下选择DNS。DNS窗口分析并显示pcap中所有DNS查询的指标。我们将使用此窗口查看查询类型分析。
通过单击Count列进行排序。然后再次单击以按降序排序。
查询类型按类型显示查询的数量。但是,这不会删除重复查询。
九、RITA
RITA使用Zeek日志,应该会得到与我们前面直接查看日志文件相同的结果。如果还没有,请按照基本工具使用文档中的描述导入日志文件。
本例中的数据集名称为“sample”。
rita show-exploded-dns -H --limit 10 sample
+-------------------+-------------------+-----------------+
| DOMAIN | UNIQUE SUBDOMAINS | TIMES LOOKED UP |
+-------------------+-------------------+-----------------+
| r-1x.com | 62468 | 109227 |
| dnsc.r-1x.com | 62466 | 108911 |
| akamaiedge.net | 154 | 27381 |
| akadns.net | 125 | 13907 |
| edgekey.net | 121 | 7110 |
| amazonaws.com | 101 | 13297 |
| elb.amazonaws.com | 90 | 13259 |
| com.edgekey.net | 88 | 6075 |
| microsoft.com | 67 | 1687 |
| com.akadns.net | 59 | 8405 |
+-------------------+-------------------+-----------------+
上面的命令几乎等同于处理上面的Zeek日志来计算每个基本域的子域数。然而,RITA计算每个域的子域的数量,而不仅仅是基本域。你可以从上面看到dnsc.r-1x.com和elb.amazonws.com的结果。