首页 >> 网络安全 >>漏洞分析 >> Windows DNS Server远程代码执行漏洞分析(CVE-2020-1350)
详细内容

Windows DNS Server远程代码执行漏洞分析(CVE-2020-1350)

时间:2020-08-14     作者:深信服威胁情报【转载】   阅读

 背景介绍

Microsoft Windows Server操作系统自带了一个DNS server,Windows自Windows 2000后提供了一些DNS API给应用程序开发者,允许他们通过这些API使用一些DNS方法(例如创建DNS查询,比较记录,查找name等)。

一种最简单的用户和DNS Server的交互过程如下图所示:

DNS查询和响应均通过DNS消息进行传输,消息的结构如下所示:

	+---------------------+
	|       Header    |
	+---------------------+
	|  Question / Zone |  the question / zone for the name server
	+---------------------+
	|  Answer / Prereq |  RRs answering the question / prereq
	+---------------------+
	| Authority / Updates |  RRs pointing toward an authority / updates
	+---------------------+
	|      Additional |  RRs holding additional information
	+---------------------+

此外,DNS还包含Dynamic Update消息类型,在结构上类似于query/response,但是在Dynamic Update消息中的section的名称有一定变化,如上面结构所示,Question称为Zone,Answer称为Prerequisites,Authority称为Updates。

DNS Header部分的结构如下所示:

所有多字节数据均以大端序进行传输,上面提到的各个section都包含不定数量的Resource Records(RR),这些RR指定了DNS 资源和entity的详细信息。RR的结构如下:

对于Zone section来说,包含如上格式的RR,但是省略了TTL,RDLENGTH,RDATA。

Name字段编码了0个或多个DNS标签,标签以空字符结尾。每个标签为一个1字节固定长度的字节字符串。例如,一个域名为www.example.com,会切分成3个标签,www,example以及com,然后进行编码组合到一起\x03www\x07example\x03com\x00。或者,不使用按照长度编码为字节字符串,而是一个标签包含一个2字节的指针,前2个最重要的位设置为1,其他位存储从DNS Header部分的未压缩标签出现的位置的偏移(字节数),例如Zone包含一个Name为\x03www\x07example\x03com\x00的RR,然后其他的RR可以使用2字节的指针\xc0\xc0指向该name,0xc0是距Zone RR的Name字段出现的DNS数据包起点的偏移。

Dynamic Update是可以远程更新DNS记录的一种功能,该功能允许经过授权的更新者区域中的权威名称server上增加和删除资源记录。通常情况下,Dynamic Update使用SIG或者TSIG对更新进行签名。SIG RR的Type字段的值为\x00\x18,RDATA字段结构如下:

其结构图如下所示:


漏洞分析

在Windows系统中,DNS client和DNS server通过两个不同的模块进行实现:

- DNS Client:dnsapi.dll,负责处理DNS 解析

- DNS Server:dns.exe,负责响应DNS查询

在dns.exe中,实现针对各种支持的响应类型的解析函数:

dns!RR_DispatchFunctionForType()通过RRWireReadTable来确定对应的处理功能。RRWireReadTable中包含的支持的响应类型如下:

对于SIG 查询的响应类型也在其中。而处理 SIG 查询的响应类型的函数为dns!SigWireRead(),其汇编代码如下:

也就是在接收到包含SIG RRd的Dynamic Update查询后,dns!SigWireRead()函数被调用来进行RR解析,并存储到一个堆缓冲区中。在调用DNS!RR_AllocateEx()函数进行堆区分配之前,首先调用dns!Name_PacketNameToCountNameEx()函数统计Signer's Name的长度,然后按照如下公式进行计算需要分配的缓冲区的大小:

bsize (buffer size) = Length of uncompressed Signer's Name + 0x14 + Length of Signature

上面公式的计算过程使用的均为16位寄存器,然后在RR_AllocateEx()函数中进行扩展:

如果最后bsize的计算结果大于0xFFFF(16位寄存器能表示的最大值),那么在传入RR_AllocateEx()函数进行内存分配操作时,就会分配一个很小的缓冲区:

从代码中可以看到,在进行内存分配时,实际分配的内存大小为bsize + 0x4a,而且在进行copy操作时,将SIG RR的Signature字段copy到了偏移为Length of uncompressed Signer's Name+0x4c处的缓冲区中,这主要是为了确保Signature可以被copy到缓冲区的末尾位置。

正常情况下,bsize的计算结果会比0xFFFF小,原因如下:

- DNS通过TCP传输的packet的最大数据量为0xFFFF

- DNS的packet一定包含一个12字节的Header

- 对于root zone来说,一个最小的Zone RR大小为5字节

- Signer's Name字段前的SIG RR的长度为18个字节

因此,在正常情况下,Signer's Name和Signature长度的和一定小于0xFFFF - 12 - 5 - 18 = 0xFFDC,那么也就说明bsize的长度不会大于0xFFF0(0xFFDC + 0x14)。

但是,仍然有可能构造一个恶意的Signer's Name来使得bsize的大小超过0xFFFF来造成溢出。因为SIG RR的前18个字节在调用memcpy()函数之前都不会被处理,从而可以任意使用这些字节来存储一个DNS name,而且,构造的DNS name的最后2个字节可以指向Zone RR的Name字段。例如,Name的前18个字节如下:

\x0FAAAAAAAAAAAAAAA\xc0\x0c

使用嵌套指针在SIG RR的18个字节中构造一个Name,如下所示:

Label1 = <Label1_Length> <Label1_Name> \xc0\x0c
Crafted_Name = <Label2_Length> <Label1> <Pointer1>

Pointer1指向Label1_Length处的字节。请注意,Crafted_Name包含一个指向Label1的指针Pointer1,Label1本身包含在Crafted_Name中。由于Label1的指向\xc0\x0c后缀(即Zone RR的Name字段),因此不会导致无限递归,而是通过添加作为名称子集的后缀来延长Crafted_Name 。以一个例子来说明该种方案:

Label1 = \x0cAAAAAAAAAAAA\xc0\x0c
Crafted_Name = \x11\x0cAAAAAAAAAAAA\xc0\x0c\xc0XX

其中,Zone假设为example.com,XX指向Label1。Crafted_Name就变成\x0CAAAAAAAAAAAA\xC0\x0C.AAAAAAAAAAAA.example.com,长度由原来的18字节变为40字节。通过嵌套指针,使得长度变为了原来的2倍。如果Signer's Name指向Crafted_Name,那么就可能实现bsize大于0xFFFF,从而触发漏洞。

影响范围

目前受影响的Microsoft版本:

Microsoft Windows Server 2008 

Microsoft Windows Server 2008 R2

Microsoft Windows Server 2012

Microsoft Windows Server 2012 R2

Microsoft Windows Server 2016

Microsoft Windows Server 2019

Microsoft Windows Server version 1803 (Server Core installation)

Microsoft Windows Server version 1903 (Server Core installation)

Microsoft Windows Server version 1909 (Server Core installation)

Microsoft Windows Server version 2004 (Server Core installation)

时间轴

2020/07/15  深信服千里目实验室发布微软7月份补丁日重点漏洞通告,内容包含对该漏洞的预警及缓解措施

2020/07/31  深信服千里目实验室进行进一步响应并给出解决方案

参考链接

[1].https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2020-1350

技术支持: 建站ABC | 管理登录