查看原文
其他

CVE-2020-1350分析与复现

Saturn35 看雪学院 2021-03-06

本文为看雪论坛精华文章

看雪论坛作者ID:Saturn35





前言


CVE-2020-1350是微软在2020年7月修复的DNS协议相关漏洞,CVSS给出了高达10分的评分。漏洞发现的细节最初由CheckPoint进行纰漏,随后FSecureLabs的@maxpl0it研究员给出了相关POC脚本,我会在文末给出相关链接。

本文主要在肝完checkpoint的文章的基础上,通过[4][5]两篇文章的启发,使用POC进行漏洞分析和复现。

测试环境:Win Server2019+Win Server2016

本文原文地址:https://saturn35.com/2020/07/24/20200724-1/#more





漏洞原理


根据checkpoint的描述,以及对相关补丁的diff后,找到漏洞函数为:

dns.exe! SigWireRead


在IDA中查看其流程如下所示:

伪代码如下:

可以看到在申请内存函数RR_AllocateEX的参数中,第一参数v9+v13+20表示分配大小,其值由[Name_PacketNameToCountNameEx result]+ [0x14]
+ [signature’s length (rdi–rax)] 决定。

当此值结果在CX和DI寄存器中传递,而16位寄存器最大值为65535,当上数值结果大于65535时,将发生溢出,而真正申请到的数据是比要申请的大小小得多。

而后续我们可以看到存在memcpy拷贝函数,那么,可能存在由整数溢出的导致基于堆的缓冲区溢出。




DNS协议和数据包


格式如下:


Header表示DNS数据头,Question表示查询区,Answer表示应答区,后两个为认证区和附加区。

Header部分始终存在。大小为12字节,包含以下字段:

ID:同一查询和应答对应相同的16位ID;

QR:一位代表查询(0)或者应答(1);

TC:指定此消息由于长度大于传输通道上允许的长度而被截断。在DNS协议中,默认采用的传输层协议为用户数据报协议(UDP),但UDP传输的DNS数据包限制最大为512B,并不足以触发漏洞。

而此标志位是漏洞触发的关键,当其被设置为1是,在应答时,表示通知客户端,数据量比较大,让客户端用TCP重发一次查询请求,而基于TCP的DNS数据包大小可大于512字节。

查询区主要由域名、类型和类构成。

比较有趣的是域名的构成是分段式的len+str的形式:

eg:对于完整的一个域名,www.baidu.com,需要14个字节。



规定域名段的长度不能超过63个字节,所以表示域名段长度的字节最高两位没有用到,因此另有用途。

(1)当最高两位为00时,表示以上面的形式的传输

(2)当最高两位为11时,表示将域名进行压缩,该字节去掉最高两位后剩下的6位,以及后面的8位总共14位,指向DNS数据报文中的某一段域名,相当于一个指针。如0xc00c, 表示从DNS正文(UDP payload)的偏移offset=0x0c处所表示的域名。

(3)混合表示:以www.baidu.com为例,假设该域名位于DNS报文偏移0x20处,可能的用法有:

a、0xc020:表示完整域名www.baidu.com

b、0xc024:从完整域名的第二段开始,指代baidu.com

c、0x016dc024:0x01表示后面跟的size大小1,0x6d表示字符m,所以0x016d表示字符串"m",第二段0xc024指代baidu.com,因此整段表示m.baidu.com





SIG资源记录


在漏洞函数中,当读取SIG类型响应包才回进入触发流程,因此有必要了解下其结构。

在RFC2535官方文档中,对SIG资源记录的概括如下:

The SIG or "signature" resource record (RR) is the fundamental way that data is authenticated in the secure Domain Name 
System (DNS). As such it is the heart of the security provided.The SIG RR unforgably authenticates an RRset [RFC 2181] 
of a particular type, class, and name and binds it to a time interval and the signer's domain name.  This is done 
using cryptographic techniques and the signer's private key. The signer is frequently the owner of the zone from which 
the RR originated. The type number for the SIG RR type is 24.

其格式如下:

其中,signer's name表示生成SIG RR的签名者的域名。这是可用于验证签名的公钥RR的所有者名。通常是包含被认证的RRset的区域......可以使用标准的DNS名称压缩来压缩签名者的名称。




复现思路


在maxpl0it的POC中,思路是受害DNS服务器向evil服务器发送sig类型的域名查询时,通过启动UDP Server和TCP Server 监听当前设备IP 0.0.0.0和53端口,在程序中当收到指定类型和域名的DNS查询时,伪造DNS应答数据,设置TC位为1。通知受害者服务器重新用TCP发送查询。

