Apache Commons Collections
Apache Commons Collections是一个扩展了Java标准库里的Collection结构的第三方基础库,它提供了很多强有力的数据结构类型并且实现了各种集合工具类。作为Apache开源项目的重要组件,Commons Collections被广泛应用于各种Java应用的开发。其实Java JDK已经提供了丰富的集合操作,但是在某些场合下,可能无法满足,apache commons组件提供了更加丰富的集数据结构。
复现环境
1 | Mac OS Big Sur |
JDK7下载地址:https://www.oracle.com/java/technologies/javase/javase7-archive-downloads.html
下载好之后查看本地JDK版本
1 | caoyifan@MacBookPro ~ % ls /Library/Java/JavaVirtualMachines |
IDEA配置
创建好Maven项目之后,指定对应的JDK版本即可
Common Collections3.1通过maven添加
1 | <dependencies> |
漏洞分析
一个简单反射例子
在分析该漏洞之前我们先写一个利用反射弹计算器的例子。后面的漏洞分析会基于这个例子进行修改。
1 | import java.lang.reflect.Method; |
从Trnsformer看起
我们知道该漏洞的问题出现在Transformer接口类,因此我们首先查看一下实现这个类都有哪些方法。
这个时候我们随便点进去一个方法看看具体是怎么实现的。例如在ConstantTransformer
类返回的是一个常量。在InvokerTransformer
类中实现的是一个反射调用,而且参数都是可控的。因此我们尝试利用InvokerTransformer
来改写上面的反射的例子。
InvokerTransformer
在InvokerTransformer
类中存在三个参数是我们可控的,因此我们只需要按照transform方法中的调用方式传值就可以了。改写后的代码如下
1 | import org.apache.commons.collections.functors.InvokerTransformer; |
这个时候我们已经找到了一个点,是InvokerTransformer.transform
这个方法,它是一个危险方法,接着我们向上继续找还有哪些调用了transform
方法,最好是不同名的
TransformedMap
注意到TransformedMap
这个类,因为在这个类中有好几处都调用了transform
这个方法。
跟进checkSetValue
方法, 发现调用了valueTransformer
的transform
方法
找到TransformedMap
的构造函数,发现传入了一个map
和两个Transformer
,可以理解为接受一个map
并对这个map
的key
和value
做一些操作,因为这是一个保护方法, 我们继续找一下在哪里调用了这个方法。
在构造方法上面找到了decorate
静态方法
接着我们向上查找哪些调用了checkSetValue
方法,发现只有一处调用了该方法,继续跟进
发现是AbstractInputCheckedMapDecorator
类中有一个MapEntry
类,这个类调用了setValue
方法
MapEntry
这个时候我们梳理一遍,当我们遍历被修饰的Map
的时候,就会走到setValue
这个方法,从而会调用checkSetValue
,接着调用到了valueTransformer.transform
方法,之后就会走到InvokerTransformer.transform
方法执行
我们再次尝试改写上面的例子,首先实例化一个map
对象,并对map
进行装饰,因为在后面执行transform
方法的是decorate
方法传入的第三个参数,因此我们可以给第二个参数传一个空值,之后通过for
循环调用setValue
方法将我们的Runtime.getRuntime()
对象传入。
1 | import org.apache.commons.collections.functors.InvokerTransformer; |
jdk源码关联
这个时候我们继续向上寻找调用链,看哪些类调用了setValue
方法,按照流程,我应该能找到在AnnotationInvocationHandler
这个类的readObject
方法里面调用了setValue
方法,可是找了一圈,并没有。。。我以为是我jdk版本的问题,于是在jdk下面查看,路径是rt.jar
下面的sun.reflect.annotation
,发现这个类不是源代码,所以查找调用的时候不会出现。
对于这个问题我找到了一个相对合理的解答:因为sun包是hotspot虚拟机中java. 和javax.的底层实现。因为包含在rt中,所以我们也可以调用。但是因为不是sun对外公开承诺的接口,所以根据实现的需要随时增减,因此在不同版本的hotspot中可能是不同的,而且在其他的jdk实现中是没有的,调用这些类,可能不会向后兼容,所以一般不推荐使用。因此如果我们需要查看rt.jar
包下的源码就需要进行源码关联。
JDK-7u6源代码地址:http://jdk7src.sourceforge.net
下载好对应JDK版本之后,在IDEA中就可以设置。进入File->Project Structrue->SDKs->Sourcepath
中添加即可
这个时候我们再次查看AnnotationInvocationHandler
这个类,发现已经是源代码文件了,同样也在setValue
放的的调用类中成功找到了这个类
AnnotationInvocationHandler
现在我们可以继续修改我们上面写的例子,将AnnotationInvocationHandler
类加进去,尝试实例化这个类,但是由于该类不是public
的,不能直接在外部调用,因此需要用到反射去获取。
1 | import org.apache.commons.collections.functors.InvokerTransformer; |
遇到的三个问题
这里就会遇到三个问题,第一个问题是setValue
,在上面的例子中我们setValue
的值直接传入的是一个Runtime
对象,但是在AnnotationInvocationHandler
类中,这个传入的值并不是我们可控的。
第二个问题是对于Runtime
类,它并不是可序列化的,因为它没有继承Serializable
接口,因此我们也需要通过反射来实现。
第三个问题是进入AnnotationInvocationHandler
类的readObject
方法中的setValue
方法需要满足两个if条件。
反射调用Runtime
我们先解决第二个问题,将Runtime
对象通过反射实现。
1 | import java.lang.reflect.Method; |
接着我们把这个反射调用改成InvokerTransformer
的形式
1 | import org.apache.commons.collections.functors.InvokerTransformer; |
ChainedTransformer
我们可以发现,实际上是对InvokerTransformer
类的transform
方法连续调用了三次,不由想到在之前的Transformer
的实现类中有一个ChainedTransformer
,在它的transform
方法中就是一个循环调用的形式。
因此我们尝试使用ChainedTransformer
类调用
1 | import org.apache.commons.collections.Transformer; |
Target.class
接着我们继续修改两个if判断的问题。在第一个if之前首先会遍历我们传入的map并将key赋给name,此时我们拿到的name就是在map中put的key
,之后会通过memberTypes.get
方法获取name,将值赋给memberType。
由于我们现在传入的是Override.class
,在Override
中并没有存在成员方法,因此在get的时候就拿不到任何值,所以得到的memberType
就为空。
因此我们需要找一个有成员方法的class,并将map传入的key
值改为成员方法的名字,才可以进入第一层if判断,所以我们使用Target.class
代替,并将map.put
的key
值改为value
在第二个判断语句中使用isInstance
判断是否可以强转,这个判断很明显是false
,取反之后正好可以让我们进入第二层if判断,从而执行setValue
方法
ConstantTransformer
现在我们接着解决上面的第一个问题,就是需要将setValue
中的代理替换成我们的Runtime.class
,可以通过ConstantTransformer
实现。前面讲到了ConstantTransformer
的transform
方法接收一个输入并返回一个常量,因此我们只需要传入Runtime.class
即可
调用链
1 | Gadget chain: |
最终poc
1 |
|
参考链接
- https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/payloads/CommonsCollections1.java
- http://diego.team/2021/02/04/java-cc1-%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E7%AE%80%E5%8D%95%E5%88%86%E6%9E%90/
- https://paper.seebug.org/1242/
- https://www.buaq.net/go-75937.html
- https://mp.weixin.qq.com/s?__biz=MzI0MjgyNDA5NQ==&mid=2247483715&idx=1&sn=bda48a95891b8a4533fbe1535d1ac75b&chksm=e97727b3de00aea5e21cfa1407e669da095fed826733265e0beb93107e434178b8329f6cfe32&token=1359929470&lang=zh_CN#rd