news 2026/9/21 14:07:54

CVE-2026-70426 Jenkins Remoting反序列化RCE实战:原理、复现、检测脚本与加固方案

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
CVE-2026-70426 Jenkins Remoting反序列化RCE实战:原理、复现、检测脚本与加固方案

前言

Java反序列化漏洞发展到今天,单纯的原生无过滤反序列化漏洞已经极少。各类中间件、框架都引入类白名单机制,把危险类拦截在反序列化入口。JEP-200就是Jenkins为了封堵Remoting通道反序列化攻击引入的防护,多年来被视作Jenkins控制器最重要的安全边界之一。

CVE-2026-70426(SECURITY-3911)的特殊之处,不是JEP-200白名单本身失效,而是代码异常分支里的漏校验。正常流程会走类过滤器校验,一旦类加载抛出异常,程序进入catch块直接使用父类resolveClass,跳过全部安全校验。攻击者只要拿到Agent/Connect权限或者控制Agent进程,就可以构造序列化载荷,让控制器加载核心类路径内的恶意类,在Jenkins主节点完成RCE。

很多运维、安全人员会误判这个漏洞,以为是公网直接打Jenkins页面的一键漏洞。真实攻击链路藏在CI/CD架构的控制器与Agent通信通道,属于供应链攻击的典型入口。构建任务在Agent执行,依赖包投毒、Agent账号被接管,都能变成攻击控制器的跳板。控制器一旦失陷,所有凭证仓库、代码仓库密钥、云账号、生产环境部署密钥全部暴露。

本文从第一性原理拆解漏洞,做对抗式审查,从底层代码逻辑、攻击链路、环境复现、检测脚本、临时缓解、长期加固完整落地。附带Mermaid流程图与架构图,可直接插入文章配图。所有检测脚本、验证代码可复制使用。

1 漏洞基础信息

CVE编号:CVE-2026-70426
Jenkins内部安全编号:SECURITY-3911
漏洞类型:不安全反序列化,绕过JEP-200类过滤器,RCE
CVSS:9.0 严重
漏洞组件:Jenkins Remoting通信库

1.1 受影响版本

Remoting库:≤3384.v60d89463d9e0,版本3355.3357.v931d3c992987除外
Jenkins每周版:≤2.575
Jenkins LTS长期支持版:≤2.568.1

修复版本:
Jenkins 2.576
Jenkins LTS 2.568.2
Remoting ≥3386

版本例外说明:3355.3357.v931d3c992987版本已经修复该回退分支问题,不受漏洞影响,升级排查时不要误判。

1.2 攻击前置条件(对抗式审查重点)

这个漏洞不能无授权直接远程攻击,必须满足下面任意一条:

  1. 攻击者控制Jenkins Agent代理进程,Agent上可以执行自定义代码;
  2. 攻击者账号拥有Jenkins的Agent/Connect权限,可以新建Agent节点,建立Agent到控制器的Remoting通信通道。

没有上述权限,载荷无法投递到Remoting通信通道,漏洞无法触发。很多厂商的漏洞通告简化描述,容易让人误解成公网未授权RCE,这是红队与蓝队排查时最容易踩的认知陷阱。

漏洞载荷的限制:只能使用Jenkins核心classpath内的类,插件自带依赖类不能被反序列化。攻击者只能利用JDK原生类、Jenkins core内置类构造gadget链,不能直接加载第三方插件的类。这个边界决定gadget选型范围,也限制攻击载荷的构造思路。

2 Jenkins Remoting与JEP-200底层原理

2.1 Remoting通信架构

Jenkins控制器(Controller)和Agent节点依靠Remoting库完成跨节点通信。Agent执行构建任务,把执行状态、返回对象序列化后通过TCP通道传给控制器;控制器下发任务对象到Agent。整个通道大量使用Java原生序列化传输对象。

flowchart LR A[Jenkins Controller] <-->|Remoting TCP通道 Java序列化对象| B[Jenkins Agent] A --> C[JEP-200类过滤器<br/>反序列化前校验类白名单] C --> D[正常类加载流程] D --> E[业务逻辑执行]

控制器在接收Agent发来的序列化对象时,默认启用JEP-200类过滤器。过滤器维护白名单,只有可信类才允许被反序列化,阻断经典Java反序列化gadget。

JEP-200在2018年正式落地,把Jenkins Remoting从黑名单防护切换为白名单防护。在这之前,Jenkins多次出现Remoting通道反序列化RCE。JEP-200上线后,安全业界普遍认为Agent到控制器的序列化攻击面基本关闭。

2.2 正常resolveClass流程

