聚焦源代码安全,网罗国内外最新资讯!
漏洞简介
Windows DNS Server 是 Windows Server 服务器上的一项重要功能组件, 负责调度和处理域内主机的所有DNS相关服务。
奇安信代码安全实验室的研究员在Windows DNS Server中发现一个严重的远程代码执行漏洞 (CVE-2021-24078)。它是首个由国内安全研究员发现并提交的蠕虫级漏洞,危害巨大,CVSS 评分为9.8分,堪比微软去年修复的另外一个 Windows DNS Server RCE漏洞 (CVE-2020-1350)。攻击者仅需向目标DNS服务器发送特制数据包,即可利用该漏洞在目标系统上以本地系统账户权限执行任意代码,且触发无需交互、无需身份认证且在 Windows DNS 默认配置下即可执行。
攻击场景
攻击场景如下:
(1) 攻击者向目标DNS服务器发起特殊查询”XXXXXXXXXXXX.com”。
(2) 目标DNS服务器无法解析"XXXXXXXXXXXX.com",向上一级 DNS服务器(如8.8.8.8)发起递归查询。
(3) 得到的记录是一个攻击者提前申请的ns记录。此记录的地址指向攻击机器,含义是目标DNS服务器必须去这个ip地址查询相关域名信息。
(4) 目标DNS服务器向攻击机发起第二次查询,直接向攻击机的ip地址发起查询。
(5) 此时攻击机向目标DNS服务器发送畸形响应报文,触发类型混淆漏洞。
漏洞分析与利用
漏洞点在于供处理报文的rr记录生成请求函数dns.exe!Wire_CreateRecordFromWire。该函数所调用的类型解析函数dns.exe!RR_DispatchFunctionForType在解析时出现错误:在判断rr类型是否合法时出现错误,将本应该作为有符号的比较错误地当成无符号比较,导致生成的rr记录被标记成任意type值。换句话说,在此函数中生成的rrcord的type值几乎可被标记为任意值(0-0xffff范围内的大部分值),从而触发类型混淆漏洞,最终导致RCE。漏洞分析流程如图1所示。
图1 漏洞的分析流程图
伪代码如下:
-
_int64 __fastcall RR_DispatchFunctionForType(__int64 *a1, unsigned __int16 a2)
-
{
-
-
-
unsigned __int16 v2;
// r8
-
-
-
__int64 result;
// rax
-
-
-
-
-
-
-
v2 = a2;
-
-
-
if ( a2 )
-
-
-
{
-
-
-
if ( a2 >
52u )
-
-
-
{
-
-
-
if ( (
unsigned __int16)(a2 +
0xFF) <=
1u )
-
-
-
v2 = a2 +
0x134;
-
-
-
else
-
-
-
v2 =
0;
-
-
-
}
-
-
-
if ( !v2 || (result = a1[v2]) ==
0 )
-
-
-
result = *a1;
-
-
-
}
-
-
-
else
-
-
-
{
-
-
-
if ( WPP_GLOBAL_Control != (CDnsClientSubnetRecordsTrie *)&WPP_GLOBAL_Control
-
-
-
&& *((_BYTE *)WPP_GLOBAL_Control +
28) &
1
-
-
-
&& *((_BYTE *)WPP_GLOBAL_Control +
25) >=
4u )
-
-
-
{
-
-
-
WPP_SF_(*((_QWORD *)WPP_GLOBAL_Control +
2),
10i64, &WPP_78f9f773bfac3ce873e2989308e70330_Traceguids);
-
-
-
}
-
-
-
result =
0i64;
-
-
-
}
-
-
-
return result;
-
-
-
}
该解析函数使传入任意非零的rr type值都能找到相关rr的构造函数的CopyWireRead地址,造成类型混淆,进一步转换类型混淆会导致任意地址读或任意地址写后果,最终导致任意代码执行。而且,部分非默认的DNS server甚至支持版本查询,从而使该漏洞更加具有实战价值。
通常,在Windows DNS的域名信息缓存记录过程中,信息会被写入一个个rrecord中。rrcord的类型一般有20多种,包括:
A: 主机地址信息
AAAA: ipv6主机地址
SOA: 标记权威区域地址
……
每一种rrecord的结构都各不相同。在PoC中,笔者将Copyrrcord混淆为type值为0xf0f0类型、Windows自定义的特殊rrcord类型。在此类型中,rrcord偏移的0x20、0x28、0x30、0x38处都是一个指针指向另外一个record,而在Copyrrcord类型中,偏移0x20、0x28、0x30处的值为0,偏移0x38处为一个长度可控的buf的起始位置。0xf0f0类型和copyrrecord类型的rrecord结构如图2和图3所示。
图2 0xf0f0类型的rrecord结构
图3 Copyrrecord类型(type值为0或者其它)rrecord结构
在PoC 中实现的是可写部分用于触发崩溃,通过调用RR_Free函数清理现场(当报文处理函数发现报文畸形时,将会拒绝继续处理报文并清理现场)。这样即可控制free函数,free任意一个地址。
实际上,到了这一步已经可以开始尝试进行利用漏洞。当向 DNS server缓存大量rrecord记录时,可等同于堆喷效果。尝试向0x0c0c0c0c0c0c0c0c或其它地址进行free,造成释放后使用 (UAF),再转为可读或可写,最终完成任意代码执行。相关代码如下:
-
void __fastcall RR_Free(__int64 a1)
-
{
-
-
-
……
-
-
-
if ( *(_WORD *)(v1 +
12) ==
0xF0F0u || *(_BYTE *)(v1 +
10) <
0 )
-
-
-
{
-
-
-
if ( WPP_GLOBAL_Control != (CDnsClientSubnetRecordsTrie *)&WPP_GLOBAL_Control
-
-
-
&& *((_DWORD *)WPP_GLOBAL_Control +
17) &
0x100
-
-
-
&& *((_BYTE *)WPP_GLOBAL_Control +
65) >=
5u )
-
-
-
{
-
-
-
v9 = *(
unsigned __int16 *)(v1 +
12);
-
-
-
WPP_SF_qd(*((_QWORD *)WPP_GLOBAL_Control +
7),
10i64, &WPP_103a918d359034d16f977c36c11204c8_Traceguids, v1);
-
-
-
}
-
-
-
RR_ListFree(*(_QWORD **)(v1 +
56));
-
-
-
……
-
-
-
-
在后续函数Wire_AddResourceRecordToMessage (为响应报文中写入rrcord中记录的信息)中,我们还可以尝试进行反向混淆操作,如即将其它类型的rrcord混淆为Copyrrcord,造成信息泄漏等。
推荐阅读
微软披露首个由中国发现的蠕虫级漏洞 奇安信代码安全实验室获致谢
FireEye 红队失窃工具大揭秘之:分析复现SolarWinds RCE 0day (CVE-2020-10148)
XStream 反序列化漏洞 (CVE-2020-26258 & 26259) 的复现与分析
题图:Pixabay License
转载请注明“转自奇安信代码卫士 https://codesafe.qianxin.com”。
奇安信代码卫士 (codesafe)
国内首个专注于软件开发安全的
产品线。
觉得不错,就点个 “在看” 或 "赞” 吧~
转载:https://blog.csdn.net/smellycat000/article/details/113787650