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. arukas 樱花免费docker容器获取IP和端口

    arukas 樱花免费docker容器,可以安装linux系统,但是每隔一段时间会重启,重启以后IP地址和映射到公网的端口都会变,获取IP和端口,我研究了很久终于找到了C#获取IP和端口的办法,用来搭 ...

  2. 无重复字符的最长子串[双指针+哈希表] LeetCode.3

    给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度. 示例 1: 输入: "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc&qu ...

  3. ES解决bootstrap checks failed, memory locking requested for elasticsearch process but memory is not locked问题

    问题描述: ERROR: [1] bootstrap checks failed[1]: memory locking requested for elasticsearch process but ...

  4. Linux安装配置Samba共享文件系统

    Samba共享文件系统搭建与配置: 1.Samba服务端:yum install samba samba-client cifs-utilscd /etc/samba/cp smb.conf smb. ...

  5. Spring源码剖析6:Spring AOP概述

    原文出处: 五月的仓颉 我们为什么要使用 AOP 前言 一年半前写了一篇文章Spring3:AOP,是当时学习如何使用Spring AOP的时候写的,比较基础.这篇文章最后的推荐以及回复认为我写的对大 ...

  6. Example With JdbcDaoSupport

    By extended the JdbcDaoSupport, set the datasource and JdbcTemplate in your class is no longer requi ...

  7. vsftpd 530 Login incorrect问题处理

    vsftpd 530 login incorrect 的N中情况 1.密码错误. 2.检查/etc/vsftpd/vsftpd.conf配置 vim /etc/vsftpd/vsftpd.conf 看 ...

  8. [Python] Django框架入门5——静态文件、中间件、上传图片和分页

    说明: 本文主要描述Django其他的内容,涉及静态文件处理.中间件.上传文件.分页等. 开发环境:win10.Python3.5.Django1.10. 一.静态文件处理 在Django项目的静态文 ...

  9. ssh三大框架的认识

    一.SSH三大框架的概述 ssh为 struts+spring+hibernate的一个集成框架,是目前较流行的一种Web应用程序开源框架.  集成SSH框架的系统从职责上分为四层:表示层.业务逻辑层 ...

  10. 【selenium】- webdriver常见元素定位(中)

    本文由小编根据慕课网视频亲自整理,转载请注明出处和作者. 1.By.tagName 遇到hidden就break,继续下一个循环. 2.By.linkText 对上图中的“糯米”进行定位: 3.By. ...