Java反序列化Commons-Beanutils篇-CB链
<1> 环境介绍
jdk:jdk8u65
CB:commons-beanutils 1.8.3
pom.xml 添加
1 | <dependency> |
<2> 什么是CommonsBeanutils和JavaBean?
CommonsBeanutils 是应用于 javabean 的工具,它提供了对普通Java类对象(也称为JavaBean)的一些操作方法
那 什么是JavaBean呢?
JavaBean 是一种JAVA语言写成的可重用组件,它是一个类
所谓javaBean,是指符合如下标准的Java类:
- 类是公共的
- 有一个无参的公共的构造器
- 有私有属性,且须有对应的get、set方法去设置属性
- 对于boolean类型的成员变量,允许使用”is”代替上面的”get”和”set”
在java中,有很多类定义都符合这样的规范
比如这样一个类
1 | public class Person { |
它包含了一个私有属性name,以及读取和设置这个属性的两个public方法 getName()和setName(),即getter和setter
这种 class 就是 JavaBean
用于对属性赋值的方法称为属性修改器或setter方法,用于读取属性值的方法称为属性访问器或getter方法
只有getter的属性称为只读属性(read-only),例如,定义一个age只读属性:
- 对应的读方法是int getAge()
- 无对应的写方法setAge(int)
类似的,只有setter的属性称为只写属性(write-only)
注:属性只需要定义getter和setter方法,不一定需要对应的字段,例如,child只读属性定义如下:
1 | public class Person { |
<3> CommonsBeanutils利用点
commons-beanutils中提供了一个静态方法PropertyUtils.getProperty(),可以让使用者直接调用任意JavaBean的getter方法
PropertyUtils.getProperty()传入两个参数,第一个参数为 JavaBean 实例,第二个是 JavaBean 的属性
比如:
1 | Person person = new Person("Mike"); |
除此之外, PropertyUtils.getProperty 还支持递归获取属性,比如a对象中有属性b,b对象
中有属性c,我们可以通过 PropertyUtils.getProperty(a, “b.c”); 的方式进行递归获取。通过这个
方法,使用者可以很方便地调用任意对象的getter
因此,如果getter方法存在可以rce的点可以利用的话,就存在安全问题了。
commons-beanutils里还有很多其他的辅助方法,setter等等,这里分析CB链暂时用不到 不再叙述
<4> 利用链分析
在前面的CC链中,我们提到过一种利用 TemplatesImpl 动态加载恶意类来实现rce
它的链子为:
1 | /* |
重点看:TemplatesImpl#getOutputProperties()
getOutputProperties()方法即其 _outputProperties 属性的 getter 方法是加载恶意字节码的起点,我们可以利用 前面提到的,commons-beanutils里的PropertyUtils.getProperty()去调用getter
那么往上找链子,CB链里 哪个位置调用了getProperty呢?
在之前的CC2/4的链中我们用到了java.util.PriorityQueue的readObject触发反序列化,主要是通过调用了其TransformingComparator的compare方法,进而调用了transform链的调用
而 CommonsBeanutils 利用链中核心的触发位置就是 BeanComparator.compare() 函数,当调用 BeanComparator.compare() 函数时,其内部会调用我们前面说的 getProperty 函数,进而调用 JavaBean 中对应属性的 getter 函数

这里会调用PropertyUtils.getProperty()方法 因此通过给 o1赋值构造好的templates对象,property赋值为TemplatesImpl的 outputProperties属性,即可调用 TemplatesImpl.getOutputProperties() 往下就是TemplatesImpl的利用链
那么往上找 哪里调用 compare()呢 可以利用CC2/4链中用的 PriorityQueue.readObject()
因此整体的CB链就是
1 | PriorityQueue.readObject() |
前面的CC2文章提到了,queue的size应该>2。 而add()也会执行compare由于在BeanComparator#compare() 中,如果 this.property 为空,则直接比较这两个对象。这里实际上就是对1、2进行排序。
1 | BeanComparator comparator = new BeanComparator(); |
初始化时使用正经对象,且 property 为空,这一系列操作是为了初始化的时候不要出错。然后,我们
再用反射将 property 的值设置成恶意的 outputProperties ,将add进队列里的1、2替换成恶意的
TemplateImpl 对象
1 | setFieldValue(comparator,"property","outputProperties"); |
与CC2/4 略微不同的是,还需要用反射去修改 queue属性的值,因为要控制 BeanComparator.compare()的参数为恶意templates对象
1 | setFieldValue(queue,"queue",new Object[]{templates,templates});// 设置BeanComparator.compare()的参数 |
EXP如下:
1 | import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; |

shiro550中自带CommonsBeanutils 1.8.3 和 commons-collections-3.2.1的依赖,可以利用此条链进行攻击
Java反序列化Commons-Beanutils篇-CB链
https://1vxyz.github.io/2023/07/30/Java反序列化Commons-Beanutils篇-CB链/