Remoting自定义ObjectInputStreamEx继承原生ObjectInputStream,重写resolveClass方法。

  1. 读取序列化流中的类名称;
  2. 在try代码块内尝试使用自定义类加载器加载目标类;
  3. 加载成功,调用filter.check(),JEP-200过滤器校验类是否在白名单;
  4. 校验通过,返回Class对象,完成反序列化;
  5. 校验失败,抛出异常,终止反序列化。

2.3 漏洞:异常catch分支的回退路径无过滤

漏洞根源在两处代码:ObjectInputStreamEx.resolveClassMultiClassLoaderSerializer$Input.resolveClass
try块内加载类发生ClassNotFoundException,代码捕获异常,直接调用super.resolveClass
super.resolveClass是父类ObjectInputStream原生方法,完全没有执行JEP-200 filter校验

flowchart TD S[进入resolveClass] T[try 自定义类加载器加载类] F{加载成功?} OK[执行JEP-200 filter.check<br/>白名单校验] ENDOK[返回Class,继续反序列化] FAIL[捕获ClassNotFoundException] BYPASS[调用super.resolveClass<br/>无JEP-200校验] ENDBYPASS[返回Class,继续反序列化] S --> T T --> F F --成功--> OK --> ENDOK F --失败--> FAIL --> BYPASS --> ENDBYPASS

攻击者的目标就是主动制造ClassNotFoundException,迫使代码进入这个未校验的回退分支。

实现思路:构造序列化数据,让第一次类加载失败。例如传入空类加载器、伪造类加载标记,触发异常,走fallback路径。此时控制器使用控制器自身类加载器加载目标类,不再经过JEP-200白名单。

第一性原理视角:安全校验只写在主逻辑,异常分支没有做同等校验。安全编码里最常见的缺陷,防护逻辑没有覆盖全部代码路径。对抗审查的核心思路:不要只看正常业务路径,遍历所有异常捕获分支。

3 攻击完整链路拆解

  1. 攻击者拿到Agent执行权限或者Agent/Connect权限,创建受控Agent节点,建立Agent到Controller的Remoting TCP通信通道;
  2. 构造恶意序列化对象,精心设置类加载参数,让第一次自定义类加载抛出ClassNotFoundException;
  3. 序列化数据通过Remoting通道发送给Jenkins控制器;
  4. 控制器调用ObjectInputStreamEx.resolveClass,try加载失败,进入catch;
  5. 执行super.resolveClass,跳过JEP-200校验,加载Jenkins core classpath内的gadget类;
  6. 反序列化执行readObject方法,触发gadget链,在控制器主机执行系统命令;
  7. 执行结果沿Remoting通道回传给攻击者。

攻击链路不是Web页面注入,是跨节点通信通道的序列化攻击。这个攻击面在很多企业被低估。很多企业防火墙严格限制公网访问Jenkins 8080端口,但内网Agent节点与控制器50000端口互通。一旦Agent被入侵,就可以横向移动拿下控制器。

供应链场景下,开发人员提交的构建脚本、npm/maven依赖投毒,都能在Agent执行阶段触发载荷,发起对控制器的攻击。攻击者不需要拿到Jenkins账号,只需要污染构建依赖,在构建执行阶段触发攻击。

4 源码缺陷定位与补丁分析

4.1 漏洞原始代码片段

@Override protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException { try { Class<?> c = classLoader.loadClass(desc.getName()); filter.check(desc, c); return c; } catch (ClassNotFoundException e) { return super.resolveClass(desc); } }

try块内加载成功,执行filter.check做安全校验。捕获ClassNotFoundException后,直接返回父类resolveClass结果,没有filter校验MultiClassLoaderSerializer$Input.resolveClass存在完全相同的缺陷。

4.2 官方补丁改动

补丁在catch分支同样增加filter校验逻辑。不管是try内加载成功,还是fallback到super.resolveClass拿到Class对象,都必须执行filter.check()

@Override protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException { Class<?> c; try { c = classLoader.loadClass(desc.getName()); } catch (ClassNotFoundException e) { c = super.resolveClass(desc); } filter.check(desc, c); return c; }

把filter校验移出try块,放到所有分支的公共出口。无论走哪条路径,类对象返回前都必须经过JEP-200过滤器。这个改动消除了回退分支的安全缺口。

同时Jenkins新增回归测试用例,专门模拟ClassNotFoundException场景,覆盖fallback路径,防止后续版本迭代再次引入同类漏洞。

5 本地复现环境搭建

警告:仅授权内网测试环境复现,禁止对公网未授权Jenkins实例进行测试,遵守网络安全法规。

