浅谈二次反序列化利用
字数 1398 2025-08-10 17:51:51
二次反序列化利用技术详解
前言
二次反序列化是指在反序列化一个对象时,该对象中包含的某个字段本身又是一个可反序列化对象。这种技术常用于绕过黑名单等安全限制场景,在Java安全领域有重要应用。
三种二次反序列化利用方式
1. SignedObject方式
java.security.SignedObject类提供了标准的序列化/反序列化机制:
- 构造方法中实现了序列化一个Serializable对象的操作,并将字节数组存储到content字段
SignedObject#getObject方法实现了将content字段反序列化的操作
利用原理:
- 将恶意序列化对象包装在SignedObject中
- 当SignedObject被反序列化时,黑名单检查会通过
- SignedObject的getObject方法被调用时,内部存储的恶意对象被二次反序列化
2. RMIConnector方式
javax.management.remote.rmi.RMIConnector类中的利用链:
findRMIServerJRMP方法中对base64字符串进行反序列化findRMIServer方法调用findRMIServerJRMP,要求path以"/stub/"开头- 通过反射修改urlPath属性为"/stub/base64_ser_str"形式
- 使用CC链中的
InvokerTransformer#transform触发RMIConnector#connect
示例利用链:
InvokerTransform#transform
-> RMIConnector#connect
-> RMIConnector#findRMIServerJRMP
3. WrapperConnectionPoolDataSource方式
利用com.mchange.v2.c3p0.WrapperConnectionPoolDataSource:
- 构造方法调用
C3P0ImplUtils.parseUserOverridesAsString parseUserOverridesAsString处理hex字符串并最终调用反序列化- 通过FastJson等注入点设置
userOverridesAsString为恶意hex序列化数据
组合利用:
FastJson + CC6 + C3P0
HDCTF-二次反序列化利用实战
环境分析
- 使用自定义的
MyownObjectInputStream代替标准反序列化 - 实现了黑名单机制,过滤危险类如
TemplatesImpl等 - 重写了
resolveClass方法进行安全检查
绕过思路
- 使用ROME反序列化链(利用
EqualsBean和ToStringBean) - 通过
SignedObject包装恶意对象绕过黑名单 - ROME链会自动调用
getObject方法触发二次反序列化
关键代码实现
// 创建恶意TemplatesImpl对象
TemplatesImpl obj = new TemplatesImpl();
setFieldValue(obj, "_bytecodes", new byte[][]{bytes});
setFieldValue(obj, "_name", "Poria");
setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
// 使用ROME链构造初始payload
HashMap payload2 = getPayload(Templates.class, obj);
// 使用SignedObject进行二次包装
SignedObject signedObject = signedObject(payload2);
// 再次使用ROME链构造最终payload
HashMap payload = getPayload(SignedObject.class, signedObject);
绕过原理
- 外层反序列化时只看到
SignedObject类,通过黑名单检查 - ROME链自动调用
getObject方法 getObject内部反序列化原始恶意对象(TemplatesImpl等)- 此时已绕过外层安全检查,成功执行恶意代码
技术总结
- 黑名单绕过:二次反序列化能有效绕过基于类名的黑名单防御
- 利用场景:多出现在CTF比赛,实际环境中较少但仍有参考价值
- 防御建议:
- 使用白名单而非黑名单
- 禁止反序列化不可信数据
- 监控可疑的反序列化操作
参考资源
- HDCTF2023 Web题出题记录
- Java安全编码规范
- 反序列化漏洞防御指南