CommonsCollections1反序列化漏洞点研究
CommonsCollections1反序列化漏洞点
Ysoserial中Payload CommonsCollections1反序列化漏洞点仍然是commons-collections-3.1版本包中的InvokerTransformer类(org.apache.commons.collections.functors.InvokerTransformer)的transform方法,并且在LazyMap(org.apache.commons.collections.map.LazyMap)的get方法中调用了Transformer(org.apache.commons.collections.Transformer)的transform方法,最终即可调用InvokerTransformer的transform方法触发漏洞:
而get方法可通过sun.reflect.annotation.AnnotationInvocationHandler做动态代理时的invoke方法调用,只需要把memberValue属性设置为LazyMap即可:
触发漏洞的入口为sun.reflect.annotation.AnnotationInvocationHandler的readObject方法,从payload的getObject方法也可以看出这一点,最终返回的就是AnnotationInvocationHandler(Gadgets.createMemoizedInvocationHandler函数返回的):
再仔细观察该payload,在createMemoizedInvocationHandler函数中调用了AnnotationInvocationHandler的newInstance方法,将mapProxy设置成了其memberValues属性:
在CommonsCollections1.java中可以看出给最终返回的AnnotationInvocationHandler设置的memberValues属性的mapProxy实际上是通过Gadgets.createMemoitizedProxy函数创建出来的一个动态代理,而该动态代理又是一个AnnotationInvocationHandler:
反序列化入口是AnnotationInvocationHandler的readObject方法,在执行this.memberValues.entrySet函数时即触发AnnotationInvocationHandler的invoke方法:
再继续看payload,payload把LazyMap的factory属性设置为了ChainedTransformer:
ChainedTransformer中存在一个iTransformers属性包含一个Transformers数组,payload依次设置为以下五个:
然后在执行transform函数时就会依次调用这五个transformer的transform函数,从而利用反射执行Runtime.exec函数:
因此整个漏洞触发的调用栈为:
AnnotationInvocationHandler.readObject
AnnotationInvocationHandler.invoke
LazyMap.get
ChainedTransformer.transform
InvokerTransformer.transform
Runtime.exec
版本影响及修补手段
查阅文档发现在CommonsCollections的3.2.2和4.1版本中因为ysoserial的CommonsCollections1和CommonsCollections2的两个漏洞禁止了不安全类的反序列化(不安全类不再实现Serializable接口),比如上面的InvokerTransformer:
因此3.2.2版本就会导致CommonsCollections1的payload失效,而经过实验3.2.1、3.2、3.1版本都是有效的,并不是ysoserial介绍说明的该payload仅支持3.1版本:
对于有效jdk的版本,ysoserial在代码中要求jdk版本<=1.8u71:
但是实际测试时发现1.8u71是会报错的,最多支持到1.8u66