Skip to content

Commit 6b820f1

Browse files
committed
publish post
1 parent 25d14a1 commit 6b820f1

7 files changed

+852
-50
lines changed

HOWTO.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,31 @@
11
# How to manage
22

3+
## editing the blog
4+
5+
- open the `~/Dropbox/grey_blog/greyshell.github.io` folder in `sublime` editor
6+
37
## start the site at localhost
48

59
- navigate to the greyshell.github.io folder
610
- type `bundle exec jekyll s` and access the site at http://127.0.0.1:4000/
11+
- alternate: ./tools/run.sh
712

813
## how to post
914

10-
- copy an existing post from _post folder as template.
15+
- copy an existing post from `_post` folder as template.
1116
- save the post related assets inside assets folder. create a folder with the same filename as post.
1217
- for pasting the clipboard data use `pngpaste image_name.png`.
18+
- example: `![image_name](assets/post_name.assets/image_name.png)`
19+
- make sure to put extra line before and after the image_link to avoid `ERROR Errno::ECONNRESET`
20+
21+
### others
22+
23+
- tags are the specific context of the `categories`. for example, in the context of the password storage
24+
- categories: [crypto]
25+
- tags: [hashing]
26+
- TAG names should always be lowercase
27+
- `assets` folder contains all images.
28+
- folder name should be same as the .md file name in `_posts` folder.
1329

1430
## how to publish
1531

_posts/2016-11-07-exploit_dev_hp_openview_nnm.md

Lines changed: 653 additions & 1 deletion
Large diffs are not rendered by default.

_posts/2019-07-16-stack_canary_bypass.md

Lines changed: 0 additions & 8 deletions
This file was deleted.

_posts/2019-11-22-insecure_deserialization_java.md

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,15 @@ The process of `re-creating` the actual object in memory from byte stream is cal
3737

3838
### Observations
3939

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`.
4141

4242
![consume_superclass](assets/2019-11-22-insecure_deserialization_java.assets/consume_superclass.png)
4343

44-
- [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`.
4545

4646
![consume_baseclass](assets/2019-11-22-insecure_deserialization_java.assets/consume_baseclass.png)
4747

