Jenkins CLI任意文件读取漏洞CVE-2024-23897原理与实战复现 📅 2026/6/25 15:12:15 1. 项目概述一次典型的供应链组件漏洞实战最近在安全圈里Jenkins 的 CVE-2024-23897 这个漏洞讨论得挺热。简单来说这是一个存在于 Jenkins 命令行接口CLI中的任意文件读取漏洞。攻击者能够利用这个漏洞在未授权或低权限的情况下读取 Jenkins 控制器服务器文件系统上的任意文件。对于任何一个依赖 Jenkins 做持续集成/持续部署CI/CD的团队来说这都不是个小问题因为它直接威胁到了构建服务器上可能存放的敏感信息比如源码、配置文件、密钥、数据库凭证等等。我之所以花时间把这个漏洞的复现过程完整走一遍并记录下来是因为 Jenkins 在 DevOps 流水线中的地位太核心了。很多企业的核心代码编译、测试、部署都挂在这上面。这个漏洞的利用门槛相对不高但造成的潜在影响却可以很大。通过亲手复现我们不仅能理解漏洞的成因和利用方式更能直观地感受到在真实环境中一个配置不当或未及时更新的 Jenkins 实例会带来多大的风险。这篇文章我就以一个安全研究者的视角带你从零开始搭建靶场、分析原理、完成利用并最终探讨加固方案。无论你是安全工程师想了解漏洞细节还是运维人员想评估自身系统风险都能从中获得可以直接参考的实操经验。2. 漏洞原理深度剖析CLI协议与参数解析的致命缺陷要理解 CVE-2024-23897我们必须先钻进 Jenkins CLI 的工作机制里看看。Jenkins 提供了一个命令行客户端通常是jenkins-cli.jar允许用户通过命令行与 Jenkins 服务器进行交互执行各种任务比如创建任务、触发构建、管理插件等。这个 CLI 与服务器之间的通信基于一种自定义的、二进制的协议。2.1 CLI 协议与参数处理流程当你在命令行中执行类似java -jar jenkins-cli.jar -s http://your-jenkins command arg1 arg2的命令时客户端会将这些参数打包通过 HTTP 发送给 Jenkins 服务器的/cli端点。服务器端有一个关键的类负责处理这些传入的参数hudson.cli.CLICommand的main方法。这个方法会解析命令行参数并将其转换为命令对象可以理解的格式。漏洞的根源就出现在参数解析的这个环节。在解析参数时如果参数以字符开头Jenkins 会将其后续的内容解释为一个文件路径并尝试读取该文件的内容将其作为参数值注入到命令中。这个设计的初衷可能是为了方便用户从文件中读取复杂的参数比如一个很长的脚本。然而问题在于这个文件读取操作没有进行充分的路径校验和权限控制。2.2 漏洞触发的关键路径攻击者可以构造一个特殊的参数例如/etc/passwd。当 Jenkins 服务器特别是 2.441 版本之前在某些特定配置下处理这个参数时它会尝试去读取服务器本地文件系统上的/etc/passwd文件并将文件内容作为参数值。更危险的是由于参数解析逻辑的缺陷在读取文件过程中服务器会将其中的换行符\n十六进制0x0A作为分隔符处理。这导致服务器在读取文件时会逐行将文件内容输出到错误流或作为响应的一部分返回给客户端。简单来说攻击者发送/etc/passwdJenkins 服务器不仅会去读这个文件还会在解析时把文件内容“泄露”出来。这就实现了任意文件读取。影响版本主要涵盖 Jenkins 2.441 版本之前并且启用了 CLI 功能默认是启用的的实例。注意这里需要澄清一个常见的误解。这个漏洞的利用并不总是需要认证。在某些配置下例如早期版本或特定安全设置未启用时攻击者可以在未授权的情况下直接利用。但在另一些配置下如启用了“通过SSH执行CLI命令”或要求认证的配置可能需要低权限的账户。不过在安全评估中我们通常以最坏情况即未授权可利用为前提。2.3 与类似漏洞的对比思考看到“任意文件读取”很多朋友可能会想到其他一些经典漏洞比如某些Web框架的目录遍历Path Traversal。CVE-2024-23897 的特殊性在于它发生在 Jenkins 这个特定应用的、非Web的协议层CLI协议。它不依赖于Web请求参数中的../序列而是利用了应用自身对命令行参数解析逻辑的信任。这提醒我们在评估应用安全时不能只盯着常见的Web入口点如HTTP API、表单那些用于管理、维护、集成的后台接口和协议往往因为曝光度低而隐藏着更深的风险。3. 靶场环境搭建与工具准备理论分析完了我们动手来搭建一个可复现的漏洞环境。最安全、最方便的方式当然是使用 Docker。3.1 使用 Docker 快速搭建漏洞版本 Jenkins我们选择拉取一个明确受影响的 Jenkins 版本镜像例如jenkins/jenkins:2.440。这个版本在漏洞影响范围内且易于获取。# 拉取特定版本的 Jenkins 镜像 docker pull jenkins/jenkins:2.440 # 运行 Jenkins 容器 # -p 8080:8080 将容器的8080端口映射到宿主机 # -p 50000:50000 用于 Jenkins agent 的连接 # -v jenkins-data:/var/jenkins_home 将数据卷挂载出来避免容器删除后数据丢失 # --name vulnerable-jenkins 给容器起个名字 docker run -d -p 8080:8080 -p 50000:50000 -v jenkins-data:/var/jenkins_home --name vulnerable-jenkins jenkins/jenkins:2.440执行完上述命令后访问http://你的宿主机IP:8080。你会看到 Jenkins 的初始化页面按照提示完成安装需要从容器日志中获取初始管理员密码。为了复现漏洞在安装过程中我们选择“安装推荐的插件”即可。3.2 获取 Jenkins CLI 客户端漏洞利用需要jenkins-cli.jar文件。这个文件可以从正在运行的 Jenkins 服务器上直接下载。# 从你的 Jenkins 服务器下载 CLI 客户端 wget http://localhost:8080/jnlpJars/jenkins-cli.jar或者你也可以通过浏览器访问http://localhost:8080/jnlpJars/jenkins-cli.jar来下载。确保这个 jar 包和你靶场 Jenkins 的版本一致虽然跨小版本有时也能用但为了减少干扰最好保持一致。3.3 辅助工具与脚本准备单纯使用原始的jenkins-cli.jar进行利用需要处理二进制协议比较麻烦。社区已经出现了很多优秀的工具来简化利用过程。这里我推荐使用一个用 Go 语言编写的开源工具它封装了协议交互的细节让我们可以像使用普通命令行工具一样进行利用。你可以从 GitHub 上搜索相关项目进行下载和编译。例如一个典型的利用工具可能被命名为jenkins-cli-exploit或类似。使用前请务必在独立的测试环境中进行并遵守相关法律法规。# 假设工具名为 exploit_jenkins_cli # 查看帮助信息了解使用方法 ./exploit_jenkins_cli -h通常这类工具需要你提供目标 Jenkins 的 URL以及你想要读取的文件路径。3.4 环境验证与注意事项在开始利用前我们先验证环境是否正常。Jenkins 服务状态访问http://localhost:8080确保 Jenkins 已启动并可以登录。CLI 基础功能尝试一个不需要认证的简单命令检查 CLI 是否可用。java -jar jenkins-cli.jar -s http://localhost:8080 help如果返回命令列表或提示需要认证说明 CLI 端点是可以访问的。如果连接被拒绝请检查防火墙或 Docker 端口映射。实操心得在 Docker 环境中复现漏洞是最佳实践。它保证了环境的隔离性和可重复性。完成后一个docker stop和docker rm就能清理干净不会影响宿主机。务必记住所有操作仅限于你自己搭建的靶机环境。4. 漏洞复现实操步骤详解环境准备好了我们开始一步步复现这个漏洞。我会分别演示使用原始jenkins-cli.jar的“硬核”方法和使用现成利用工具的“快捷”方法。4.1 方法一使用原始 jenkins-cli.jar 进行利用这种方法有助于我们理解底层交互但过程稍显复杂因为我们需要模拟 CLI 协议的二进制通信。首先我们需要知道 Jenkins 服务器支持哪些 CLI 命令。我们可以发送一个help命令的请求包并观察其原始流量。使用tcpdump或Wireshark抓包或者使用一个能发送原始 HTTP 请求的工具如netcat或 Python 脚本来构建请求。由于 CLI 协议是二进制的手动构造数据包比较繁琐。一个更简单的思路是利用某些命令如groovy命令如果配置不当可能允许执行脚本。但 CVE-2024-23897 的直接利用点在于参数解析而非命令执行。因此社区研究者发现可以通过发送一个精心构造的、包含符号的参数序列来触发文件读取。实际上完整的利用链涉及对hudson.cli.CLICommand连接、协议握手、然后发送命令报文的过程。对于只想验证漏洞是否存在的情况我更推荐使用下面封装好的工具。4.2 方法二使用专用漏洞利用工具推荐我们以假设的exploit_jenkins_cli工具为例。它的用法通常非常直观。# 基本语法读取单个文件 ./exploit_jenkins_cli -u http://target-jenkins:8080 -f /etc/passwd # 如果 Jenkins 需要认证例如启用了“通过SSH执行CLI命令”并配置了密钥 ./exploit_jenkins_cli -u http://target-jenkins:8080 -f /etc/shadow --user username --key /path/to/private/key # 批量读取文件列表 ./exploit_jenkins_cli -u http://target-jenkins:8080 -l file_list.txt假设我们的靶场地址是http://localhost:8080我们尝试读取 Linux 系统上经典的敏感文件/etc/passwd。./exploit_jenkins_cli -u http://localhost:8080 -f /etc/passwd如果漏洞存在且环境配置允许未授权访问你将在终端上看到/etc/passwd文件的内容被打印出来。让我们解读一下输出你看到的应该是一个标准的 Unix 用户列表每一行类似于root:x:0:0:root:/root:/bin/bash。这证明了 Jenkins 服务器进程确实拥有读取该系统文件的权限并且漏洞成功地将文件内容返回给了我们。4.3 尝试读取更多敏感文件证明了漏洞存在后我们可以进一步探索了解在真实的 Jenkins 环境中可能泄露哪些高价值信息。Jenkins 主目录下的敏感文件# 读取 Jenkins 的初始管理员密码首次安装后 ./exploit_jenkins_cli -u http://localhost:8080 -f /var/jenkins_home/secrets/initialAdminPassword # 读取 Jenkins 的加密密钥 ./exploit_jenkins_cli -u http://localhost:8080 -f /var/jenkins_home/secrets/hudson.util.Secret # 读取 credentials.xml这里可能存储了各类密钥、密码 ./exploit_jenkins_cli -u http://localhost:8080 -f /var/jenkins_home/credentials.xml # 读取 config.xml包含 Jenkins 全局配置 ./exploit_jenkins_cli -u http://localhost:8080 -f /var/jenkins_home/config.xml # 读取用户配置文件 ./exploit_jenkins_cli -u http://localhost:8080 -f /var/jenkins_home/users/*/config.xml系统级敏感文件# 尝试读取 shadow 文件通常需要 root 权限但有时 Jenkins 可能以高权限运行 ./exploit_jenkins_cli -u http://localhost:8080 -f /etc/shadow # 读取 SSH 私钥 ./exploit_jenkins_cli -u http://localhost:8080 -f /root/.ssh/id_rsa ./exploit_jenkins_cli -u http://localhost:8080 -f /home/jenkins/.ssh/id_rsa # 读取应用配置文件可能包含数据库密码 ./exploit_jenkins_cli -u http://localhost:8080 -f /var/www/html/.env ./exploit_jenkins_cli -u http://localhost:8080 -f /app/config/application.properties利用路径遍历尝试扩大范围 虽然漏洞本身不是传统的路径遍历但我们可以尝试在后面跟相对路径或包含../的路径测试服务器对路径的解析是否有限制。./exploit_jenkins_cli -u http://localhost:8080 -f ../../../../etc/passwd ./exploit_jenkins_cli -u http://localhost:8080 -f /var/jenkins_home/../secrets/initialAdminPassword注意事项在真实的渗透测试或安全评估中读取/etc/passwd通常是证明漏洞存在的“概念验证”PoC。但后续读取credentials.xml、shadow等文件可能涉及更敏感的数据务必确保你拥有目标系统的测试授权并且所有操作在可控的隔离环境中进行。在我的靶场里这些操作都是为了理解漏洞的影响面。4.4 漏洞利用的流量特征分析作为一个防御者了解攻击流量长什么样至关重要。我们可以用 Wireshark 抓包或者通过 Jenkins 的访问日志来观察。当利用工具发起攻击时它会向 Jenkins 服务器的/cli端点发送一个 HTTP POST 请求。这个请求的 body 不是普通的表单数据而是包含特定二进制格式的 CLI 协议数据。在日志中你可能只会看到一个对/cli的 POST 请求返回状态码可能是200或500如果文件读取出错。在流量层面防御系统可以尝试检测对/cli端点的异常频繁访问。POST 请求体中包含可读的/etc/passwd、/var/jenkins_home/secrets/等字符串模式虽然主体是二进制但参数路径字符串可能以明文形式存在。来自同一源的大量、快速的400或500错误响应这可能代表攻击者在进行路径爆破。5. 漏洞修复与安全加固指南复现漏洞是为了更好地防御。对于正在使用 Jenkins 的团队必须立即采取行动。5.1 官方补丁升级这是最根本、最有效的解决方案。Jenkins 官方在漏洞披露后迅速发布了安全更新。修复版本Jenkins 2.440 版本已包含针对此漏洞的修复。强烈建议所有用户升级到Jenkins 2.440 或更高版本。升级步骤备份务必先完整备份JENKINS_HOME目录通常是/var/jenkins_home。查看升级指南访问 Jenkins 官网的升级文档根据你当前的安装方式WAR包、Docker、系统包选择对应的升级方案。执行升级Docker 用户将镜像标签改为jenkins/jenkins:2.440或latest然后重新创建容器注意挂载数据卷。WAR 包用户下载新版 WAR 包替换旧的jenkins.war重启服务。系统包用户如 Ubuntu/Debian使用包管理器更新。验证升级后访问管理界面确认版本号已更新。再次尝试之前的漏洞利用方法应该会失败或返回错误。5.2 临时缓解措施如果因为某些原因无法立即升级可以考虑以下临时缓解方案以降低风险禁用 Jenkins CLI 这是最直接的阻断方式。可以通过以下两种方法实现通过系统配置在 Jenkins 管理界面 - “系统配置” - “全局安全配置”中找到 “SSH Server” 和 “CLI over SSH” 选项将其禁用。同时确保 “TCP port for JNLP agents” 相关设置是受控的。通过 Java 系统属性在启动 Jenkins 时添加-Dhudson.CLI.disabledtrue参数。这将在全局禁用 CLI 功能。注意禁用 CLI 可能会影响一些依赖于 CLI 的自动化脚本或插件。请评估对现有流程的影响。严格网络访问控制将 Jenkins 控制器的管理界面默认8080端口和 CLI 端口如果独立设置限制在特定的、可信的 IP 地址或 VPN 网络内访问。绝不应对公网开放。使用反向代理如 Nginx, Apache为 Jenkins 添加一层防护可以配置额外的认证、请求过滤或 WAF 规则。强化 Jenkins 自身权限确保运行 Jenkins 的操作系统用户如jenkins具有最小权限原则。不要使用root用户运行 Jenkins。定期审计JENKINS_HOME目录下的文件权限确保敏感文件如secrets/目录下的文件只有 Jenkins 进程用户可以读写。5.3 长期安全实践建议打补丁和临时屏蔽只是“治标”建立良好的安全习惯才能“治本”。订阅安全公告关注 Jenkins 官方的安全公告邮件列表或 RSS。CVE-2024-23897 这类严重漏洞官方会第一时间发布通告。建立定期更新机制将 Jenkins 及其插件的更新纳入常规的运维日历。非长期支持LTS版本更新频繁建议使用 LTS 版本并规划好每个季度的升级窗口。最小化安装与权限安装时只安装必需的插件。每个插件都可能引入新的攻击面。定期审查并卸载不再使用的插件。凭证管理充分利用 Jenkins 的 “Credentials” 功能管理密钥和密码避免在任务配置或脚本中硬编码敏感信息。定期轮换凭证。日志与监控启用并集中收集 Jenkins 的访问日志和系统日志。设置告警规则监控对/cli端点的异常访问、大量的错误登录尝试等。6. 漏洞复现过程中的常见问题与排查在复现过程中你可能会遇到一些问题。这里我总结几个常见的坑和解决办法。6.1 工具连接失败或超时症状执行利用命令后长时间无响应或提示 “Connection refused”、“Timeout”。排查检查目标地址和端口确认http://localhost:8080是否正确Jenkins 服务是否真的在运行。docker ps查看容器状态docker logs vulnerable-jenkins查看容器日志。检查防火墙宿主机防火墙是否阻止了 8080 端口的访问如果是远程靶机确保网络可达。检查 Jenkins 访问模式某些 Jenkins 安装可能配置了 HTTPS 或者上下文路径如http://host:8080/jenkins/。确保 URL 完整正确。CLI 端点是否可用直接在浏览器中访问http://localhost:8080/cli可能会下载一个jenkins-cli.jar或返回一个简单页面。如果返回 404可能是 CLI 被禁用或版本差异。6.2 漏洞利用成功但读取不到预期文件症状工具返回成功如 HTTP 200但返回的内容是空、错误信息而不是文件内容。排查文件路径是否正确确认你要读取的文件在目标 Jenkins 服务器上是否存在。Docker 容器内的路径可能与宿主机不同。例如在容器内Jenkins 主目录是/var/jenkins_home。权限不足Jenkins 进程用户可能没有读取目标文件的权限。尝试读取一个全局可读的文件如/etc/passwd来验证。如果/etc/passwd能读但/etc/shadow不能读那就是权限问题。文件编码或内容如果文件是二进制文件输出到终端可能会显示乱码。可以尝试将输出重定向到文件然后用file命令检查类型或用hexdump查看。工具兼容性你使用的利用工具可能对特定 Jenkins 版本或响应格式处理不佳。尝试换一个工具或者用最原始的抓包方式验证服务器是否返回了文件内容数据。6.3 返回错误 “Anonymous access is not allowed” 或要求认证症状工具返回错误提示需要认证。排查Jenkins 安全配置你的靶场 Jenkins 可能已经配置了“任何用户可以做任何事”以外的安全策略。进入 “系统配置” - “全局安全配置”查看 “安全域” 和 “授权策略”。如果启用了如 “Logged-in users can do anything” 或更严格的策略那么未授权的 CLI 访问会被拒绝。为复现调整配置为了复现最典型的未授权利用场景你可以临时将授权策略改为 “Anyone can do anything”。请注意这仅用于测试环境完成后务必改回或销毁环境。使用凭证进行利用如果不想降低安全配置而你的测试账户拥有足够权限一些利用工具支持通过--user和--password或--key参数提供认证信息。你需要先创建一个测试用户并赋予相应权限。6.4 升级后漏洞依然疑似存在症状升级到 2.440 或更高版本后用旧版工具测试可能仍有一些响应但内容不同。排查确认版本登录 Jenkins 管理界面首页查看确切的版本号。理解修复原理官方的修复是在参数解析逻辑中加强了对文件路径的校验和限制防止读取预期外的文件。升级后尝试读取/etc/passwd应该返回明确的错误信息如 “Invalid command” 或 “Access denied”而不是文件内容。清理缓存确保你使用的jenkins-cli.jar客户端也是从新版本服务器下载的避免兼容性问题。彻底重启确保 Jenkins 服务在升级后已经完全重启。7. 从防御视角看漏洞的深度利用与检测站在蓝队防御方的角度我们不仅要会修还要知道攻击者会怎么玩出花来这样才能更好地布防。7.1 攻击链拓展从信息泄露到权限提升一个成熟的攻击者不会满足于读几个文件。CVE-2024-23897 作为任意文件读取漏洞往往是攻击链的起点。信息收集读取/etc/passwd了解系统用户读取 Jenkins 的config.xml、credentials.xml、secrets/目录下的文件获取数据库连接字符串、云服务密钥、Git仓库凭证、SSH私钥等。横向移动利用获取到的 SSH 私钥尝试登录服务器上的其他账户或网络内的其他机器。权限提升如果读取到了shadow文件且 Jenkins 以高权限运行可以尝试离线破解密码哈希。或者在credentials.xml中发现了高权限的 Jenkins API Token攻击者可以直接以该用户身份操作 Jenkins创建恶意任务、执行系统命令。持久化在 Jenkins 上创建后门任务或修改现有任务注入恶意脚本确保即使漏洞被修复攻击者仍能维持访问。7.2 基于流量的检测规则思路对于安全运营团队可以在 WAF、IDS 或网络流量分析设备上部署检测规则。请求特征检测对/cli端点的 POST 请求特别是请求体Body大小异常、或包含可读的/etc/、/var/jenkins_home/、C:\Windows\Windows路径等模式字符串的请求。注意由于是二进制协议字符串可能不是完整的可以尝试检测字符后跟路径分隔符/或\的模式。响应特征检测来自/cli端点的响应中是否包含常见的文件头内容。例如Linux/etc/passwd文件响应中会包含多行root:x:0:0:这样的模式/etc/shadow的行通常以用户名和$开头的哈希值开头。可以编写相应的正则表达式进行匹配。行为基线在正常业务中对/cli的访问应该非常少且来源固定如自动化服务器。建立访问频率和来源的基线对偏离基线的访问进行告警。7.3 主机侧与日志侧的检测Jenkins 日志检查$JENKINS_HOME/logs/目录下的日志文件。虽然漏洞利用可能不会留下特别明显的错误日志但结合时间点观察是否有异常的 CLI 连接记录。系统进程监控 Jenkins Java 进程的文件读取操作。在 Linux 上可以使用auditd或strace仅用于调试来监控 Jenkins 进程对敏感文件如/etc/passwd,/etc/shadow,$JENKINS_HOME/secrets/的open系统调用。文件完整性监控对$JENKINS_HOME下的关键配置文件如config.xml,credentials.xml实施文件完整性监控FIM任何未授权的修改都应触发告警。漏洞复现不只是为了“能攻击”更重要的是通过攻击者的视角审视自身系统的薄弱环节。CVE-2024-23897 给所有 Jenkins 用户敲响了警钟即使是成熟、广泛使用的开源基础设施软件其非核心功能模块也可能存在严重的设计缺陷。建立主动的漏洞监控、及时的补丁管理、深度的防御检测和最小化的权限体系才是应对这类供应链安全风险的持久之道。在我的测试中升级到最新版本并禁用不必要的 CLI 访问后原有的利用方式便完全失效这再次印证了及时跟进官方更新是成本最低、效果最显著的安全措施。