You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: _posts/2019-11-22-insecure_deserialization_java.md
+12-12Lines changed: 12 additions & 12 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -37,15 +37,15 @@ The process of `re-creating` the actual object in memory from byte stream is cal
37
37
38
38
### Observations
39
39
40
-
-[x]For instance, if a serialized object is created using the `User` class but type checking during deserialization is performed with the `SuperUser` class, then application will throw a `ClassCastException`.
40
+
-[x]Case 1: If a serialized object is created using the `User` class but during deserialization when the `type checking`is performed with the `SuperUser` class, then application throws a `ClassCastException`.
-[x]However, if a serialized object is created using the `SuperUser` class but type checking during deserialization is performed with the `User` class, the application will not throw any exception because `SuperUser` class is derived from the base class `User`.
44
+
-[x]Case 2: If a serialized object is created using the `SuperUser` class but during deserialization when the `type checking`is performed with the `User` class, then the application does not throw any exception because `SuperUser` class is derived from the base class `User`.
-[x] Some objects may be required to implement `Serializable` due to inheritance for example `SuperUser`. It inherites the base class `User` that implements `Serializable`.
48
+
-[x] Some objects may be required to implement `Serializable` due to `inheritance` for example `SuperUser` class. It inherits the base class `User` that implements `Serializable`.
49
49
50
50
To ensure that such objects (e.g., `SuperUser`) cannot be deserialized, we can override the `readObject()` method and mark it as `final` to throw an exception during the deserialization process.
51
51
@@ -97,7 +97,7 @@ From a Whitebox perspective
97
97
98
98
#### Leveraging `ysoserial`
99
99
100
-
- Generate the rce payload to open `gnome-calculator` using the latest [ysoserial](https://github.com/frohoff/ysoserial).
100
+
- Generate the RCE payload to open `gnome-calculator` using the latest [ysoserial](https://github.com/frohoff/ysoserial).
1. Do not blindly accept serialized objects from untrusted sources. Implement integrity checks or sign the serialized objects to prevent tampering or the creation of malicious objects.
@@ -162,21 +160,23 @@ During deserialization, when the application attempts to reconstruct the object
162
160
- Extend `ObjectInputStream` to create a custom `SafeObjectInputStream` class.
163
161
- Override the `resolveClass()` method to verify if `cls.getName()` exists in the `HashSet`, otherwise, throw an `InvalidClassException`.
164
162
165
-
When we provide any object other than `User` type, it throws exception.
163
+
For example,
164
+
165
+
- When we provide any object other than `User` type, it throws exception.
> A Denial of Service (DoS) is inevitable if the `expected` object type is a `HashSet`, `HashMap`, or `ArrayList`.
174
+
> A Denial of Service (DoS) is `inevitable` if the `expected` object type is a `HashSet`, `HashMap`, or `ArrayList`.
175
175
{: .prompt-danger }
176
176
177
177
178
+
### Defense in depth
178
179
179
-
Defense in depth
180
180
1. Use the `transient` keyword for sensitive fields that you do not want to be serialized. The `transient` keyword prevents a variable, like a password field, from being serialized. When the JVM encounters a variable marked as transient or `static`, it disregards its original value and instead saves the default value corresponding to that variable’s data type.
181
181
182
182
2. For detective controls, log any exceptions or failures that occur during the deserialization process.
tags: [java, insecure_deserialization] # TAG names should always be lowercase
6
6
---
7
7
8
-
Site migration in process .. Drafting notes..
9
-
10
-
11
8
I was always curious about how the actual remote code execution occurs during the Insecure Deserialization process. So I thought of giving a try to understand the known harmful `gadgets` from `commons-collections-3.2.2.jar` and develop the entire chain from scratch.
12
9
13
10
We need to use `property oriented programming` to build a `RCE gadget` from the scratch.
14
11
15
-
## Component / Classes Used to build the gadget
12
+
## Component / Classes used to build the gadget
13
+
16
14
1. Default JRE System Libraries: HashMap
17
15
2.`commons-collections-3.2.2.jar`:
18
16
1. ChainedTransformer
19
17
2. LazyMap
20
18
3. TiedMapEntry
21
19
4. HashBag
20
+
3.`commons-lang3-3.7.jar`
21
+
4.`mockito-all-1.9.5.jar`
22
+
23
+
> Make sure to add all those external libraries into Java class PATH (i.e Pycharm File -> Project Structure -> Libraries)
The return type of the `transform()` method is `Object` therefore it can return any type of object.
49
64
50
-
> The return type of the `transform()` method is `Object` therefore it can return any type of object.
65
+
## Command Execution using ConstantTransformer
51
66
52
-
### ConstantTransformer
53
67
In contrast to the `Transformer` class, it always returns the `same object` that specified during `initialization`.
54
68
55
69
- If we Initialize a `ConstantTransformar` with `Runtime.class` and can call the `transform()` method with `any object`(for example, `HashSet`), we will always get the `Runtime.class` type object.
`ChainedTransformer` is an array of transformers. By carefully maintaining their execution order we can achieve the same result but with minimum amount of code.
1. This can be used to `enable` a `Map` entry to `make changes` on the `underlying` map.
123
+
2. Key point to remember `tiedmapentry.hashcode()` method calls `tiedmapentry.getValue()` method then intern it finally calls `lazymap.get(this.key)` method.
- Our primary objective for during the deserialization process is to ensure that `TiedMapEntry.hashcode()` gets invoked first time only.
148
+
- However, when we attempt to serialize the HashBag object to generate the payload or .ser file, the method lazymap.get("invalid_key") is invoked once. This causes the underlying HashMap to be updated with the entry `invalid_key:derived_value`.
149
+
- As a result, during the deserialization process, when `TiedMapEntry.hashcode()` triggers the call `lazymap.get(this.key)`, the `ChainedTransformer.transform(key)` method will not be executed. This is because the LazyMap no longer needs to derive the value for the key using the `transform()` method—the underlying HashMap already contains the precomputed entry.
150
+
151
+
> Therefore, we need to find a way to prevent the `TiedMapEntry.hashcode()` method from being invoked while creating the exploit payload.
152
+
{: .prompt-warning }
153
+
154
+
### Resolve using mokito
155
+
156
+
1. Create a `HashBag` instance and add any `Object` into it.
157
+
2. This will invoke Object’s `hashcode()` method and based on the hashcode / index, the underlying `HashBag's` => `HashMap` table entry will be updated with `key = Object` and `value / count = 1`.
158
+
3. Now using `mokito` library, modify that `HashBag's` => `HashMap’s``first` entry in `memory`.
159
+
- Replace that `Object` with `TiedMapEntry` Object.
160
+
- We have added only one entry due to that we are modifying the `first` entry.
161
+
4. As you can observe, till this point, `TiedMapEntry.hashcode()` is not called anywhere.
162
+
5. Serialize this `HashBag` Object.
163
+
164
+
An exception might still occur while creating the serialized object, as serialization support is now disabled by default for `org.apache.commons.collections.functors.InvokerTransformer` is `disabled`.
165
+
166
+
Therefore enable the support in both producer and consumer programs to serialize / deserialize the object without any exception
Before finalizing the exploit payload, we need to include support for the Mockito library.
178
+
179
+
> Java’s **strong encapsulation** introduced in **Java 9+**, which restricts reflective access to certain internal Java classes and fields by default. This is especially relevant when using libraries or tools that attempt to access private or internal fields of classes like `HashMap`.
180
+
{: .prompt-danger }
181
+
182
+
-[x] By adding the `--add-opens` option, we can explicitly open the necessary package (`java.util`) for reflection. In IntelliJ IDEA -> Run -> Edit Configurations -> In **VM options** field, add the following
0 commit comments