48-
- [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`.
4949

5050
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.
5151

@@ -97,7 +97,7 @@ From a Whitebox perspective
9797

9898
#### Leveraging `ysoserial`
9999

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).
101101

102102
```bash
103103
java -jar ysoserial-all.jar CommonsCollections7 gnome-calculator > bad_serialized_object_ysoserial.ser
@@ -140,7 +140,7 @@ During deserialization, when the application tries to reconstruct the object in
140140
--add-opens java.base/java.util=ALL-UNNAMED
141141
```
142142

143-
![add_vm_options2](assets/2019-11-22-insecure_deserialization_java.assets/add_vm_options.png)
143+
![add_vm_options](assets/2019-11-22-insecure_deserialization_java.assets/add_vm_options.png)
144144

145145
- Execute `RCE.java` and generate the `rce_serialized_object`.
146146

@@ -151,8 +151,6 @@ During deserialization, when the application attempts to reconstruct the object
151151
![rce_calculator](assets/2019-11-22-insecure_deserialization_java.assets/rce_calculator.png)
152152

153153

154-
155-
156154
## How to Mitigate
157155

158156
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
162160
- Extend `ObjectInputStream` to create a custom `SafeObjectInputStream` class.
163161
- Override the `resolveClass()` method to verify if `cls.getName()` exists in the `HashSet`, otherwise, throw an `InvalidClassException`.
164162

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.
166166

167167
![bad_object](assets/2019-11-22-insecure_deserialization_java.assets/bad_object.png)
168168

169169

170-
When we provide `User` type object, it does not throw any exception.
170+
- When we provide expected `User` type object, it does not throw any exception.
171171

172172
![good_object](assets/2019-11-22-insecure_deserialization_java.assets/good_object.png)
173173

174-
> 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`.
175175
{: .prompt-danger }
176176

177177

178+
### Defense in depth
178179

179-
Defense in depth
180180
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.
181181

182182
2. For detective controls, log any exceptions or failures that occur during the deserialization process.
@@ -194,4 +194,4 @@ System.setProperty(
194194

195195
## Code Repo
196196

197-
https://github.com/greyshell/java_insecure_deserialization
197+
<https://github.com/greyshell/java_insecure_deserialization>

_posts/2019-11-24-demystify_java_gadget_chain.md

Lines changed: 155 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,57 +5,200 @@ categories: [web_security]
55
tags: [java, insecure_deserialization] # TAG names should always be lowercase
66
---
77

8-
Site migration in process .. Drafting notes..
9-
10-
118
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.
129

1310
We need to use `property oriented programming` to build a `RCE gadget` from the scratch.
1411

15-
## Component / Classes Used to build the gadget
12+
## Component / Classes used to build the gadget
13+
1614
1. Default JRE System Libraries: HashMap
1715
2. `commons-collections-3.2.2.jar`:
1816
1. ChainedTransformer
1917
2. LazyMap
2018
3. TiedMapEntry
2119
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)
24+
{: .prompt-info }
25+
26+
## Pieces of the Puzzle
27+
28+
![gadget_flow](assets/2019-11-24-demystify_java_gadget_chain.assets/gadget_flow.png)
29+
30+
31+
## Command Execution using `Runtime` object directly
2232

23-
## 1. Command Execution using `Runtime` object directly
2433
We can use the Java `Runtime` object and its `exec()` method to execute any `system` commands.
2534
- for example, running the `mate-calculator` in linux.
2635

36+
![rce01](assets/2019-11-24-demystify_java_gadget_chain.assets/rce01.png)
37+
38+
## Command Execution using Reflection API and `Runtime` object
2739

28-
## 2. Command Execution using Reflection API and `Runtime` object
2940
* Java `Reflection API` is used to `examine` or `modify` the `behavior` of methods, classes, interfaces at `runtime`.
3041
- Through reflection API, we can invoke any method at `runtime` via `invoke()` function.
3142
- Here, we are trying to invoke `getRuntime()` method to get a `Runtime` object.
3243

44+
![rce02](assets/2019-11-24-demystify_java_gadget_chain.assets/rce02.png)
3345

34-
## 3. Command Execution using `ConstantTransformer` and `InvokerTransformer` together
3546

3647
Before directly jump into the `Constant Transformer` and `InvokerTransformer`, first understand the `Transformer` class and the `transform()` method.
3748

38-
#### Transformer
49+
## Concept of Transformer
50+
3951
- It transforms an input object to an output object through `transform()` method.
4052
- It doesn’t change the input object.
4153
- It is mainly used for: `type conversion`, `extracting` parts of an object.
4254

4355
For example, we can create a class `MyReverse` by implementing the `Transformer`interface and `transform()` method.
4456
- Here, in `transform()` method, we specify how to reverse a `String` type object.
4557

46-
4758
When we call the `transform()` method via passing the argument of a `String` type object, it reverses the string.
4859

60+
![concept_transformer](assets/2019-11-24-demystify_java_gadget_chain.assets/concept_transformer.png)
61+
62+
63+
The return type of the `transform()` method is `Object` therefore it can return any type of object.
4964

50-
> The return type of the `transform()` method is `Object` therefore it can return any type of object.
65+
## Command Execution using ConstantTransformer
5166

52-
### ConstantTransformer
5367
In contrast to the `Transformer` class, it always returns the `same object` that specified during `initialization`.
5468

5569
- 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.
5670

71+
![rce03](assets/2019-11-24-demystify_java_gadget_chain.assets/rce03.png)
72+
73+
## Concept of InvokerTransformer
5774

58-
### InvokerTransformer
5975
* During initialization, it takes a `method name` with optional parameters.
6076
* On `transform`, it calls that method for the object provided with the parameters.
6177

78+
![concept_invoker_transformer](assets/2019-11-24-demystify_java_gadget_chain.assets/concept_invoker_transformer.png)
79+
80+
81+
## Command Execution combining Transformer, ConstantTransformer and InvokerTransformer
82+
83+
We can chain all three types of transformers and perform RCE.
84+
85+
![rce04](assets/2019-11-24-demystify_java_gadget_chain.assets/rce04.png)
86+
87+
88+
## Command Execution using ChainedTransformer
89+
90+
`ChainedTransformer` is an array of transformers. By carefully maintaining their execution order we can achieve the same result but with minimum amount of code.
91+
92+
![rce05](assets/2019-11-24-demystify_java_gadget_chain.assets/rce05.png)
93+
94+
## Concept HashMap
95+
96+
> **public** **class** HashMap<K,V> **extends** AbstractMap<K,V> **implements** Map<K,V>, Cloneable, Serializable
97+
98+
1. HashMap class contains `values` based on the `key`.
99+
2. It contains only unique `keys`.
100+
3. It maintains no order.
101+
4. It returns `null` if there’s `no` value is present for the requested `key`.
102+
103+
![concept_hashmap](assets/2019-11-24-demystify_java_gadget_chain.assets/concept_hashmap.png)
104+
105+
## Concept LazyMap
106+
107+
1. A type of `Map` which `creates` a `value` if there’s `no` value is present for the `requested` key.
108+
2. This `generation` is done through a `transformation` (i.e transformer.`transform()` method) on the requested `Key`.
109+
3. When the request key is not found then `lazyMap.get("invalid_key")` calls `transformer.transform("invalid_key")` to generate the key on the fly.
110+
111+
![concept_lazymap1](assets/2019-11-24-demystify_java_gadget_chain.assets/concept_lazymap1.png)
112+
113+
![concept_lazymap2](assets/2019-11-24-demystify_java_gadget_chain.assets/concept_lazymap2.png)
114+
115+
## Command Execution by combining ChainedTransformer and LazyMap
116+
117+
![rce06](assets/2019-11-24-demystify_java_gadget_chain.assets/rce06.png)
118+
119+
120+
## Concept TiedMapEntry
121+
122+
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.
124+
125+
![concept_tidemapentry1](assets/2019-11-24-demystify_java_gadget_chain.assets/concept_tidemapentry1.png)
126+
127+
![concept_tidemapentry2](assets/2019-11-24-demystify_java_gadget_chain.assets/concept_tidemapentry2.png)
128+
129+
## Concept HashBag
130+
131+
1. A Collection that `counts` the number of times an object `appears` in the collection.
132+
2. Backed by an internal `HashMap` object.
133+
3. While adding any Object, first it's `hashcode()` is calculated. Based on that hashcode/index, it updates the underlying `HashMap` table entry.
134+
4. Key Point to remember `hashbag.add(tiedmapentry)` method calls `tiedmapentry.hashcode()` method.
135+
136+
![concept_hashbag](assets/2019-11-24-demystify_java_gadget_chain.assets/concept_hashbag.png)
137+
138+
## Assembling the pieces
139+
140+
1. Create a `TiedMapEntry` with a underlying `lazyMap` and key is `String` -> 'invalid_key'.
141+
2. Then `add` the `tiedmapentry` Object into a `HashBag` instance.
142+
3. `hashbag.add(tiedmapentry)` -> `tiedmapentry.hashcode()` -> `lazymap.get(this.key)` -> `chainedtransformer.transform(key)` -> `Runtime.getRuntime().exec("/usr/bin/gnome-calculator");`
143+
144+
145+
### Challenges
146+
147+
- 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
167+
168+
```java
169+
170+
System.setProperty(
171+
"org.apache.commons.collections.enableUnsafeSerialization",
172+
"true");
173+
```
174+
175+
## Prepare Final Exploit
176+
177+
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
183+
184+
```text
185+
--add-opens java.base/java.util=ALL-UNNAMED
186+
```
187+
188+
![add_vm_options](assets/2019-11-24-demystify_java_gadget_chain.assets/add_vm_options.png)
189+
190+
![rce07_1](assets/2019-11-24-demystify_java_gadget_chain.assets/rce07_1.png)
191+
192+
![rce07_2](assets/2019-11-24-demystify_java_gadget_chain.assets/rce07_2.png)
193+
194+
It was observed that the calculator did not open during object creation because `TiedMapEntry.hashcode()` was not invoked at any point.
195+
196+
### Test Exploit
197+
198+
When the client deserialization code attempts to process the .ser file, the calculator opens.
199+
200+
![rce07_3](assets/2019-11-24-demystify_java_gadget_chain.assets/rce07_3.png)
201+
202+
## References
203+
- Code Repo: <https://github.com/greyshell/rce_gadget/tree/main/src>
204+
- <https://speakerdeck.com/dhavalkapil/magichat-insomnihack-teaser-2018-writeup>

0 commit comments

Comments
 (0)