java反序列化利用链自动挖掘工具gadgetinspector源码浅析
字数 1804 2025-08-25 22:58:55
Java反序列化利用链自动挖掘工具GadgetInspector源码深度解析
0x01 工具概述
GadgetInspector是一款自动化挖掘Java反序列化利用链的工具,它通过静态分析技术自动发现从反序列化入口(source)到危险调用点(slink)的完整执行路径。该工具解决了人工分析反序列化利用链耗时耗力的问题,采用了污点分析、调用图构建等关键技术。
主要功能特点
- 自动化发现Java反序列化利用链
- 支持多种反序列化方式(原生Java序列化、Jackson等)
- 采用静态分析方法,无需实际执行代码
- 实现参数污染传播分析
- 支持多态方法调用分析
0x02 核心架构与流程
GadgetInspector的分析流程分为五个主要阶段:
- MethodDiscovery:收集类、方法数据及继承关系
- PassthroughDiscovery:分析参数对返回值的污染关系
- CallGraphDiscovery:构建方法调用图及参数关联
- SourceDiscovery:识别反序列化入口方法
- GadgetChainDiscovery:整合数据发现完整利用链
0x03 MethodDiscovery阶段详解
3.1 功能目标
收集三类核心数据:
- 类信息(类名、父类、接口、字段等)
- 方法信息(类名、方法名、描述符、静态标志等)
- 类继承关系(父子类、接口实现关系)
3.2 实现原理
使用ASM框架的ClassVisitor和MethodVisitor遍历所有类文件:
public void discover(final ClassResourceEnumerator classResourceEnumerator) throws Exception {
for (ClassResourceEnumerator.ClassResource classResource : classResourceEnumerator.getAllClasses()) {
ClassReader cr = new ClassReader(in);
cr.accept(new MethodDiscoveryClassVisitor(), ClassReader.EXPAND_FRAMES);
}
}
3.3 数据存储格式
-
classes.dat:
类名 父类 接口列表 是否接口 字段信息字段信息格式:
字段名!访问修饰符!类型 -
methods.dat:
类名 方法名 方法描述符 是否静态方法 -
inheritanceMap.dat:
类名 父类/接口1 父类/接口2 ...
0x04 PassthroughDiscovery阶段详解
4.1 功能目标
分析方法的参数是否会影响返回值,建立参数索引与返回值的污染关系。
4.2 关键技术:污点分析
通过模拟JVM栈帧操作,跟踪参数数据流:
- 本地变量表(Local Variables):存储方法参数和局部变量
- 操作数栈(Operand Stack):跟踪方法调用时的参数传递
4.3 核心实现
使用ASM MethodVisitor实现字节码级别的数据流分析:
@Override
public void visitVarInsn(int opcode, int var) {
// 处理局部变量加载/存储指令
switch(opcode) {
case Opcodes.ALOAD:
push(savedVariableState.localVars.get(var));
break;
case Opcodes.ASTORE:
saved0 = pop();
savedVariableState.localVars.set(var, saved0);
break;
// ...其他指令处理
}
}
@Override
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
// 处理方法调用指令,分析参数污染传播
Set<Integer> passthrough = passthroughDataflow.get(methodRef);
if (passthrough != null) {
for (Integer passthroughDataflowArg : passthrough) {
resultTaint.addAll(argTaint.get(passthroughDataflowArg));
}
}
}
4.4 逆拓扑排序
为确保分析方法时其调用方法已被分析,采用DFS逆拓扑排序:
private static void dfsTsort(Map<MethodReference.Handle, Set<MethodReference.Handle>> outgoingReferences,
List<MethodReference.Handle> sortedMethods,
Set<MethodReference.Handle> visitedNodes,
Set<MethodReference.Handle> stack,
MethodReference.Handle node) {
// DFS实现逆拓扑排序
if (visitedNodes.contains(node)) return;
stack.add(node);
for (MethodReference.Handle child : outgoingRefs) {
dfsTsort(outgoingReferences, sortedMethods, visitedNodes, stack, child);
}
stack.remove(node);
visitedNodes.add(node);
sortedMethods.add(node);
}
4.5 数据存储格式
passthrough.dat:
类名 方法名 方法描述符 污染参数索引列表
0x05 CallGraphDiscovery阶段详解
5.1 功能目标
建立方法调用图,记录调用者与被调用者之间的参数传递关系。
5.2 关键数据结构
class GraphCall {
MethodReference.Handle callerMethod; // 调用者方法
MethodReference.Handle targetMethod; // 被调用方法
int callerArgIndex; // 调用者参数索引
String callerArgPath; // 调用者字段路径(如"arg0.field")
int targetArgIndex; // 被调用者参数索引
}
5.3 数据存储格式
callgraph.dat:
调用者类名 调用者方法名 调用者方法描述符
被调用者类名 被调用者方法名 被调用者方法描述符
调用者参数索引 调用者字段路径 被调用者参数索引
0x06 SourceDiscovery阶段详解
6.1 功能目标
识别反序列化过程中会被自动调用的方法(入口点)。
6.2 不同序列化方式的入口
-
Java原生序列化:
- readObject()
- readResolve()
- readExternal()
-
Jackson反序列化:
- 无参构造方法
- setter方法(setXxx)
- getter方法(getXxx)
6.3 实现示例(Jackson)
public class JacksonSourceDiscovery extends SourceDiscovery {
public void discover(...) {
for (MethodReference.Handle method : methodMap.keySet()) {
if (serializableDecider.apply(method.getClassReference())) {
if (method.getName().equals("<init>") && method.getDesc().equals("()V")) {
addDiscoveredSource(new Source(method, 0));
}
if (method.getName().startsWith("get") && method.getDesc().startsWith("()")) {
addDiscoveredSource(new Source(method, 0));
}
// ...其他条件
}
}
}
}
6.4 数据存储格式
sources.dat:
类名 方法名 方法描述符 污染参数索引
0x07 GadgetChainDiscovery阶段详解
7.1 功能目标
整合前几个阶段的数据,发现从source到slink的完整利用链。
7.2 关键步骤
-
加载方法实现关系:
Map<MethodReference.Handle, Set<MethodReference.Handle>> methodImplMap = InheritanceDeriver.getAllMethodImplementations(inheritanceMap, methodMap); -
构建调用图:
Map<MethodReference.Handle, Set<GraphCall>> graphCallMap = new HashMap<>(); for (GraphCall graphCall : loadData("callgraph.dat")) { graphCallMap.computeIfAbsent(graphCall.getCallerMethod(), k -> new HashSet<>()) .add(graphCall); } -
链式搜索算法:
while (!methodsToExplore.isEmpty()) { GadgetChain chain = methodsToExplore.pop(); GadgetChainLink lastLink = chain.links.get(chain.links.size()-1); for (GraphCall graphCall : graphCallMap.get(lastLink.method)) { Set<MethodReference.Handle> allImpls = implementationFinder.getImplementations(graphCall.getTargetMethod()); for (MethodReference.Handle methodImpl : allImpls) { GadgetChainLink newLink = new GadgetChainLink(methodImpl, graphCall.getTargetArgIndex()); if (isSink(methodImpl, graphCall.getTargetArgIndex(), inheritanceMap)) { discoveredGadgets.add(new GadgetChain(chain, newLink)); } else { methodsToExplore.add(new GadgetChain(chain, newLink)); } } } }
7.3 Sink点判断
工具内置的危险方法(slink)包括:
private boolean isSink(MethodReference.Handle method, int argIndex, InheritanceMap inheritanceMap) {
// Runtime.exec()
if (method.getClassReference().getName().equals("java/lang/Runtime")
&& method.getName().equals("exec")) {
return true;
}
// Method.invoke()
if (method.getClassReference().getName().equals("java/lang/reflect/Method")
&& method.getName().equals("invoke") && argIndex == 0) {
return true;
}
// URL.openStream()
if (method.getClassReference().getName().equals("java/net/URL")
&& method.getName().equals("openStream")) {
return true;
}
// ...其他危险方法
}
0x08 扩展与定制
8.1 支持新的序列化方式
通过实现GIConfig接口:
public interface GIConfig {
String getName();
SerializableDecider getSerializableDecider(...);
ImplementationFinder getImplementationFinder(...);
SourceDiscovery getSourceDiscovery();
}
8.2 自定义Source发现
继承SourceDiscovery类并实现discover方法:
public class CustomSourceDiscovery extends SourceDiscovery {
@Override
public void discover(...) {
// 实现自定义的入口点发现逻辑
}
}
8.3 添加新的Sink点
修改isSink方法,添加新的危险方法判断条件。
0x09 总结
GadgetInspector通过静态分析技术实现了Java反序列化利用链的自动化挖掘,其核心创新点包括:
- 污点传播分析:精确跟踪参数对返回值的污染关系
- 逆拓扑排序:确保分析方法时其调用方法已被分析
- 多态方法处理:考虑接口/父类方法的所有实现
- 模块化设计:支持多种反序列化方式的扩展
该工具为Java反序列化漏洞研究提供了强有力的自动化支持,极大提高了漏洞挖掘的效率。