但是,TCP传输DNS包大小限制为65535,还不足以触发。

那么,根据checkpoint的介绍,用到另一个技术,DNS域名压缩。

根据A warm welcome to DNS, powerdns.org:官方文档描述

“为了将尽可能多的信息压缩到512字节中,可以(通常必须)压缩DNS名称……在这种情况下,应答的DNS名称编码为0xc0 0x0c。c0部分设置了两个最高有效位,表示接下来的6 + 8位是指向消息中较早位置的指针。在这种情况下,它指向数据包中紧靠DNS标头的位置12(= 0x0c)。”

函数Name_PacketNameToCountNameEx根据Signer's Name 来获取域名的大小。0xc00c(偏移从Transaction ID 0x8380开始计算)指向域名9.ibrokethe.net,大小则为0x11。(1+1+1+9+1+3+1=17)

但通过设置Signer's Name 为0xc00d,将域名起始位置指向"9",此时会将"9"当作<size>,将后面的0x39个字节当作域名段,并且一直解析下去,直至解析到'\0'。

如下图,Name_PacketNameToCountNameEx会将图中选中的部分当成域名,获取大小。此时大小为(0x39+1)+(0xf+1)*5 +1 =0x8b。(0x39和0xf表示域名段大小,+1表示".", 最后一个+1表示"\0")。

Windbg中结果如下,可以看到计算结果为0x8b:

传入dns!Name_PacketNameToCountNameEx第一参数[rsp+30h]拿到了获取到的域名大小,rdi和rax分别表示signature的结束地址和起始地址,最后算出此段数据大小为0xffaa。


那么,最终上述公式的最终结果为0x8b+0x14+0xffaa & 0xffff = 0x49:

将此值作为第一参数,传入RR_AllocateEX函数,最终申请堆内存大小为0x49,而后续进行memcpy拷贝时,拷贝signature字段的数据,拷贝到刚刚申请的内存,大小为0xffaa,最终产生溢出,崩溃。

可以看到,我们伪造的DNS应答数据如下,当设置TC位为1时,则向受害服务器表面需要重新发送一次TCP查询,后续可以看到开始TCP握手,并进行应答。

最终进入整数溢出,访问失败,如下所示:

成功复现!

最后要说的是,复现过程采用了Windows DNS服务器的条件转发器,略过了向权威NS查询的步骤,直接向恶意DNS服务器发出查询。

踩坑:
1. VMware双虚拟机最好采用NAT,同时关闭防火墙。

2.关闭恶意DNS服务器所在主机的DNS服务,否则影响脚本中的监听服务器。

3. 方便理解,可将POC中拆分为两个脚本,避免多线程问题。




补丁更新


可以看到,在7月份的更新中,微软对传入内存申请的大小做了判断,V11+v9>V11,即防止了溢出,使得后续申请到正常大小的内存,可以看到修补的比较直接。





参考链接


[1] SIGRed – Resolving Your Way into Domain Admin: Exploiting a 17 Year-old Bug in Windows DNS Servers
https://research.checkpoint.com/2020/resolving-your-way-into-domain-admin-exploiting-a-17-year-old-bug-in-windows-dns-servers/

[2] CVE-2020-1350 (SIGRed) - Windows DNS DoS Exploit
https://github.com/maxpl0it/CVE-2020-1350-DoS

[3] CVE-2020-1350: Windows DNS Server蠕虫级远程代码执行漏洞分析
https://cert.360.cn/report/detail?id=5b7082dae4756f361d43a5efde233edd

[4] CVE-2020-1350漏洞深入剖析
https://bbs.pediy.com/thread-260712.htm

[5] RFC1035
https://tools.ietf.org/html/rfc1035



- End -


看雪ID:Saturn35

https://bbs.pediy.com/user-831334.htm

  *本文由看雪论坛 Saturn35 原创,转载请注明来自看雪社区。



推荐文章++++

* 不能说的秘密

* 某Nginx后门分析复现与改写

* 让C语言源码可知自身函数的实际地址与大小

* 一种通过后端编译优化脱混淆壳的方法

* Win10 1909逆向(反向计算Windows内核内存布局及代码实现)




公众号ID:ikanxue
官方微博:看雪安全
商务合作:wsc@kanxue.com



ps. 觉得对你有帮助的话,别忘点分享点赞在看,支持看雪哦~


“阅读原文”一起来充电吧!

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存