5.1 环境清单

  • Jenkins版本:2.575(受影响版本)
  • Remoting版本:3384.v60d89463d9e0
  • JDK版本:JDK11(Jenkins推荐运行环境)
  • Agent:JNLP Agent,和控制器建立Remoting通道
  • 操作系统:Linux Ubuntu 22.04

5.2 部署步骤

  1. 下载jenkins.war 2.575版本,启动控制器
java -jar jenkins.war --httpPort=8080
  1. 初始化Jenkins,新建Agent节点,获取JNLP连接密钥;
  2. 启动Agent,连接控制器50000 JNLP端口;
  3. 在Agent端部署测试代码,构造序列化载荷,通过Remoting Channel发送至控制器。

5.3 复现关键点

  1. 必须保证Agent和控制器Remoting通道正常连通;
  2. 载荷必须触发ClassNotFoundException,进入fallback分支;
  3. gadget类必须存在于Jenkins core classpath,插件类无法使用;
  4. 反序列化成功后,命令执行在控制器进程,不是Agent。

6 检测脚本:资产扫描与漏洞检测

下面两个脚本,第一个Python脚本批量扫描内网Jenkins资产,获取版本,判断是否在受影响范围;第二个Java简易检测代码,用于验证Remoting通道通信。

6.1 Python批量资产检测脚本(可直接复制)

#!/usr/bin/env python3 # CVE-2026-70426 Jenkins 版本检测脚本 # 仅检测版本,不做漏洞利用,蓝队资产巡检使用 import requests import argparse import sys from concurrent.futures import ThreadPoolExecutor headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" } def check_jenkins(target): try: url = f"{target}/api/json" resp = requests.get(url, headers=headers, timeout=5, verify=False) if resp.status_code == 200: data = resp.json() ver = data.get("version", "") if not ver: print(f"[INFO] {target} 识别为Jenkins,未获取版本号") return # 判断版本范围 vulnerable = False try: # 每周版 <=2.575 ; LTS <=2.568.1 if ver.startswith("2."): if "." not in ver: pass parts = ver.split(".") major = int(parts[1]) if len(parts)==2: # 每周版 if major <= 575: vulnerable=True elif len(parts)==3: # LTS 2.568.1 if major ==568 and int(parts[2]) <=1: vulnerable=True except Exception: pass if vulnerable: print(f"[VULN] {target} | Version:{ver} 存在CVE-2026-70426风险") else: print(f"[SAFE] {target} | Version:{ver} 版本不受影响") except Exception as e: print(f"[ERR] {target} 连接失败 {str(e)[:60]}") def main(): parser = argparse.ArgumentParser() parser.add_argument("-f", "--file", help="目标列表文件,每行一个http://ip:port") parser.add_argument("-t", "--target", help="单个目标 http://ip:8080") parser.add_argument("-w", "--workers", default=8, type=int) args = parser.parse_args() targets = [] if args.file: with open(args.file,"r",encoding="utf-8") as f: for line in f: line = line.strip() if line: targets.append(line) if args.target: targets.append(args.target) if not targets: print("请输入 -t 单个目标或者 -f 目标文件") sys.exit(1) with ThreadPoolExecutor(max_workers=args.workers) as executor: executor.map(check_jenkins, targets) if __name__ == "__main__": main()

使用示例:

# 单个目标 python3 jenkins_cve202670426_scan.py -t [http://127.0.0.1:8080](http://127.0.0.1:8080) # 批量扫描 python3 jenkins_cve202670426_scan.py -f targets.txt

说明:脚本只做版本指纹识别,不能证明可利用。版本匹配仅代表存在漏洞条件,是否能利用还需要Agent/Connect权限或受控Agent。蓝队风险评估不能只靠版本判定,必须结合权限模型、Agent接入管控综合判断。

6.2 临时缓解措施(无法升级时)

如果业务不能立刻升级Jenkins版本,官方提供临时缓解方案,在Jenkins启动参数添加系统属性,收紧Remoting类过滤。

-Dhudson.remoting.ClassFilter=!*

这个配置默认禁止所有类跨Remoting通道反序列化,业务会受影响,需要按需添加业务白名单类。仅作为临时应急,长期方案还是升级。

7 红队攻击面拓展与对抗审查

很多安全人员只盯着Web页面,忽略Agent侧的攻击入口。我们做对抗审查,梳理真实场景的攻击入口。

7.1 攻击入口1:新增Agent节点(Agent/Connect权限)

拥有Agent/Connect权限的用户,可以新建JNLP Agent,拿到Agent连接密钥,在攻击者服务器启动Agent,接入控制器。建立Remoting通道后,发送序列化载荷。
很多企业RBAC配置粗放,普通开发账号被分配Agent/Connect权限,这是高危配置。

