rivaedoardo62-boop/cve-2024-23897-jenkins-poc

GitHub: rivaedoardo62-boop/cve-2024-23897-jenkins-poc

通过 Docker 双环境对比复现 CVE-2024-23897 Jenkins CLI 任意文件读取漏洞,提供完整的 PoC 驱动流程与补丁分析报告。

Stars: 0 | Forks: 0

# CVE-2024-23897: Jenkins 任意文件读取 (args4j @-Syntax) 这是一个完全独立且本地化的 **CVE-2024-23897**(严重级别,CVSS 3.1 基础分 9.8)复现项目,针对的是 Jenkins CLI 中的任意文件读取漏洞。该项目启动了两个仅 Jenkins 次版本号不同的 Docker 技术栈,对两者运行相同的 proof of concept,并展示了漏洞在未打补丁的 controller 上触发,而在打补丁的版本上则被成功阻止。 整个流程由一个单独的 Python 程序 `poc.py` 驱动。测试框架仅负责统筹环境(Docker Compose、官方 `jenkins-cli.jar` 客户端以及对输出的原样捕获)。漏洞本身存在于 Jenkins 自己的 Java 代码中,此处并未对其进行重新实现。 包含补丁审查和 CVSS 分解的完整书面分析,请参见 [`report/report.pdf`](report/report.pdf)。 ## 一段话解释漏洞 Jenkins CLI 使用 args4j 库构建其参数解析器。args4j 有一个名为 `expandAtFiles` 的功能,由 `atSyntax` 标志控制且默认启用,它会在命令运行前将任何 `@/path/to/file` 形式的参数重写为该文件的内容。该文件以 Jenkins controller 进程的权限被打开。由于所有三种 CLI 传输方式(HTTP、WebSocket、SSH)都汇入同一个解析器,任何能够发送 CLI 命令的客户端都可以读取 controller 上的任意文件。修复补丁(commit `554f0378`)添加了一个默认值为 `false` 的常量 `ALLOW_AT_SYNTAX`,从而关闭了该展开行为。 这不是经典的路径遍历:这里没有 `../`,也没有需要逃逸的基础目录。路径是被直接打开的。在结果层面上,这是一个任意文件读取漏洞;在机制层面上,这是一个参数展开问题。 ## 仓库结构 ``` cve-2024-23897-jenkins-poc/ README.md # this file LICENSE poc.py # Python reproduction harness (all subcommands) Dockerfile.vuln # jenkins/jenkins:2.426.2-lts + matrix-auth Dockerfile.fix # jenkins/jenkins:2.426.3-lts + matrix-auth docker-compose.vuln.yml # jenkins-vuln + attacker-vuln docker-compose.fix.yml # jenkins-fix + attacker-fix init.groovy.d/ 01-create-users.groovy # bootstraps admin + readuser via matrix-auth evidence/ docker-versions.txt # host Docker + Compose versions output-vulnerable.txt # captured during `poc.py exploit` output-fixed.txt # captured during `poc.py verify-fix` report/ report.pdf # full written analysis report.tex # LaTeX source (self-contained, no external figures) ``` ## 前置条件 | 要求 | 备注 | |---|---| | Docker Engine 24 或更新版本 | 实际使用的版本记录在 `evidence/docker-versions.txt` 中 | | Docker Compose v2 | 以内置的 `docker compose` 插件形式提供 | | Python 3.8 或更新版本 | 仅使用标准库,无需 `pip install` | | 磁盘空间 | 约 1.5 GB,用于两个 Jenkins 镜像、temurin 镜像和 matrix-auth 插件 | 主机上不需要安装 JDK。Java 在攻击者容器内部运行。compose 文件固定使用 `platform: linux/amd64`,以确保这些镜像在 Apple Silicon 上的行为完全一致;这是一个运行环境上的选择,并不影响该漏洞,因为该漏洞是与平台无关的。 ## 如何运行 在仓库内部执行: ``` python3 poc.py up-vuln # build and start the vulnerable stack, fetch the CLI jar python3 poc.py place-proof # write the harmless marker file inside the controller python3 poc.py exploit # run the PoC, writes evidence/output-vulnerable.txt python3 poc.py up-fix # tear down vuln, build and start the patched stack python3 poc.py verify-fix # run the same PoC, writes evidence/output-fixed.txt python3 poc.py teardown # stop and remove both stacks ``` 首次运行需要几分钟(拉取镜像并安装插件)。随后的运行速度会快得多。 当捕获的输出中出现标记字符串 `POC-PROOF-LINE` 时(表明发生了泄露),`poc.py exploit` 即为通过。`poc.py verify-fix` 的通过条件则相反:必须不存在该标记。这两个子命令在失败时均会以非零状态退出,因此这两个证据文件及其退出状态本身就是测试结果。 ## 架构 两个 compose 文件都在同一个 Docker 网络上运行相同的两个服务:一个 Jenkins controller(受害者)和一个轻量级的 `eclipse-temurin:17-jre` 攻击者容器。 `poc.py` 在主机上运行并通过 `subprocess` 驱动 Docker,但实际的 `java -jar jenkins-cli.jar ...` 调用是在攻击者容器内运行的。 攻击者无法访问 Jenkins 数据卷;它只能通过网络访问 controller,就像远程攻击者一样。 ## 授权模型 `init.groovy.d/01-create-users.groovy` 使用 matrix-auth 插件创建了两个具有刻意设置的不同权限的账户: | 账户 | 权限 | 在 PoC 中的角色 | |---|---|---| | `admin` | `Jenkins.ADMINISTER` | 仅为满足“至少有一个管理员”的条件而存在,从未用于攻击 | | `readuser` | 仅具有 `Jenkins.READ` (Overall/Read) | 经过身份验证的攻击者 | | anonymous | 无 | 未经身份验证的攻击者 | 这重现了官方安全公告中 Overall/Read 与 anonymous 对立的确切划分,而不是 Jenkins 核心默认配置所产生的那种较宽松的“任何登录用户与 anonymous 对立”的情况。因此,完整的文件泄露仅归因于该 CVE,而非管理权限的滥用。 ## 结果 PoC 对每个 controller 运行了四种场景。下表总结了 A/B 对比结果;完整的捕获内容位于 `evidence/` 目录中。 | 观察结果 | 存在漏洞的 2.426.2 | 已修复的 2.426.3 | |---|---|---| | `@`-token 处理方式 | 被展开为文件内容 | 被视为字面字符串 | | readuser + `connect-node` | 完整文件泄露(3 行中的 3 行) | 无泄露 | | anonymous + `who-am-i` / `help` | 通过 auth gate 之前的解析器错误导致部分泄露(第一行) | 无泄露 | | 输出中的 `POC-PROOF-LINE` 标记 | 存在 | 不存在 | 这两列之间唯一变化的变量是 Jenkins 的次要版本,以及随之而来的补丁后 `atSyntax` 的默认值。因此,截然相反的结果将这种行为变化归因于 commit `554f0378` 中的解析器修复。 ## 为什么 Docker 无法修复该 Bug 在容器中运行 Jenkins 并不能作为一种缓解措施。解析器以 Jenkins JVM 的权限读取文件,而这些文件位于与凭据存储相同的容器文件系统中。容器边界保护的是主机免受 Jenkins 进程的影响,而不是保护 Jenkins 进程免受其自身的攻击。 这里的 Docker 设置仅用于演示沙盒,仅此而已。 ## 缓解措施 升级到已修复的版本:2.442(每周版),或 2.426.3 或 2.440.1 (LTS),这些版本均发布于 2024 年 1 月 24 日。如果无法立即升级,请将系统属性 `hudson.cli.CLICommand.allowAtSyntax` 保持未设置状态(使用其默认值),这会使 `ALLOW_AT_SYNTAX` 保持为 false 并禁用展开。禁用单个 CLI 传输方式仅是一种临时缓解措施,因为这三种方式最终都汇聚到同一个解析器。 ## 安全提示 所有操作均在本地 Docker 环境中针对一个无害的三行标记文件(`/tmp/poc-proof.txt`,由测试框架自行创建)运行。不会扫描或联系任何公共 Jenkins 实例,也不会读取任何真正的密钥(如 `secrets/master.key` 或 `credentials.xml`)。 ## 参考资料 - Jenkins 安全公告 2024-01-24 (SECURITY-3314, SECURITY-3315): https://www.jenkins.io/security/advisory/2024-01-24/ - CVE-2024-23897 的 NVD 条目: https://nvd.nist.gov/vuln/detail/CVE-2024-23897 - jenkinsci/jenkins 上的修复 commit `554f0378`: https://github.com/jenkinsci/jenkins/commit/554f03782057c499c49bbb06575f0d28b5200edb - args4j (`ParserProperties.withAtSyntax`): https://github.com/kohsuke/args4j - Zscaler ThreatLabz 分析文章(从文件读取到 RCE): https://www.zscaler.com/blogs/security-research/jenkins-arbitrary-file-leak-vulnerability-cve-2024-23897-can-lead-rce
标签:Docker, Jenkins, JS文件枚举, Python, 人体姿态估计, 安全漏洞, 安全防御评估, 无后门, 本地环境搭建, 漏洞复现, 版权保护, 请求拦截, 逆向工具