前言
CommonCollections系列的gadgets之CommonsCollections3
实验环境:jdk1.7.0_80、commons-collections:commons-collections:3.1
代码分析
还是和之前一样,先理清楚代码得基本思路,最后提出一些关于调用链中不好理解得问题。以下为关键调用链。
1 | at com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.getTransletInstance |
从调用链中可以看到反序列化触发点还是AnnotationInvocationHandler得readObject函数然后通过entry类型的动态代理调用到AnnotationInvocationHandler.invoke,最后触发LazyMap.get->ChainedTransformer.transform这里是和CommonCollections1相同的。不同的是ChainedTransformer中iTransformers参数的内容。
cc1中为:
1 | final Transformer[] transformers = new Transformer[] { |
cc3中为:
1 | final Transformer[] transformers = new Transformer[] { |
使用了cc3中的transformers可以让我们执行任意代码,从而不限制于只执行java.Runtime中的系统命令。所以说cc3像是cc1和cc2的综合。从ChainedTransformer.transform在cc1中已经讲解过,和cc1是一模一样的,如果记不清楚请看ysoserial学习之CommonsCollections1。
下面着重说明cc3 exp中开头的部分。
1 | Object templatesImpl = Gadgets.createTemplatesImpl(command); |
这个在cc2中讲解过,可以理解为创建了一个_bytecode字段为设置为命令执行类字节码的一个org.apache.xalan.xsltc.trax.TemplatesImpl实体类,该实体类还做了一些操作,如将父类设置为org.apache.xalan.xsltc.runtime.AbstractTranslet等。
1 | final Transformer transformerChain = new ChainedTransformer( |
这句可能只是作者为了保险起见,中途不会有某种东西触发到了ChainedTransformer.transform进而中断程序。实际我测试之后的做法为:
1 | final Transformer transformerChain = new ChainedTransformer( |
讲上面两句删除,在下面这句代码后面
1 | final Transformer[] transformers = new Transformer[] { |
直接添加一个
1 | final Transformer transformerChain = new ChainedTransformer(transformers); |
同样也是可以的。
前置工作做完之后我们开始解析ChainedTransformer.transform是如何触发任意代码执行的。
经过前面分析,我们知道ChainedTransformer的iTransformers已经被设置为了Transformer数组的串了。
1 | ChainedTransformer.transform的逻辑为将new ConstantTransformer(TrAXFilter.class)的类作为new InstantiateTransformer( |
也就是最后反射调用了下面的方法
这里我们看到了熟悉的东西,templates.newTransformer,这样也就把我们提前放置的_bytecode字节码实例化了,因此触发了任意代码执行。相比于java.Runtime系统代码执行,任意代码执行适用更加灵活,可以打weblogic的安装rmi实现代码执行或者打内存马。而我们只需要把我们想执行的java代码转换为字节码放到_bytecode里面就可以了,不过需要注意的是cc3和cc2一样有jdk版本限制。
后记
这次没有什么不好理解的问题,就没有自问自答环节了。。。