7.2 攻击入口2:现有Agent被入侵

Agent服务器被入侵(漏洞、弱口令、恶意构建脚本),攻击者在Agent进程内执行代码,通过已存在Remoting通道发送载荷攻击控制器。
这是供应链攻击最典型路径。构建任务执行npm、maven、pip依赖,恶意依赖包在构建阶段执行代码,接管Agent。

7.3 攻击入口3:云原生动态Agent(K8s Agent)

Kubernetes插件动态创建Agent Pod。如果构建脚本可以控制Pod,攻击者拿到Agent Pod权限,横向攻击控制器。云原生CI/CD场景下,这个攻击面经常被忽略。

7.4 对抗审查要点清单

  1. 核查用户权限,哪些账号拥有Agent/Connect权限;
  2. 审计Agent节点接入方式,是否允许外部自建Agent;
  3. 审计Agent服务器基线,Agent是否最小权限运行;
  4. 审计构建流水线,是否允许不受控依赖包下载;
  5. 网络层面:控制器50000端口是否过大范围开放访问;
  6. 日志审计:Remoting通道通信日志、类加载异常日志。

8 生产环境加固方案

8.1 优先操作:版本升级

升级Jenkins到安全版本:

  • 普通版升级 ≥2.576
  • LTS长期支持版升级 ≥2.568.2
    升级同时Remoting库同步更新至≥3386。升级前备份JENKINS_HOME目录,保存配置与凭证。

8.2 权限最小化

  1. 严格限制Agent/Connect权限,只给运维管理员,普通开发账号移除该权限;
  2. Agent运行账号最小权限,Agent进程不能拥有服务器root权限;
  3. 禁止匿名Agent接入,关闭废弃的Agent协议。

8.3 网络隔离

  1. Jenkins控制器50000 JNLP端口,仅允许可信Agent网段访问;
  2. 控制器和Agent之间网络分段,Agent所在网段不能访问控制器管理后台;
  3. 公网禁止直接暴露Agent JNLP端口。

8.4 日志与监控

开启Remoting通信日志,监控异常类加载、大量ClassNotFoundException报错。
告警规则:短时间内大量Remoting通道抛出ClassNotFoundException,大概率是漏洞探测或攻击尝试。

8.5 流水线安全加固

  1. 依赖包镜像扫描,构建前做恶意依赖检测;
  2. 流水线脚本使用SCM审批,不允许用户自由提交未审核脚本;
  3. 构建容器隔离,Agent使用一次性容器,构建结束销毁,防止持久化入侵。

9 漏洞与同类Jenkins漏洞横向对比

CVE-2024-43044同样依赖Agent/Connect权限,漏洞是文件读取。CVE-2026-70426是RCE,危害等级更高。两者攻击入口一致,都是Remoting通道。
这一组漏洞证明:Agent接入权限本质等同于控制器高风险权限。很多企业认知错误,认为Agent只是执行构建,Agent被攻陷不会影响控制器。CVE-2026-70426直接推翻这个认知边界。

JEP-200作为防护机制,设计思路没问题,但安全校验只覆盖主流程,异常分支遗漏。这是安全编码经典错误。安全校验不能假设程序永远走正常分支,所有异常捕获、降级、回退逻辑,都要复用相同安全校验逻辑。

10 漏洞未来演进预判

同类漏洞还会持续出现在序列化、类加载相关代码。开发人员处理异常时,容易省略安全校验。这类缺陷静态代码扫描很难发现,需要人工做路径遍历审计。
CI/CD平台持续成为攻击热点。攻击者越来越喜欢利用构建流水线作为跳板,供应链攻击会持续增加。Agent与控制器的信任边界,是CI/CD安全最重要的防线。很多企业只加固Web页面,忽略这个内部通信通道。

Jenkins后续安全开发,会强化全路径安全校验、增加更多回归测试覆盖异常分支。但只要Java序列化继续用于跨节点通信,类似风险就不会完全消失。长期安全方案,逐步减少跨节点Java序列化传输,替换为JSON等非序列化通信协议。

结尾互动

  1. 你的企业Jenkins是否开放了Agent/Connect权限给普通开发账号?
  2. 你们在CI/CD安全建设里,有没有把Agent当成攻击面重点管控?
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/21 12:02:03

VSS横向扩展指南:如何把视频AI处理规模从单机扩展到生产级

VSS横向扩展指南&#xff1a;如何把视频AI处理规模从单机扩展到生产级 【免费下载链接】video-search-and-summarization NVIDIA AI Blueprint for video search and summarization (VSS) is a GPU-accelerated reference architecture for building video analytics agents wi…

作者头像 李华