From e7b7c0a463450bbada4c5e9f08d6091e66ffa634 Mon Sep 17 00:00:00 2001 From: Translator Date: Mon, 28 Jul 2025 18:13:06 +0000 Subject: [PATCH] Translated ['src/pentesting-web/deserialization/basic-java-deserializati --- ...ialization-objectinputstream-readobject.md | 83 +++++++++++++++++-- 1 file changed, 75 insertions(+), 8 deletions(-) diff --git a/src/pentesting-web/deserialization/basic-java-deserialization-objectinputstream-readobject.md b/src/pentesting-web/deserialization/basic-java-deserialization-objectinputstream-readobject.md index 677a1ec68..f5875301b 100644 --- a/src/pentesting-web/deserialization/basic-java-deserialization-objectinputstream-readobject.md +++ b/src/pentesting-web/deserialization/basic-java-deserialization-objectinputstream-readobject.md @@ -1,15 +1,27 @@ +# Basic Java Deserialization with ObjectInputStream readObject + {{#include ../../banners/hacktricks-training.md}} -在这篇文章中,将解释一个使用 `java.io.Serializable` 的示例。 +在这篇文章中,将解释一个使用 `java.io.Serializable` 的示例**以及为什么重写 `readObject()` 在输入流由攻击者控制时可能极其危险**。 -# Serializable +## Serializable -Java `Serializable` 接口(`java.io.Serializable` 是一个标记接口,您的类必须实现它才能被 **序列化** 和 **反序列化**。Java 对象序列化(写入)是通过 [ObjectOutputStream](http://tutorials.jenkov.com/java-io/objectoutputstream.html) 完成的,反序列化(读取)是通过 [ObjectInputStream](http://tutorials.jenkov.com/java-io/objectinputstream.html) 完成的。 +Java `Serializable` 接口 (`java.io.Serializable`) 是一个标记接口,您的类必须实现它才能被 **序列化** 和 **反序列化**。Java 对象序列化(写入)是通过 [`ObjectOutputStream`](http://tutorials.jenkov.com/java-io/objectoutputstream.html) 完成的,反序列化(读取)是通过 [`ObjectInputStream`](http://tutorials.jenkov.com/java-io/objectinputstream.html) 完成的。 -让我们看一个 **可序列化的类 Person** 的示例。这个类 **重写了 readObject** 函数,因此当 **这个类的任何对象** 被 **反序列化** 时,这个 **函数** 将被 **执行**。\ -在这个示例中,类 Person 的 **readObject 函数** 调用了它的宠物的 `eat()` 函数,而 Dog 的 `eat()` 函数(出于某种原因)调用了 **calc.exe**。 **我们将看到如何序列化和反序列化一个 Person 对象以执行这个计算器:** +### 提醒:在反序列化过程中哪些方法会被隐式调用? -**以下示例来自 [https://medium.com/@knownsec404team/java-deserialization-tool-gadgetinspector-first-glimpse-74e99e493649](https://medium.com/@knownsec404team/java-deserialization-tool-gadgetinspector-first-glimpse-74e99e493649)** +1. `readObject()` – 类特定的读取逻辑(如果实现且为 *private*)。 +2. `readResolve()` – 可以用另一个对象替换反序列化的对象。 +3. `validateObject()` – 通过 `ObjectInputValidation` 回调。 +4. `readExternal()` – 对于实现 `Externalizable` 的类。 +5. 构造函数 **不会** 被执行 – 因此小工具链完全依赖于之前的回调。 + +在该链中的任何方法如果最终调用了攻击者控制的数据(命令执行、JNDI 查找、反射等),将使反序列化过程变成 RCE 小工具。 + +让我们看一个 **Person 类** 的示例,该类是 **可序列化的**。这个类 **重写了 readObject** 函数,因此当 **该类的任何对象** 被 **反序列化** 时,这个 **函数** 将被 **执行**。\ +在这个示例中,Person 类的 **readObject** 函数调用了它的宠物的 `eat()` 函数,而 Dog 的 `eat()` 函数(出于某种原因)调用了 **calc.exe**。 **我们将看到如何序列化和反序列化一个 Person 对象以执行这个计算器:** + +**以下示例来自 ** ```java import java.io.Serializable; import java.io.*; @@ -80,8 +92,63 @@ payloadTest("test.ser"); } } ``` -## 结论 +### 结论(经典场景) -正如您在这个非常基本的示例中所看到的,这里的“漏洞”出现是因为 **readObject** 函数 **调用了其他易受攻击的函数**。 +正如您在这个非常基本的例子中所看到的,这里的“漏洞”出现是因为 **readObject()** 方法 **调用了其他攻击者控制的代码**。在现实世界的 gadget 链中,成千上万的类包含在外部库中(Commons-Collections、Spring、Groovy、Rome、SnakeYAML 等)可以被滥用——攻击者只需要 *一个* 可达的 gadget 就能获得代码执行。 + +--- + +## 2023-2025:Java 反序列化攻击的新动态 + +* 2023 – CVE-2023-34040:当 `checkDeserExWhen*` 标志启用时,Spring-Kafka 反序列化错误记录头允许从攻击者发布的主题构造任意 gadget。已在 3.0.10 / 2.9.11 中修复。¹ +* 2023 – CVE-2023-36480:Aerospike Java 客户端的受信任服务器假设被破坏——恶意服务器回复包含被客户端 反序列化 的序列化有效负载 → RCE。² +* 2023 – CVE-2023-25581:`pac4j-core` 用户配置文件属性解析接受 `{#sb64}` 前缀的 Base64 blob,并在 `RestrictedObjectInputStream` 的情况下反序列化它们。升级 ≥ 4.0.0。 +* 2023 – CVE-2023-4528:JSCAPE MFT Manager Service(端口 10880)接受 XML 编码的 Java 对象,导致以 root/SYSTEM 身份的 RCE。 +* 2024 – 多个新的 gadget 链被添加到 ysoserial-plus(mod),包括 Hibernate5、TomcatEmbed 和 SnakeYAML 2.x 类,绕过了一些旧的过滤器。 + +## 现代缓解措施 + +1. **JEP 290 / 序列化过滤(Java 9+)** +*添加类的允许列表或拒绝列表:* +```bash +# 仅接受您的 DTO 和 java.base,拒绝其他所有内容 +-Djdk.serialFilter="com.example.dto.*;java.base/*;!*" +``` +编程示例: +```java +var filter = ObjectInputFilter.Config.createFilter("com.example.dto.*;java.base/*;!*" ); +ObjectInputFilter.Config.setSerialFilter(filter); +``` +2. **JEP 415(Java 17+)上下文特定过滤器工厂** – 使用 `BinaryOperator` 根据执行上下文(例如,每个 RMI 调用、每个消息队列消费者)应用不同的过滤器。 +3. **不要通过网络暴露原始 `ObjectInputStream`** – 更倾向于没有代码执行语义的 JSON/二进制编码(Jackson 在禁用 `DefaultTyping` 后,Protobuf、Avro 等)。 +4. **深度防御限制** – 设置最大数组长度、深度、引用: +```bash +-Djdk.serialFilter="maxbytes=16384;maxdepth=5;maxrefs=1000" +``` +5. **持续的 gadget 扫描** – 在您的 CI 中运行工具,如 `gadget-inspector` 或 `serialpwn-cli`,如果危险的 gadget 变得可达则失败构建。 + +## 更新的工具备忘单(2024) + +* `ysoserial-plus.jar` – 社区分支,包含 > 130 个 gadget 链: +```bash +java -jar ysoserial-plus.jar CommonsCollections6 'calc' | base64 -w0 +``` +* `marshalsec` – 仍然是 JNDI gadget 生成的参考(LDAP/RMI)。 +* `gadget-probe` – 针对网络服务的快速黑盒 gadget 发现。 +* `SerialSniffer` – JVMTI 代理,打印每个被 `ObjectInputStream` 读取的类(有助于制作过滤器)。 +* **检测提示** – 启用 `-Djdk.serialDebug=true`(JDK 22+)以记录过滤器决策和被拒绝的类。 + +## 安全 `readObject()` 实现的快速检查清单 + +1. 将方法设为 `private` 并添加 `@Serial` 注解(有助于静态分析)。 +2. 切勿在方法中调用用户提供的方法或执行 I/O – 仅读取字段。 +3. 如果需要验证,请在反序列化 **后** 执行,位于 `readObject()` 之外。 +4. 更倾向于实现 `Externalizable` 并显式读取字段,而不是默认序列化。 +5. 即使对于内部服务,也要注册一个强化的 `ObjectInputFilter`(抗妥协设计)。 + +## 参考文献 + +1. Spring Security Advisory – CVE-2023-34040 Java 反序列化在 Spring-Kafka 中(2023年8月) +2. GitHub Security Lab – GHSL-2023-044:Aerospike Java 客户端中的不安全反序列化(2023年7月) {{#include ../../banners/hacktricks-training.md}}