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