|
2 | 2 |
|
3 | 3 | {{#include ../../banners/hacktricks-training.md}}
|
4 | 4 |
|
5 |
| -In this POST it's going to be explained an example using `java.io.Serializable`. |
| 5 | +In this POST it's going to be explained an example using `java.io.Serializable` **and why overriding `readObject()` can be extremely dangerous if the incoming stream is attacker-controlled**. |
6 | 6 |
|
7 | 7 | ## Serializable
|
8 | 8 |
|
9 |
| -The Java `Serializable` interface (`java.io.Serializable` is a marker interface your classes must implement if they are to be **serialized** and **deserialized**. Java object serialization (writing) is done with the [ObjectOutputStream](http://tutorials.jenkov.com/java-io/objectoutputstream.html) and deserialization (reading) is done with the [ObjectInputStream](http://tutorials.jenkov.com/java-io/objectinputstream.html). |
| 9 | +The Java `Serializable` interface (`java.io.Serializable`) is a marker interface your classes must implement if they are to be **serialized** and **deserialized**. Java object serialization (writing) is done with the [`ObjectOutputStream`](http://tutorials.jenkov.com/java-io/objectoutputstream.html) and deserialization (reading) is done with the [`ObjectInputStream`](http://tutorials.jenkov.com/java-io/objectinputstream.html). |
| 10 | + |
| 11 | +### Reminder: Which methods are implicitly invoked during deserialization? |
| 12 | + |
| 13 | +1. `readObject()` – class-specific read logic (if implemented and *private*). |
| 14 | +2. `readResolve()` – can replace the deserialized object with another one. |
| 15 | +3. `validateObject()` – via `ObjectInputValidation` callbacks. |
| 16 | +4. `readExternal()` – for classes implementing `Externalizable`. |
| 17 | +5. Constructors are **not** executed – therefore gadget chains rely exclusively on the previous callbacks. |
| 18 | + |
| 19 | +Any method in that chain that ends up invoking attacker-controlled data (command execution, JNDI lookups, reflection, etc.) turns the deserialization routine into an RCE gadget. |
10 | 20 |
|
11 | 21 | Lets see an example with a **class Person** which is **serializable**. This class **overwrites the readObject** function, so when **any object** of this **class** is **deserialized** this **function** is going to be **executed**.\
|
12 |
| -In the example, the **readObject function** of the class Person calls the function `eat()` of his pet and the function `eat()` of a Dog (for some reason) calls a **calc.exe**. **We are going to see how to serialize and deserialize a Person object to execute this calculator:** |
| 22 | +In the example, the **readObject** function of the class Person calls the function `eat()` of his pet and the function `eat()` of a Dog (for some reason) calls a **calc.exe**. **We are going to see how to serialize and deserialize a Person object to execute this calculator:** |
13 | 23 |
|
14 |
| -**The following example is from [https://medium.com/@knownsec404team/java-deserialization-tool-gadgetinspector-first-glimpse-74e99e493649](https://medium.com/@knownsec404team/java-deserialization-tool-gadgetinspector-first-glimpse-74e99e493649)** |
| 24 | +**The following example is from <https://medium.com/@knownsec404team/java-deserialization-tool-gadgetinspector-first-glimpse-74e99e493649>** |
15 | 25 |
|
16 | 26 | ```java
|
17 | 27 | import java.io.Serializable;
|
@@ -84,11 +94,63 @@ public class TestDeserialization {
|
84 | 94 | }
|
85 | 95 | ```
|
86 | 96 |
|
87 |
| -### Conclusion |
| 97 | +### Conclusion (classic scenario) |
88 | 98 |
|
89 |
| -As you can see in this very basic example, the "vulnerability" here appears because the **readObject** function is **calling other vulnerable functions**. |
| 99 | +As you can see in this very basic example, the “vulnerability” here appears because the **readObject()** method is **calling other attacker-controlled code**. In real-world gadget chains, thousands of classes contained in external libraries (Commons-Collections, Spring, Groovy, Rome, SnakeYAML, etc.) can be abused – the attacker only needs *one* reachable gadget to get code execution. |
90 | 100 |
|
91 |
| -{{#include ../../banners/hacktricks-training.md}} |
| 101 | +--- |
| 102 | + |
| 103 | +## 2023-2025: What’s new in Java deserialization attacks? |
| 104 | + |
| 105 | +* 2023 – CVE-2023-34040: Spring-Kafka deserialization of error-record headers when `checkDeserExWhen*` flags are enabled allowed arbitrary gadget construction from attacker-published topics. Fixed in 3.0.10 / 2.9.11. ¹ |
| 106 | +* 2023 – CVE-2023-36480: Aerospike Java client trusted-server assumption broken – malicious server replies contained serialized payloads that were deserialized by the client → RCE. ² |
| 107 | +* 2023 – CVE-2023-25581: `pac4j-core` user profile attribute parsing accepted `{#sb64}`-prefixed Base64 blobs and deserialized them despite a `RestrictedObjectInputStream`. Upgrade ≥ 4.0.0. |
| 108 | +* 2023 – CVE-2023-4528: JSCAPE MFT Manager Service (port 10880) accepted XML-encoded Java objects leading to RCE as root/SYSTEM. |
| 109 | +* 2024 – Multiple new gadget chains were added to ysoserial-plus(mod) including Hibernate5, TomcatEmbed, and SnakeYAML 2.x classes that bypass some old filters. |
| 110 | + |
| 111 | +## Modern mitigations you should deploy |
92 | 112 |
|
| 113 | +1. **JEP 290 / Serialization Filtering (Java 9+)** |
| 114 | + *Add an allow-list or deny-list of classes:* |
| 115 | + ```bash |
| 116 | + # Accept only your DTOs and java.base, reject everything else |
| 117 | + -Djdk.serialFilter="com.example.dto.*;java.base/*;!*" |
| 118 | + ``` |
| 119 | + Programmatic example: |
| 120 | + ```java |
| 121 | + var filter = ObjectInputFilter.Config.createFilter("com.example.dto.*;java.base/*;!*" ); |
| 122 | + ObjectInputFilter.Config.setSerialFilter(filter); |
| 123 | + ``` |
| 124 | +2. **JEP 415 (Java 17+) Context-Specific Filter Factories** – use a `BinaryOperator<ObjectInputFilter>` to apply different filters per execution context (e.g., per RMI call, per message queue consumer). |
| 125 | +3. **Do not expose raw `ObjectInputStream` over the wire** – prefer JSON/Binary encodings without code execution semantics (Jackson after disabling `DefaultTyping`, Protobuf, Avro, etc.). |
| 126 | +4. **Defense-in-Depth limits** – Set maximum array length, depth, references: |
| 127 | + ```bash |
| 128 | + -Djdk.serialFilter="maxbytes=16384;maxdepth=5;maxrefs=1000" |
| 129 | + ``` |
| 130 | +5. **Continuous gadget scanning** – run tools such as `gadget-inspector` or `serialpwn-cli` in your CI to fail the build if a dangerous gadget becomes reachable. |
93 | 131 |
|
| 132 | +## Updated tooling cheat-sheet (2024) |
94 | 133 |
|
| 134 | +* `ysoserial-plus.jar` – community fork with > 130 gadget chains: |
| 135 | + ```bash |
| 136 | + java -jar ysoserial-plus.jar CommonsCollections6 'calc' | base64 -w0 |
| 137 | + ``` |
| 138 | +* `marshalsec` – still the reference for JNDI gadget generation (LDAP/RMI). |
| 139 | +* `gadget-probe` – fast black-box gadget discovery against network services. |
| 140 | +* `SerialSniffer` – JVMTI agent that prints every class read by `ObjectInputStream` (useful to craft filters). |
| 141 | +* **Detection tip** – enable `-Djdk.serialDebug=true` (JDK 22+) to log filter decisions and rejected classes. |
| 142 | + |
| 143 | +## Quick checklist for secure `readObject()` implementations |
| 144 | + |
| 145 | +1. Make the method `private` and add the `@Serial` annotation (helps static analysis). |
| 146 | +2. Never call user-supplied methods or perform I/O in the method – only read fields. |
| 147 | +3. If validation is needed, perform it **after** deserialization, outside of `readObject()`. |
| 148 | +4. Prefer implementing `Externalizable` and do explicit field reads instead of default serialization. |
| 149 | +5. Register a hardened `ObjectInputFilter` even for internal services (compromise-resilient design). |
| 150 | + |
| 151 | +## References |
| 152 | + |
| 153 | +1. Spring Security Advisory – CVE-2023-34040 Java Deserialization in Spring-Kafka (Aug 2023) |
| 154 | +2. GitHub Security Lab – GHSL-2023-044: Unsafe Deserialization in Aerospike Java Client (Jul 2023) |
| 155 | + |
| 156 | +{{#include ../../banners/hacktricks-training.md}} |
0 commit comments