AmesianX/CVE-2026-53435
GitHub: AmesianX/CVE-2026-53435
针对 Jenkins 反序列化漏洞 CVE-2026-53435 的 PoC 项目,附带从公告到可用 exploit 的完整 8 小时研究过程记录与差异化验证实验环境。
Stars: 7 | Forks: 2
# CVE-2026-53435 — Jenkins 反序列化 → 任意文件读取 (PoC)

| | |
|---|---|
| **CVE** | CVE-2026-53435 (Jenkins SECURITY-3707) |
| **类别** | 不安全的反序列化(通过 config.xml 绕过 ClassFilter) |
| **影响(本 PoC)** | controller 上的已认证任意文件读取 |
| **受影响版本** | Jenkins weekly ≤ 2.567, LTS ≤ 2.555.2 |
| **修复版本** | Jenkins weekly 2.568, LTS 2.555.3 |
| **安全公告** | https://www.jenkins.io/security/advisory/2026-06-10/ (发布于 2026-06-10) |
| **撰写本文时的状态** | 当时无公开 PoC(GitHub PoC 仓库数:0) |
## 为什么创建此仓库
这是一次展示*过程*而不仅仅是最终成果的实验。
多年来,攻击性安全研究人员的产出仅仅是单个最终的 exploit ——
导致产生该 exploit 的那 8 小时的错误尝试都随之消失了。这个仓库保留了那些
错误尝试。人类与 AI 协作从安全公告开始到产出可用 PoC 的完整、经过轻微编辑的
记录被作为附录收录其中。
它想要刻意表达的重点*并不是*“这是 AI 做的”。这 8 小时恰恰证明了
并非如此。AI 从未一次性成功生成整个利用链。真正支撑这项工作的是
领域专业知识 —— 知道安全公告中隐藏着一个反序列化 sink,
知道应去查看 Jenkins **core** 类型而不是插件,知道补丁前
`DescribableList` 不会强制执行其元素类型,并且知道如何
*验证*一个断言而不是盲目相信它。研究人员的价值并没有
消失;它只是从**敲击 exploit 代码**转移到了**引导、剪枝和**
**验证**上。
这种转变才是真正值得记录的东西。
## 漏洞(根本原因)
Jenkins 通过自定义的 `ClassFilter` 保护反序列化过程,该过滤器仅允许
Jenkins core 或插件中定义的类型。CVE-2026-53435 表明这*仍然不够*:
能够 POST 一个 `config.xml` 的攻击者,可以让 Jenkins
将**任意的 core/插件类型反序列化到一个从未预期处理它的上下文中**,
随后通过 Stapler 路由经由 HTTP 访问到该对象。
此 PoC 将一个 `hudson.Plugin$DummyImpl`(一个 Jenkins-core 类型,因此它能
通过位置白名单)植入到一个 `ListView` 的 `` 列表中 —— 这是一个
`DescribableList`,在打补丁前,它不会强制校验其元素
类型。植入的对象带有 `baseResourceURL=file:/`。随后将 HTTP
请求路由到该对象,就会直接从 controller 的文件系统提供文件。
通用的 ysoserial 链在此处**不起作用** —— gadget 必须是
Jenkins/插件固有的类型才能绕过过滤器。这个限制条件正是
关键所在。
## 范围与负责任的漏洞披露
- 此 PoC 仅演示了**任意文件读取**的影响。
- 安全公告还描述了通过同一底层原语实现的**用户模拟**和**Script Console RCE**。
这些利用链在研究过程中已被触达,但在此处被**刻意隐去**:
该 CVE 在发布前几天才被修复,而一个现成的 RCE 主要会被用于对
未修复实例的大规模漏洞利用。文件读取已足以证明其影响。
- 该漏洞**已被修复**。所有测试均在作者自己的机器上针对
**本地的、隔离的实验环境**(见下文)进行。未触及任何外部
或第三方系统。
**仅对你拥有或明确获得授权测试的系统使用此工具。**
## 证明:在受影响版本成功,在修复版本失效
该 exploit 分别针对两个配置完全相同的容器运行 —— 受影响版本
`2.555.2` 和修复版本 `2.555.3` —— 以确认它触发的是*这个* CVE,而不是
某些不相关的文件读取原语:
| | **2.555.2 (受影响)** | **2.555.3 (已修复)** |
|---|---|---|
| `createView` | HTTP 200 | HTTP 200 |
| 存储的 `` | ` ` — **留存** | ` ` — **被剥离** |
| 触发 → `/etc/passwd` | `root:x:0:0:...` — **成功读取** | 空 — **被拦截** |
修复后的版本接受了请求,但修复措施**在反序列化时拒绝了植入的类型**,
因此 properties 列表返回为空,也就没有任何可供路由的对象。
该失败恰好对应于安全公告所描述的机制 —— 这正是它成为
CVE-2026-53435 真正 PoC 的原因。
## 用法
```
python3 exploit_cve_2026_53435_v2.py [view_name]
# 示例(针对您自己的实验室):
python3 exploit_cve_2026_53435_v2.py http://127.0.0.1:8080 /etc/passwd
```
- `base_url` — 目标的 `http://host:port`(纯 HTTP;不要添加 `https`
前缀,除非该实例确实终结了 TLS)。
- 需要一个具有 POST 视图 `config.xml` 权限
(View/Configure) 以及 Overall/Read 权限的账户。
## 复现实验环境
```
docker compose -f lab/docker-compose.yml up -d
# 存在漏洞: http://127.0.0.1:8080 (Jenkins LTS 2.555.2)
# 已修补: http://127.0.0.1:8081 (Jenkins LTS 2.555.3, negative control)
```
该实验环境通过 Groovy init 配置了一个仅限本地的用户数据库,以便在无需
外部 IdP 的情况下测试已认证低权限路径。
## 时间线 — 约 8.5 小时,某个星期五的晚上
```
2026-06-12 (Fri) 15:00 → 23:23 ≈ 8h 20m
15:00–15:12 Lab built (docker: vuln 2.555.2 / patched 2.555.3) + first recon
15:12–21:00 Deserialization sink & gadget analysis
(Commons-Collections bypass attempts failed → pivot
from properties to actions and back)
21:00–22:30 ClassFilter analysis + gadget re-hunt, restricted to core types
22:30–23:00 Working PoC (v1 → v2) + differential verification (vuln vs patched)
```
这些时间大部分都花在*分析*上,而不是敲代码。exploit 本身是
在最后约 30 分钟内完成的 —— 也就是在确定了正确的 sink 和 gadget 之后。
## 构建方式
使用 **Claude Code** (Anthropic) 构建,由作者交互式驱动:
- **主要模型:** Claude **Opus 4.8** (Claude Max)
- **部分:** Claude **Fable 5** (Mythos-class 级别)