Java反序列化利用链分析

约 8 分钟读完

一、反序列化漏洞基础

  1. 序列化与反序列化是什么?

    • 序列化:将Java对象转换为字节流(如保存到文件或网络传输)
    • 反序列化:将字节流还原为Java对象
    • 漏洞本质:攻击者构造恶意字节流,触发反序列化过程中的危险操作(如命令执行)
  2. 为何会产生漏洞?

    当程序对不可信数据(如网络传输、文件读取)直接调用ObjectInputStream.readObject()时,若该数据包含精心设计的恶意对象链,会触发预期外的代码执行。


二、利用链(Gadget Chain)核心逻辑

🔑 1. 利用链三要素

组件 作用 示例类/方法
入口点 反序列化时自动调用的起点方法 HashMap.readObject(), BadAttributeValueExpException.readObject()
传递链 通过方法调用、属性访问连接入口和出口的中间环节 Map.put(), Transformer.transform(), equals()
出口点 最终执行危险操作的方法(如命令执行、DNS请求) Runtime.exec(), URLStreamHandler.hashCode()

🌰 2. 形象比喻

把利用链看作多米诺骨牌

  • 入口点是第一张牌(readObject被推倒)
  • 传递链是中间连锁反应(牌与牌之间的碰撞)
  • 出口点是最后一张牌(命令执行倒地)

⚠️ 3. 关键特性

  • 动态反射调用:通过反射执行任意类的方法(如InvokerTransformer.transform()调用Runtime.exec()
  • 对象嵌套控制:恶意对象需满足字段约束(如特定类属性值需满足条件分支)
  • 延迟触发:利用反射修改对象状态,避免序列化时立即执行(如URLDNS链修改url.hashCode=-1

三、经典利用链案例解析

🎯 1. URLDNS链(无害探测)

  • 用途:探测目标是否存在反序列化漏洞(仅触发DNS请求,不执行命令)

  • 调用链

    graph LR
      A[HashMap.readObject] --> B[HashMap.putVal]
      B --> C[HashMap.hash]
      C --> D[URL.hashCode]
      D --> E[URLStreamHandler.hashCode]
      E --> F[发起DNS请求]
  • 绕过技巧

    用反射临时修改url.hashCode=1234→ 执行map.put(url)→ 再改回hashCode=-1,避免提前触发。

💥 2. CommonsCollections1链(命令执行)

  • 漏洞类InvokerTransformer(通过反射执行任意方法)

  • 核心调用链

    BadAttributeValueExpException.readObject()
      → TiedMapEntry.toString()
      → LazyMap.get()
      → ChainedTransformer.transform()  // 串联多个Transformer
      → InvokerTransformer.transform()   // 反射调用Runtime.exec("calc")
  • 依赖条件

    • Apache Commons Collections ≤ 3.2.1
    • JDK ≤ 8u71(后续版本修复了AnnotationInvocationHandler的利用)

🛡️ 3. JDK 8u71后的绕过(CC6链)

  • 修复绕过:不再依赖AnnotationInvocationHandler,改用TiedMapEntry作为入口

  • 新调用链

    HashMap.readObject() 
      → TiedMapEntry.hashCode() 
      → TiedMapEntry.getValue() 
      → LazyMap.get()  // 触发后续Transformer调用链

四、漏洞防御方案

🛠️ 1. 代码层防护

  • 输入过滤:禁用ObjectInputStream,改用JSON等安全格式(如Gson)

  • 白名单控制(JDK≥9):

    ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(
        "com.trusted.pkg.*;!*"  // 仅允许指定包名的类
    );
    ois.setObjectInputFilter(filter);
  • 字段验证:在readObject()中校验关键字段合法性

📦 2. 依赖与环境

  • 升级基础库

    <!-- Commons Collections安全版本 -->
    <dependency>
        <groupId>commons-collections</groupId>
        <artifactId>commons-collections</artifactId>
        <version>3.2.2+</version>
    </dependency>
  • JVM参数加固

    -Djdk.serialFilter=!org.apache.commons.collections.functors.*
    -Dcom.sun.jndi.rmi.object.trustURLCodebase=false

🔍 3. 检测工具

  • 漏洞扫描:使用ysoserial生成Payload测试(命令:java -jar ysoserial.jar CommonsCollections5 "id" > payload.bin
  • 动态分析:结合SerializationDumper解析序列化流结构

五、学习资源推荐

  • 工具实践
    • ysoserial:生成各类利用链Payload
    • JDD:自动化利用链挖掘工具(BlackHat Asia 2025)
  • 调试技巧:在IDEA中下载commons-collections 3.2.1源码,断点跟踪LazyMap.get()调用流程
  • 靶场环境:Vulhub(WebLogic/JBoss反序列化漏洞场景)

💡 小白学习路线:先掌握URLDNS链(理解触发逻辑) → 再调试CC1链(学习反射调用) → 最后分析CC6(了解绕过技巧),配合靶场实战巩固。

← Sql注入 Servlet路由配置与过滤器监听器 →