1.反序列化的原因
如果Java应用对用户输入的内容做了序列化,但是用户输入的内容是不可信的数据,进行了恶意构造,那么在对恶意构造的数据做反序列化处理,就会产生的非预期对象,在这个过程中就可能带来任意代码执行。
2.漏洞原理
在进行Map转换时,修改Map中的key和value会调用接口,触发内置的transform来获取类名、方法对象进行反射,其中传入的方法名,参数类型等都是可控的,那么我们就可以构造ChainedTransformer来进行反射,调用任意函数
3.影响版本
commons-collections<=3.2.1存在漏洞
4.下载地址
本文对commons-collections-3.2.1进行漏洞分析,下载地址:https://github.com/SQYY/Apache-Commons-Collections/raw/master/commons-collections-3.2.1-1.0.0.jar
5.漏洞分析
在org/apache/commons/collections/map/TransformedMap.class
中可以看到decorate()方法,它是将一个Map对象,转换成TransformedMap对象。
可以看到它会把它的三个参数带入到TransformedMap方法中,并返回实例化的结果。而在这个方法中,如上图所示,就是将Map中的key和value转换成TransformedMap中的key和value
而transform
是一个接口,即可实现数据变换的操作。当Map中的任意项的Key或者value被修改,这个接口就会被调用。
在org/apache/commons/collections/functors/InvokerTransformer.class
中,也是我们核心的关键点,可以看到它实现了transform和Serializable这两个接口
可以看到transform中,首先会getClass获取传入参数的类名,再通过getMethod获取方法对象,最后调用invoke进行反射
就是说只需要传入方法名、参数类型和参数,我们就可以通过Java的反射机制可以调用任意函数。
6.构造POC
那么我们重要的是多个Transformer能串联起来,形成ChainedTransformer,让它依次执行便可序列化。
我们要构造一个实例,修改其中的数据,让它依次调用Runtime –>getRuntime()–>exec(),执行Runtime.getRuntime().exec()
,便可序列化
首先需要ConstantTransformer()获取了Runtime类,接着调用getMethod方法来定位需要查找的getRuntime,再反射调用getRuntime中的的exec(),最终执行命令
而decorate()就是将Map转换成TransformedMap,这里我们再看一遍这个方法,它的第三个参数就是Transformer类型
那么我们可以将构造的内容当做第三个参数传入进去
完整POC地址:https://github.com/SQYY/Apache-Commons-Collections/blob/master/POC.java