• Java反序列化之CommonsCollections(CC1)基础篇



    前言

          本文包括:Java反序列化之CommonsCollections篇(CC1)的一些基础知识概念。


    一、基本简介和环境

        1.Apache Commons Collections简介

          Apache Commons Collections是Java应用开发中一个非常常用的工具库,它添加了许多强大的数据结构,简化了Java应用程序的开发,已经成为Java处理集合数据的公认标准。像许多常见的应用如Weblogic、WebSphere、Jboss、Jenkins等都使用了Apache Commons Collections工具库,当该工具库出现反序列化漏洞时,这些应用也受到了影响,这也是反序列化漏洞如此严重的原因。

        2.漏洞原理

          Apache Commons Collections 中提供了一个Transformer的类,这个接口的功能就是将一个对象转换为另外一个对象。
          然后整个利用链是需要重点关注这个类。

    • invokeTransformer:通过反射,返回一个对象。
    • ChainedTransformer:把transformer连接成一条链,对一个对象依次通过链条内的每一个transformer进行转换。
    • ConstantTransformer:把一个对象转化为常量,并返回。

        3.本文环境版本

          IDEA版本为:2021.1.3
          jdk版本为8u65,因为CC1的利用链在8u71的版本就修复了。下载地址:https://www.oracle.com/java/technologies/javase/javase8-archive-downloads.html
          Maven版本为:3.6.3,下载链接:https://archive.apache.org/dist/maven/maven-3/3.6.3/binaries/
          本文CommonsCollections的版本是3.2.1。3.1-3.21之间都可以。

    >
        <!-- https://mvnrepository.com/artifact/commons-collections/commons-collections -->
        
            commons-collections
            commons-collections
            3.2.1
        
    >
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

          为方便调试需加入java源码,下载地址为:https://hg.openjdk.java.net/jdk8u/jdk8u/jdk/rev/af660750b2f4。

        4.搭建过程

         1)下载openjdk对应版本的源码。并解压成文件夹。
    在这里插入图片描述
    在这里插入图片描述
         2)把jdk1.8.0_65文件夹中的src.zip解压。然后把下载的openjdk中的 jdk-af660750b2f4\src\share\classes的sun文件夹拷贝到解压的 src文件夹中。
    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述
         3)IDEA创建maven项目,Project SDK选择你下载的jdk8u65的路径。然后下一步写你项目的名字和存放路径创建即可。
    在这里插入图片描述
         4)创建好后,选择ProjectStructure项目结构。
    在这里插入图片描述
         5)选择SDKs点击Sourcepath添加src最后应用保存即可。
    在这里插入图片描述
         6)然后pom.xml文件中添加commons collections 3.2.1版本,直接下载资或者右键重新加载项目下载资源都可以。
    在这里插入图片描述
    在这里插入图片描述

    二、基础学习

       1.命令执行的方式

         1)JAVA中正常的命令执行。

    public class CC1 {
        public static void main(String[] atgs) throws Exception
        {
            // 1.先弹个计算器
            Runtime.getRuntime().exec("calc");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述
         2)利用一个普通的反射执行命令。

    import java.lang.reflect.Method;
    
    public class CC1 {
        public static void main(String[] atgs) throws Exception
        {
    //        // 1.先弹个计算器
    //        Runtime.getRuntime().exec("calc");
    
    
            // 2.写一个普通的反射
            Runtime r = Runtime.getRuntime();
            // 获取Runtime的class
            Class c = Runtime.class;
            // 获取Runtime的exec方法
            Method execMethod = c.getMethod("exec",String.class);
            // 调用exec方法
            execMethod.invoke(r,"calc");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在这里插入图片描述

       2.CC1链中涉及到的类的简介

         1)Transformer类是Commons Collections中自定义的一组功能类。Transformer类的功能就是接收一个对象然后调用transform方法,对这个对象做一些操作。

    public interface Transformer {
        public Object transform(Object input);
    }
    
    • 1
    • 2
    • 3

         2)InvokerTransformer也是实现了Transformer接口的一个类,它可以执行任意的方法。在创建InvokerTransformer对象时,需要传入三个参数,第一个是想要执行的方法名,第二个是这个方法所需要参数的参数类型,第三个是这个方法中具体的参数;当调用InvokerTransformer类中的transform方法时,将会执行我们想要执行的方法,那具体是哪个对象中的方法呢?是通过transform方法中的参数传入进去的,接下来看看代码,首先是构造方法:

    public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
        super();
        iMethodName = methodName;
        iParamTypes = paramTypes;
        iArgs = args;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

          就是将三个参数做一个赋值而已, 接下来就来看它的回调transform方法。

    public Object transform(Object input) {
        if (input == null) {
            return null;
     }
     try {
         Class cls = input.getClass();
         Method method = cls.getMethod(iMethodName, iParamTypes);
         return method.invoke(input, iArgs);}
        catch (NoSuchMethodException ex) {
            throw new FunctorException("InvokerTransformer: The method '" +iMethodName + "' on '" + input.getClass() + "' does not exist");} 
        catch (IllegalAccessException ex) {
            throw new FunctorException("InvokerTransformer: The method '" +iMethodName + "' on '" + input.getClass() + "' cannot be accessed");} 
        catch (InvocationTargetException ex) {
            throw new FunctorException("InvokerTransformer: The method '" +iMethodName + "' on '" + input.getClass() + "' threw an exception", ex);}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

          这样它就可以执行input对象的iMethodName⽅法了,原理其实也挺简单,就是利用反射先获取这个方法,然后再执行input对象中的这个方法就行了
         3)TransformedMap这个类中封装了一个decorate方法,它是用来修饰Java中的标准数据结构Map,当向被修饰过的Map中添加新元素时,它就会执行一个回调函数;这个回调并不是传统意义上的回调函数,而是相当于执行一个对象里面的transform方法,前提是这个对象的类要实现了Transformer接口。参照下面代码可以看出来其中,keyTransformer是处理新元素的Key的回调,valueTransformer是处理新元素的value的回调,当我们向outerMap中添加新元素时,它就会调用keyTransformer或者valueTransformer里面的transform方法。

    Map innerMap = new HashMap();
    Map outerMap = TransformedMap.decorate(innerMap, keyTransformer, valueTransformer);
    
    • 1
    • 2

         4)ConstantTransformer同样是一个实现了Transformer接口的一个类,这个类很简单,它有一个带参的构造函数,而参数类型是对象,当你传入一个对象后,它会在transform方法中再将这个对象返回出来。就是将传入的对象constantToReturn在transform方法中返回

    public ConstantTransformer(Object constantToReturn) {
        super();
        iConstant = constantToReturn;
    }
    public Object transform(Object input) {
        return iConstant;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

         5)前面讲了ConstantTransformer和InvokerTransformer两个类,一个可以返回一个类的对象,另一个可以执行对象中的方法,那么我们是不是就可以尝试执行Runtime类中的exec方法呢?很显然,我们还需要一个类将这两个串起来,让ConstantTransformer类返回的对象,能作为参数,进入到InvokerTransformer类的transform方法中,这样就可以了,这时候就需要拿出我们的ChainedTransformer类了;ChainedTransformer类同样也是实现了Transformer接口的一个类,它就是将内部多个实现了Transformer接口的类串在了一起,并且将前一个回调函数transform返回的结果,作为后一个回调函数transform的参数传入,代码如下,挺简单的一个逻辑,就是不停的调transform

    public ChainedTransformer(Transformer[] transformers) {
        super();
        iTransformers = transformers;
    }
    public Object transform(Object object) {
        for (int i = 0; i < iTransformers.length; i++) {
            object = iTransformers[i].transform(object);
            }
        return object;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述

  • 相关阅读:
    全网首发 黑马高端课程,仅限老学员免费领取
    SSL证书验证失败
    【设计一个缓存--针对各种类型的缓存】
    微软疑断自由软件开发者“活路”,禁止在微软商店发布商业开源
    性能优化之懒加载 - 基于观察者模式和单例模式的实现
    【李宏毅】机器学习-RNN
    【STM32】学习笔记-SPI通信
    Linux内核源码中最常见的数据结构之【hlist_head】
    MySQL8.0 索引优化-invisible index
    规则引擎集成新的可观测性框架
  • 原文地址:https://blog.csdn.net/qq_44029310/article/details/127624206