Awesome-POC/操作系统漏洞/Windows SMB远程代码执行漏洞 CVE-2020-0796.md

207 lines
11 KiB
Markdown
Raw Normal View History

2022-02-20 16:14:31 +08:00
# Windows SMB远程代码执行漏洞 CVE-2020-0796
## 漏洞描述
2020年3月10日微软在其官方SRC发布了CVE-2020-0796的安全公告ADV200005MicrosoftGuidance for Disabling SMBv3 Compression,公告表示在Windows SMBv3版本的客户端和服务端存在远程代码执行漏洞。同时指出该漏洞存在于MicroSoft Server Message Block 3.1.1协议处理特定请求包的功能中攻击者利用该漏洞可在目标SMB Server或者Client中执行任意代码
## 漏洞影响
```
SMB版本 v3.1.1
Windows 10 Version 1903 for 32-bit Systems
Windows 10 Version 1903 for x64-based Systems
Windows 10 Version 1903 for ARM64-based Systems
Windows Server, Version 1903 (Server Core installation)
Windows 10 Version 1909 for 32-bit Systems
Windows 10 Version 1909 for x64-based Systems
Windows 10 Version 1909 for ARM64-based Systems
Windows Server, Version 1909 (Server Core installation)
```
## 漏洞复现
在[MSDN](https://msdn.itellyou.cn/)上下载对应的存在漏洞的系统版本
2022-12-05 11:09:28 +08:00
![img](./images/1627103590130-7efad360-17d2-447f-913d-70e7c955739d.png)
2022-02-20 16:14:31 +08:00
安装后执行命令 winver 查看系统版本,并查看是否含有 KB4551762补丁
2022-12-05 11:09:28 +08:00
![img](./images/1627103590143-26868338-bdac-4450-82a9-903865d6bccf.png)
2022-02-20 16:14:31 +08:00
CVE-2020-0796漏洞存在于受影响版本的Windows驱动srv2.sys中。Windows SMB v3.1.1 版本增加了对压缩数据的支持。图2所示为带压缩数据的SMB数据报文的构成。
2022-12-05 11:09:28 +08:00
![img](./images/1627103608064-45c790ac-0255-4507-a3e0-87549c3cfbeb.png)
2022-02-20 16:14:31 +08:00
ProtocolId4字节固定为0x424D53FC
OriginalComressedSegmentSize4字节原始的未压缩数据大小
CompressionAlgorithm2字节压缩算法
Flags2字节详见协议文档
Offset/Length根据Flags的取值为Offset或者LengthOffset表示数据包中压缩数据相对于当前结构的偏移
2022-12-05 11:09:28 +08:00
![img](./images/1627103608128-f0173921-1137-4014-8cc2-510e9d4ed187.png)
2022-02-20 16:14:31 +08:00
srv2.sys中处理SMBv3压缩数据包的解压函数Srv2DecompressData未严格校验数据包中OriginalCompressedSegmentSize和Offset/Length字段的合法性。而这两个字段影响了Srv2DecompressData中内存分配函数SrvNetAllocateBuffer的参数。如图4所示的Srv2DecompressData函数反编译代码SrvNetAllocateBuffer实际的参数为OriginalCompressedSegmentSize+Offset。这两个参数都直接来源于数据包中SMB Compression Transform Header中的字段而函数并未判断这两个字段是否合法就直接将其相加后作为内存分配的参数(unsigned int类型
2022-12-05 11:09:28 +08:00
![img](./images/1627103608120-89f12b49-091d-4927-9611-6a8f2fdcddcc.png)
2022-02-20 16:14:31 +08:00
这里OriginalCompressedSegmentSize+Offset可能小于实际需要分配的内存大小从而在后续调用解压函数SmbCompressionDecompress过程中存在越界读取或者写入的风险。
目前已公开的针对该漏洞的本地提权利用包含如下的主要过程:
1验证程序首先创建到SMS server的会话连接记为session
2验证程序获取自身token数据结构中privilege成员在内核中的地址记tokenAddr
3验证程序通过session发送畸形压缩数据记为evilData给SMB server触发漏洞。其中evilData包含tokenAddr、权限数据、溢出占位数据。
4 SMS server收到evilData后触发漏洞并修改tokenAddr地址处的权限数据从而提升验证程序的权限。
5验证程序获取权限后对winlogon进行控制来创建system用户shell。
首先看一下已公开利用的evilData数据包
2022-12-05 11:09:28 +08:00
![img](./images/1627103608165-055f3029-8b10-4c7c-a747-2e590bd81f62.png)
2022-02-20 16:14:31 +08:00
数据包的内容很简单,其中几个关键字段数据如下:
```
OriginalSize 0xffffffff
Offset0x10
Real compressed data 13字节的压缩数据解压后应为1108字节A加8字节的token地址。
SMB3 raw data 实际上是由2个8字节的0x1FF2FFFFBC总长0x10)加上0x13字节的压缩数据组成
```
从上面的漏洞原理分析可知漏洞成因是Srv2DecompressData函数对报文字段缺乏合法性判断造成内存分配不当。在该漏洞数据包中OriginalSize 是一个畸形值。OriginalSize+ Offset = 0xffffffff + 0x10 = 0xf 是一个很小的值其将会传递给SrvNetAllocateBuffer进行调用下面具体分析内存分配情况。SrvNetAllocateBuffer的反编译代码
2022-12-05 11:09:28 +08:00
![img](./images/1627103608301-0c3eff1f-7647-4879-80ab-bda6a5f296e2.png)
2022-02-20 16:14:31 +08:00
由于传给SrvNetAllocateBuffer的参数为0xf根据SrvNetAllocateBuffer的处理流程可知该请求内存将从SrvNetBufferLookasides表中分配。这里需要注意的是变量SrvDisableNetBufferLookAsideList跟注册表项相关系统默认状态下SrvDisableNetBufferLookAsideList为0。
2022-12-05 11:09:28 +08:00
![img](./images/1627103608909-861bbd82-b9c0-4fba-ba59-7be668f343eb.png)
2022-02-20 16:14:31 +08:00
SrvNetBufferLookasides表通过函数SrvNetCreateBuffer初始化实际SrvNetCreateBuffer循环调用了SrvNetBufferLookasideAllocate分配内存调用SrvNetBufferLookasideAllocate的参数分别为[0x1100, 0x2100, 0x4100, 0x8100, 0x10100, 0x20100, 0x40100, 0x80100, 0x100100]。在这里内存分配参数为0xf对应的lookaside表为0x1100大小的表项。
2022-12-05 11:09:28 +08:00
![img](./images/1627103609167-409eade1-c459-4574-ad97-44f132fb89aa.png)
2022-02-20 16:14:31 +08:00
SrvNetBufferLookasideAllocate函数实际是调用SrvNetAllocateBufferFromPool来分配内存
2022-12-05 11:09:28 +08:00
![img](./images/1627103609243-cb1271f9-26ce-42a4-b70f-371ffdf8928c.png)
2022-02-20 16:14:31 +08:00
在函数SrvNetAllocateBufferFromPool中对于用户请求的内存分配大小内部通过ExAllocatePoolWithTag函数分配的内存实际要大于请求值多出部分用于存储部分内存相关数据结构。以请求分配0x1100大小为例经过一系列判断后最后分配的内存大小allocate_size= 0x1100 + E8 + 2*(MmSizeOfMdl + 8)。
2022-12-05 11:09:28 +08:00
![img](./images/1627103609249-7cb52d25-27e2-431d-bfa2-f2ab65619949.png)
2022-02-20 16:14:31 +08:00
内存分配完毕之后SrvNetAllocateBufferFromPool函数还对分配的内存进行了一系列初始化操作最后返回了一个内存信息结构体指针作为函数的返回值。
2022-12-05 11:09:28 +08:00
![img](./images/1627103609266-3e79a148-d677-42e9-8aff-5534c5cea03d.png)
2022-02-20 16:14:31 +08:00
这里需要注意如下的数据关系SrvNetAllocateBufferFromPool函数返回值return_buffer指向一个内存数据结构该内存数据结构起始地址同实际分配内存函数ExAllocatePoolWithTag分配的内存起始地址的的偏移为0x1150return_buffer+0x18位置指向了实际分配内存起始地址偏移0x50位置处而最终return_buffer会作为函数SrvNetAllocateBuffer的返回值
2022-12-05 11:09:28 +08:00
![img](./images/1627103609453-a5e58e1c-cab0-4b26-a0f0-97018dad5d49.png)
2022-02-20 16:14:31 +08:00
回到漏洞解压函数Srv2DecompressData在进行内存分配之后Srv2DecompressData调用函数SmbCompressionDecompress开始解压被压缩的数据
2022-12-05 11:09:28 +08:00
![img](./images/1627103610158-886f5c7b-5631-4866-ac8a-1928e44d070d.png)
2022-02-20 16:14:31 +08:00
实际上该函数调用了Windows库函数RtlDecompressBufferEx2来实现解压根据RtlDecompressBufferEx2的函数原型来对应分析SmbCompressionDecompress函数的各个参数。
```
SmbCompressionDecompress(CompressAlgo//压缩算法
Compressed_buf//指向数据包中的压缩数据
Compressed_size//数据包中压缩数据大小,计算得到
UnCompressedBuf,//解压后的数据存储地址,*(alloc_buffer+0x18)+0x10
UnCompressedSize,//压缩数据原始大小,源于数据包OriginalCompressedSegmentSize
FinalUnCompressedSize)//最终解压后数据大小
```
从反编译代码可以看出函数SmbCompressionDecompress中保存解压后数据的地址为*(alloc_buffer+0x18)+0x10的位置根据内存分配过程分析alloc_buffer + 0x18指向了实际内存分配起始位置偏移0x50处所以拷贝目的地址为实际内存分配起始地址偏移0x60位置处。
在解压过程中压缩数据解压后将存储到这个地址指向的内存中。根据evilData数据的构造过程解压后的数据为占坑数据和tokenAddr。拷贝到该处地址后tokenAddr将覆盖原内存数据结构中alloc_buffer+0x18处的数据。也就是解压缩函数SmbCompressionDecompress返回后alloc_buffer+0x18将指向验证程序的tokenAddr内核地址
2022-12-05 11:09:28 +08:00
![img](./images/1627103610224-2ebcf803-253f-4a7e-96bc-83f1d1c30afd.png)
2022-02-20 16:14:31 +08:00
2022-12-05 11:09:28 +08:00
![img](./images/1627103610225-cee1b871-7a6a-4147-9839-84a117a2e09d.png)
2022-02-20 16:14:31 +08:00
继续看Srv2DecompressData的后续处理流程解压成功后函数判断offset的结果不为0。不为0则进行内存移动内存拷贝的参数如下
```
memmove(*(alloc_buffer+0x18)SMB_payloadoffset)
```
此时alloc_buffer+0x18已经指向验证程序的tokenAddr内核地址而SMB_payload此时指向evilData中的权限数据offset则为0x10。因此这个内存移动完成后权限数据将写入tokenAddr处。这意味着SMS Server成功修改了验证程序的权限从而实现了验证程序的提权
还有一个细节需要注意在解压时Srv2DecompressData函数会判断实际的解压后数据大小FinalUnCompressedSize是否和数据包中原始数据大小OriginalCompressedSegmentSize一致
2022-12-05 11:09:28 +08:00
![img](./images/1627103610261-f1cba6bf-6870-41b7-bb01-c8933df88a43.png)
2022-02-20 16:14:31 +08:00
按理来说实际解压后的数据大小为0x1100不等于数据包中的原始压缩数据大小0xffffffff这里应该进入到后面内存释放的流程。然而实际上在函数SmbCompressionDecompress中调用RtlDecompressBufferEx2成功后会直接将OriginalCompressedSegmentSize赋值给FinalUnCompressedSize。这也是该漏洞关于任意地址写入成功的关键之一。
2022-12-05 11:09:28 +08:00
![img](./images/1627103610298-982f6ead-a91f-46c8-85fa-5f69f436f47f.png)
2022-02-20 16:14:31 +08:00
### CVE-2020-0796 目标探测(奇安信)
使用奇安信的漏洞扫描来探测:[奇安信 CVE-2020-0796 扫描下载](http://dl.qianxin.com/skylar6/CVE-2020-0796-Scanner.zip)
2022-12-05 11:09:28 +08:00
![img](./images/1627103611100-9024e27a-d488-4c8c-861e-f791256c65ed.png)
2022-02-20 16:14:31 +08:00
### CVE-2020-0796 蓝屏EXP
运行脚本后目标成功蓝屏:[Github CVE-2020-0796 蓝屏EXP 下载](https://github.com/eerykitty/CVE-2020-0796-PoC)
2022-12-05 11:09:28 +08:00
![img](./images/1627103611063-74ff70af-f1bb-457a-9b0b-5a87d2a86cc4.png)
2022-02-20 16:14:31 +08:00
### CVE-2020-0796 本地提权EXP
运行应用程序后弹出cmd窗口为 system权限[Github CVE-2020-0796 本地提权EXP 下载](https://github.com/danigargu/CVE-2020-0796)
2022-12-05 11:09:28 +08:00
![img](./images/1627103611077-e1fc15be-d3ea-4036-82f2-5cf7a90f7ea9.png)
2022-02-20 16:14:31 +08:00
或者使用 MSF的内置EXP windows/local/cve_2020_0796_smbghost 来本地提权
### CVE-2020-0796 RCE EXP
RCE[Github CVE-2020-0796 RCE EXP](https://github.com/chompie1337/SMBGhost_RCE_PoC)
msfvenom生成reversed shellcode
```
msfvenom -p windows/x64/meterpreter/bind_tcp lport=2333 -f py -o exp.py
```
将生成exp.py中的shellcode替换exploit.py中的shellcode
2022-12-05 11:09:28 +08:00
![img](./images/1627103611172-2054aa5a-50ed-4b22-b507-2e2708bb277b.png)
2022-02-20 16:14:31 +08:00
2022-12-05 11:09:28 +08:00
![img](./images/1627103611207-6e81b26c-ebc8-4012-a66a-cd4cb919ca53.png)
2022-02-20 16:14:31 +08:00
**buf 要替换为 USER_PAYLOAD**
使用 MSF
```shell
msf5 > use exploit/multi/handler
[*] Using configured payload generic/shell_reverse_tcp
msf5 exploit(multi/handler) > set payload windows/x64/meterpreter/bind_tcp
payload => windows/x64/meterpreter/bind_tcp
msf5 exploit(multi/handler) > set lport 2333
lport => 2333
msf5 exploit(multi/handler) > set rhost 192.168.1.110
rhost => 192.168.1.110
msf5 exploit(multi/handler) > exploit
执行脚本即可
python3 exploit.py -ip 192.168.1.110
```
**注意有蓝屏概率**