漏洞描述
CVE-2019-0547,一个Windows系统下DHCP客户端的任意代码执行漏洞,漏洞的主要原因是对DHCP消息的错误的处理方式造成内存损坏。 攻击者可以通过构造恶意的DHCP响应数据包到存在漏洞的系统中来触发漏洞,最终可以实现以管理员权限执行任意代码,危害巨大。漏洞影响范围
• Microsoft Windows10 version1803 • Microsoft Windows Serverversion 1803(ServerCoreInstallation) 该漏洞影响的系统版本只有两个,但是随着系统版本迭代,现在使用Windows 10的人越来越多,这个漏洞还是需要关注的。漏洞基本信息
漏洞触发文件: DHCP服务主机上运行的dcpcore.dll 漏洞触发函数: dhcpcore!DecodeDomainSearchListData() 漏洞触发数据对象: 一个原本用于存储域搜索结果的堆缓冲区漏洞分析
基础知识
动态主机配置协议(DHCP),主要用于集中管理和自动化网络上IP地址的分配。 它是BOOTP协议的扩展。 除了IP地址分配外,DHCP客户端还从DHCP服务器接收管理其网络配置所需的信息,包括子网掩码,网关地址,DNS服务器地址等。 DHCP使用UDP端口67和68进行通信。 DHCP在所有现代操作系统上都是标准的-并且默认情况下已对网络接口启用-在Microsoft Windows上。 典型的DHCP事务流程如下:- client发送DHCP DISCOVER到server
- server发送DHCP OFFER到client
- client发送DHCP REQUEST到server
- server响应一个DHCP ACK到client
原理分析
在Windows的DHCP客户端中存在越界写漏洞。 DHCP客户端在启动时作为svchost.exe服务运行,并遵循DHCP协议来获取系统上网络接口的IP地址。 当收到DHCP答复时,它将使用dhcpcore解析DHCP选项! DhcpExtractFullOptions(),当遇到域搜索选项(option tag: 119)时,该调用再调用dhcpcore! DecodeDomainSearchListData()。 此函数主要将wire format的DNS名称转换为基于文本的DNS名称。 它遍历每个DNS名称,在堆上分配内存,解压缩遇到的任何标签,并使用memcpy()复制标签,并在标签之间插入“.”,名称之间插入”,”。 用于存储DNS名称的已分配缓冲区大小是基于长度的字符串,并且由于DNS名称以空值结尾,因此缓冲区大小比DNS名称小1。 因此,DNS名称“x07examplex03comx00”导致缓冲区大小为12(请注意,字符串的长度为13)。 如果DHCP回复消息包含前两个字节为零的域搜索选项,则调用程序函数将它们视为两个不同名称的两个以空字符结尾的字符,并将大小为0传递给dhcpcore! DecodeDomainSearchListData(),该函数将无法正确验证,而是调用HeapAlloc分配0字节的缓冲区。 然后,它继续处理两个根标签,并写入无效缓冲区,从而导致越界写入。 攻击者可以设置一个恶意的DHCP服务器并使用恶意的DHCP响应消息来响应同一网段中的DHCP请求,从而利用该漏洞。代码分析
分析使用的dhcpcore.dll版本为10.0.17134.191。
; dhcpcore!DecodeDomainSearchListData:
6ffcb0cc 8bff mov edi,edi
6ffcb0ce 55 push ebp
6ffcb0cf 8bec mov ebp,esp
6ffcb0d1 83ec2c sub esp,2Ch
6ffcb0d4 8bc2 mov eax,edx
6ffcb0d6 894de4 mov dword ptr [ebp-1Ch],ecx
6ffcb0d9 8bc8 mov ecx,eax
6ffcb0db 8945f0 mov dword ptr [ebp-10h],eax
6ffcb0de 53 push ebx
6ffcb0df 8b5d0c mov ebx,dword ptr [ebp+0Ch]
6ffcb0e2 33d2 xor edx,edx
6ffcb0e4 c1e902 shr ecx,2
6ffcb0e7 83c164 add ecx,64h
6ffcb0ea 56 push esi
6ffcb0eb 33f6 xor esi,esi
6ffcb0ed 894dd4 mov dword ptr [ebp-2Ch],ecx
6ffcb0f0 8b4df0 mov ecx,dword ptr [ebp-10h]
6ffcb0f3 83f802 cmp eax,2
6ffcb0f6 57 push edi
6ffcb0f7 8b7d14 mov edi,dword ptr [ebp+14h]
6ffcb0fa 1bc0 sbb eax,eax
6ffcb0fc 40 inc eax
6ffcb0fd 8907 mov dword ptr [edi],eax ; 外层循环开始
6ffcb0ff 833f00 cmp dword ptr [edi],0
6ffcb102 0f8498010000 je dhcpcore!DecodeDomainSearchListData+0x1d4
6ffcb108 42 inc edx ; edx是计数器
6ffcb109 8955f4 mov dword ptr [ebp-0Ch],edx ; 第一次迭代时跳过HeapFree
6ffcb10c 83fa02 cmp edx,2
6ffcb0fd 8907 mov dword ptr [edi],eax
6ffcb0ff 833f00 cmp dword ptr [edi],0 ; 第二次迭代, HeapFree and HeapAlloc都发生了.
6ffcb102 0f8498010000 je dhcpcore!DecodeDomainSearchListData+0x1d4
6ffcb108 42 inc edx
6ffcb109 8955f4 mov dword ptr [ebp-0Ch],edx
6ffcb10c 83fa02 cmp edx,2
6ffcb10f 7533 jne dhcpcore!DecodeDomainSearchListData+0x78
6ffcb111 8b7508 mov esi,dword ptr [ebp+8]
6ffcb114 833e00 cmp dword ptr [esi],0
6ffcb117 7413 je dhcpcore!DecodeDomainSearchListData+0x60
6ffcb119 ff36 push dword ptr [esi]
6ffcb11b 6a00 push 0
6ffcb11d ff35580dff6f push dword ptr [dhcpcore!DhcpGlobalHeap]
6ffcb123 ff155c21ff6f call dword ptr [dhcpcore!_imp__HeapFree]
6ffcb129 832600 and dword ptr [esi],0 ; [ebx]是该函数的参数。 DNS名称的累积长度; 排除终止空字节.
6ffcb12c ff33 push dword ptr [ebx] ; dwBytes (size) In malicious case ebx = 0 6ffcb12e 6a08 push 8 ; dwFlags
6ffcb130 ff35580dff6f push dword ptr [dhcpcore!DhcpGlobalHeap] ; hHeap
6ffcb136 ff155021ff6f call dword ptr [dhcpcore!_imp__HeapAlloc] ; HeapAlloc 0 bytes 6ffcb13c 8b55f4 mov edx,dword ptr [ebp-0Ch]
6ffcb13f 8bf0 mov esi,eax ; esi = buffer allocated.size不能为0
6ffcb141 8b4df0 mov ecx,dword ptr [ebp-10h]
6ffcb144 8b4510 mov eax,dword ptr [ebp+10h]
6ffcb147 832300 and dword ptr [ebx],0
6ffcb14a 8365f800 and dword ptr [ebp-8],0
6ffcb14e 832000 and dword ptr [eax],0
6ffcb151 33c0 xor eax,eax
6ffcb153 8945ec mov dword ptr [ebp-14h],eax
6ffcb156 8845ff mov byte ptr [ebp-1],al
6ffcb159 85c9 test ecx,ecx
6ffcb15b 0f8419010000 je dhcpcore!DecodeDomainSearchListData+0x1ae ;内层循环开始
6ffcb161 8b07 mov eax,dword ptr [edi]
6ffcb163 85c0 test eax,eax
6ffcb165 0f840c010000 je dhcpcore!DecodeDomainSearchListData+0x1ab
6ffcb16b 8365e800 and dword ptr [ebp-18h],0
6ffcb16f 8b4dec mov ecx,dword ptr [ebp-14h]
6ffcb172 8b5de4 mov ebx,dword ptr [ebp-1Ch]
6ffcb175 03d9 add ebx,ecx
6ffcb177 895de0 mov dword ptr [ebp-20h],ebx
6ffcb17a 8a1b mov bl,byte ptr [ebx]
6ffcb17c 885dfe mov byte ptr [ebp-2],bl
6ffcb17f 84db test bl,bl
6ffcb181 8b5d0c mov ebx,dword ptr [ebp+0Ch] ; 第一次迭代时跳转.
6ffcb184 0f8492000000 je dhcpcore!DecodeDomainSearchListData+0x150
6ffcb21c 807dff00 cmp byte ptr [ebp-1],0
6ffcb220 7605 jbe dhcpcore!DecodeDomainSearchListData+0x15b
6ffcb222 8b4510 mov eax,dword ptr [ebp+10h]
..........
6ffcb267 8b45ec mov eax,dword ptr [ebp-14h]
6ffcb26a 8b55f4 mov edx,dword ptr [ebp-0Ch]
6ffcb26d 3bc1 cmp eax,ecx ; 跳转到第一次迭代的内层循环的开始位置
6ffcb26f 0f82ecfeffff jb dhcpcore!DecodeDomainSearchListData+0x95
; 继续第二次迭代
6ffcb275 eb03 jmp dhcpcore!DecodeDomainSearchListData+0x1ae
6ffcb277 8b45ec mov eax,dword ptr [ebp-14h]
6ffcb27a 8b55f4 mov edx,dword ptr [ebp-0Ch]
6ffcb27d 3bc1 cmp eax,ecx
6ffcb27f 7405 je dhcpcore!DecodeDomainSearchListData+0x1ba
6ffcb281 832700 and dword ptr [edi],0
6ffcb284 eb0c jmp dhcpcore!DecodeDomainSearchListData+0x1c6
6ffcb286 83fa02 cmp edx,2
6ffcb289 750a jne dhcpcore!DecodeDomainSearchListData+0x1c9
6ffcb28b 8b03 mov eax,dword ptr [ebx] ;发生越界写,程序可能不会在这里崩溃,因为单个字节被写入esi-1,这可能是一个有效的地址。
6ffcb28d c64430ff00 mov byte ptr [eax+esi-1],0
6ffcb18a 8a55fe mov dl,byte ptr [ebp-2]
6ffcb18d 80fac0 cmp dl,0C0h
; dhcpcore!ClearDomainSearchOption:
6ffcb025 8bff mov edi,edi
6ffcb027 55 push ebp
6ffcb028 8bec mov ebp,esp
6ffcb02a 51 push ecx
6ffcb02b 56 push esi
6ffcb02c 8bf1 mov esi,ecx
6ffcb02e 57 push edi
6ffcb02f 33ff xor edi,edi ;来自上述HeapAlloc的无效地址(esi)
6ffcb031 8b8624070000 mov eax,dword ptr [esi+724h]
6ffcb037 85c0 test eax,eax
6ffcb039 7414 je dhcpcore!ClearDomainSearchOption+0x2a
6ffcb03b 50 push eax
6ffcb03c 57 push edi
6ffcb03d ff35580dff6f push dword ptr [dhcpcore!DhcpGlobalHeap] ;在无效堆上释放导致svchost.exe进程崩溃
6ffcb043 ff155c21ff6f call dword ptr [dhcpcore!_imp__HeapFree]
6ffcb049 89be24070000 mov dword ptr [esi+724h],edi
攻击场景分析
攻击者可以构造一个恶意的DHCP服务器,充分发挥该漏洞的作用需要进入到某一个网段内,然后监听网段内的DHCP请求,接收到请求之后就响应一个特制的恶意的DHCP响应数据,这样就可以造成存在漏洞的系统执行代码。流量分析
首先client发起一个request:![8a805ce88a0baf085baae5a71a22dd9f.png](https://i-blog.csdnimg.cn/blog_migrate/8eb516e94f2ef79c6fda16e6d145214e.jpeg)
![676321339456a767d054c81f1791c994.png](https://i-blog.csdnimg.cn/blog_migrate/8e68ac0bec2e164e5fea152342a697eb.jpeg)
检测思路
首先要监听UDP的67/68端口的流量。 检测设备可以根据DHCP Magic Cookie值x63x82x53x63来判断是否为DHCP消息。 如果操作码为2,则检测设备必须解析每个DHCP选项,并检查option tag设置为0x77的所有选项的选项数据。 如果发现任何此类选项的选项数据以“x00x00”开头,则应将流量视为可疑的攻击流量。总结
这个分析思路很清楚,基本上是一个漏洞响应的微缩过程,到最后给出解决方案,个人感觉比较成熟。 最后的流量检测现在很多的防火墙都可以实现,从流量侧拦截攻击好过主机防御。参考文献