0x00、前言
到Commons BeanUtils组件利用链分析,主要是CB1链以及CB1链无依赖CC组件形成的CB2链的分析
0x01、CommonsBeanutils描述
Apache Commons BeanUtils 是一个 Java 库,作为更大的 Apache Commons 项目的一部分。它提供了一组实用方法和类,用于操作 Java Bean。Java Bean 是一种遵循特定命名约定的 Java 类,具有一组属性和访问它们的 getter 和 setter 方法。
Commons BeanUtils 主要功能包括:
动态操作 Java Bean 属性:通过使用 Java 反射和内省机制,BeanUtils 允许你在运行时动态地访问和修改 Java Bean 的属性。
数据类型转换:BeanUtils 提供了一组用于在各种数据类型之间进行转换的实用方法,例如将字符串转换为整数、浮点数等。
自动填充 Java Bean:通过将一个对象的属性值复制到另一个对象,BeanUtils 可以用于自动填充 Java Bean,从而简化了数据传输对象 (DTO) 和领域模型之间的转换工作。
动态创建 Java Bean 实例:BeanUtils 提供了实例化类的方法,而无需显式地调用构造函数。
支持嵌套属性:BeanUtils 支持访问嵌套属性,这意味着你可以访问和操作一个 Bean 中的另一个 Bean 的属性。
Commons BeanUtils 库在许多 Java 应用程序和框架中广泛使用,例如 Apache Struts 和 Spring Framework。它可以简化代码,提高开发效率,并有助于降低维护成本。
0x02、前置知识
templates、PriorityQueue
templates字节码、PriorityQueue优先级队列的相关知识在cc2中写过了,回顾cc2
BeanComparator
CommonsBeanutils组件的类
官方定义的作用:此比较器通过指定的bean属性比较两个bean。还可以基于嵌套的、索引的、组合的、映射的bean属性来比较bean。
也就是Bean的比较器,其中Bean理解为通过getter/setter
方式获取和赋值成员变量的类。
主要作用是通过property
字段属性来比较bean方法中返回属性,其中会通过getter/setter
来获取property
属性对应的get/set
前缀的方法,并通过反射执行
获取bean property
属性后,在进行compare
比较。
0x03、CB1分析
CB1核心就是使用CC2链,改变了触发入口点,将比较器改为了BeanComparator
漏洞版本
commons-beanutils=1.9.2
commons-collections<=3.2.1
利用环境
<dependency> |
分析
核心通过templates
加载字节码,然后设置property
属性,通过BeanComparator
比较器的getter/setter
读取property
属性并反射执行。
我这里是已经构造好POC执行,然后分析的流程,先分析过程,再最后构造POC。
跟进BeanComparator
比较器,存在property
、comparator
两个成员属性,分别代表’用于比较方法的属性名’、’比较器’
跟进compare
方法,先是判断property
属性是否存在,不存在就直接比较两个对象(这里传入的比较对象包括了templates
对象)
property
属性存在,则通过getProperty
方法getter/setter
获取对象property
真实属性
继续跟进getProperty
查看流程,调用PropertyUtilsBean.getProperty
,继续跟进
接着调用getNestedProperty
进入获取嵌套Property
属性方法
由于传入的Property
属性为普通的属性,不属于嵌套形式,因此会跳出while循环获取嵌套内容
然后判断bean
的属性,由于bean
(templates
类对象)不属于map
,并且name
(Property
属性)也不属于map
和index
类型,最后调用getSimpleProperty
方法获取真实属性
跟进getSimpleProperty
,又是同一个判断步骤,继续往下
多了个判断判断是否是动态bean类型,不属于,进入下一个代码段
通过getPropertyDescriptor
方法获取真实属性Property
跟进getPropertyDescriptor
方法,开头又是同一个判断,直接到下面代码段
通过getDescriptor
方法getter/setter
获取name
在对象中的真实属性
读取到真实方法名过后进行对对象进行方法反射调用
执行templates
的getOutputProperties
方法触发漏洞
剩下的就是如何将templates
对象传入BeanComparator
构造器的步骤了,这里就是CC2后半段的一部分,在构造POC中简述
简述下触发流程:
需要构造property
属性为getOutputProperties/newTransformer()
方法,然后将templates
对象传入compare
方法作为对象进行比较,然后BeanComparator
构造器通过getter/setter
获取对象的真实property
属性再进行反射执行触发漏洞
构造POC
首先cc2中的templates
字节码构造没变化
//创建CtClass对象容器 |
然后调用BeanComparator
构造器,并且通过反射将BeanComparator
构造器的property
属性设置为getOutputProperties/newTransformer()
方法
BeanComparator beanComparator = new BeanComparator(); |
接着就是cc2后半段,利用PriorityQueue
优先级队列将BeanComparator
构造器作为比较器,来调用BeanComparator.compare
方法
//设置优先级队列对象 |
原理:
PriorityQueue重写了反序列化步骤,调用heapify()
;
条件要求size大于2(详情查看cc2后半段分析),才能调用siftDown
方法
接着调用siftDownUsingComparator
方法
这里会调用comparator.compare
方法,通过反射setFieldValue(pq,"comparator",beanComparator);
设置了比较器,因此会调用到beanComparator.compare
方法进入上述分析的步骤
完整POC
最后加上反序列化步骤就构成了完整的poc:
public class cb1Test { |
0x04、CB2分析
利用版本
commons-beanutils=1.9.2
commons-beanutils=1.8.3
利用环境
<dependency> |
CB1依赖问题
在CB1中,调用的BeanComparator类,是直接进行声明对象调用的
BeanComparator beanComparator = new BeanComparator(); |
该调用方式直接调用BeanComparator
的无参构造方式,无参构造方式又会传递个null值去调用带一个参数的构造方法,该方法又会调用ComparableComparator.getInstance()
方法去调用public BeanComparator( String property, Comparator<?> comparator )
的构造方法
其中调用ComparableComparator.getInstance()
,调用的ComparableComparator
类为commons-collections
组件的类,意味着CB1链是依赖于CC组件的,如果目标环境不存在CC组件那么就无法使用CB1链
因此CB2链的核心变动就是BeanComparator
类的声明方式,规避使用到ComparableComparator
类作为comparator
比较器,因此只需要替换一下comparator
比较器,找一个java自带或者cb组件自带的实现了comparator
和序列化的比较器类即可
CB2分析
示例AttrCompare
类,实现了comparator
和序列化
同时不用关注该类下面的调用方法,因为BeanComparator
类的触发为BeanComparator.compare
方法中getter/setter
获取对象方法进行反射调用
因此只需要将上面的代码BeanComparator
类的声明方式换成
BeanComparator beanComparator = new BeanComparator(null, new AttrCompare()); |
其他条件不用变化,跟进查看执行,这里调用BeanComparator
类会直接调用BeanComparator( String property, Comparator<?> comparator )
的构造方法,赋值comparator
后直接跳过了调用ComparableComparator.getInstance()
的步骤
再到调用compare方法
后面在CB1分析过了,同样的步骤,通过getter/setter
获取对象方法,再通过反射调用执行该方法触发漏洞
POC
得到的POC,BeanComparator
构造参数的AttrCompare类换为其他实现comparator
和序列化的无依赖组件均可
public class cb2Test { |
0x05、总结
总体来说就是CC2(templates+链转换器+PriorityQueue)利用将入口点改变为调用BeanComparator类,在BeanComparator类进行compare比较时,会调用getter/setter javabean去获取比较对象的方法,若存在get/set对应的方法,则通过反射执行该类的该方法,其中CB1链会依赖CC组件环境,CB2将BeanComparator类调用进行了赋值comparator比较器,规避了调用CC组件的comparator比较器,因此实现了无依赖cc环境,可主要用于shiro环境的漏洞攻击
0x06、参考链接
java漫谈
https://blog.csdn.net/qq_45449318/article/details/128571962
https://mp.weixin.qq.com/s/3zvJucvcStoJMgvawkp55w