前言
之前学习了大佬们对分析CC1链反序列化漏洞形成的分析,在这里写下自己对该漏洞的理解和分析。
环境
JDK:1.8.0_65
Apache Commons Collections:3.2.1
正文
触发该反序列化利用链的接口为Transformer,实现Transformer接口的主要几个类为:ChainedTransformer、ConstantTransformer、InvokerTransformer,查看这几个类的源码
首先是ChainedTransformer类
该类ChainedTransformer构造器中传入transformers[]数组直接保存到iTransformers成员变量中,重写的transform方法,而transform方法的实现则是循环调用数组中每一个元素的transform方法,并且将前一个调用的结果当做下一个调用的参数传入
ConstantTransformer类
该类构造器将存入的参数存在iConstant的成员变量中 ,调用tansform方法可以将该成员变量返回
InvokerTransformer类
该类构造器是接收接受任意的String字符串、类数组和Object数组,在transform方法中传入一个Object对象,如果该对象不为null,获取到该对象的所在类;getMethod方法是反射获取类方法,传入的两个参数为想要反射获取的方法名和该方法名的参数类型,最后通过invoke函数对反射类的方法进行调用。
了解完这些类之后,就可以写链式调用了,只要我们可以控制了InvokerTransformer类的参数,就可以成功进行反序列化,首先通过InvokerTransformer调用计算器,Runtime类没有实现Serializable接口,所以无法直接进行反序列化,currentRuntime对象是一个私有类型Runtime对象 ,但是该类有一个public类型的getRuntime,可以返回一个currentRuntime对象
通过InvokerTransformer方法就可以实现对计算机的调用
查看transform方法在哪里被调用
TransformedMap类的构造器是protected类型的,只能本类进行调用
本类中存在一个public类型的decorete静态方法调用了TransformedMap构造器,所以现在只要可以控制checkSetValue方法中的value对象,就可以进行调用,查看哪里调用了checkSetValue方法
这里setValue重写了Map.Entryd的setValue方法,所以可以通过遍历Map集合来触发调用计算器
接下来找哪里调用setValue方法
找到了sun.reflect.annotation.AnnotationInvocationHandler类,并且该类实现了Serializable接口,重写了readObject方法
该类为defaut 类型,只能被本包下调用,所以这里使用反射对AnnotationInvocationHandler类进行调用
这里先对打开计算机进行链式调用
第一个InvokerTransformer方法获取到getRuntime方法,相当于
第二个InvokerTransformer方法获取invoke方法,相当于
第三个InvokerTransformer方法获取exec方法,相当于
这里可以使用 ChainedTransformer类进行链式调用
最终形成poc为
但是运行后无法调用计算机,这里需要分析一下 AnnotationInvocationHandler类
这里有两个if,如果这两个if的条件为false时,无法调用里面的setValue方法
第一个是memberType类型不为空值,这里type是传入的Override.class,annotationType.memberTypes()为调用出入class的成员方法,所以,传入的class类中必须存在成员方法,且成员变量的key值必须与map中的key值相同,而Override.class的成员方法为空值,所以这里可以选择Target.class作为参数
Target接口中存在value的成员变量,这里也需要把map集合的key值写成value
最终需要将 valueTransformer.transform(value)的value设置为需要传入的Runtime.class
最终的POC
参考链接
Java反序列化CommonsCollections篇(一) CC1链手写EXP_哔哩哔哩_bilibili