第一次分析cc链看了好几天,Java基础也不太好真的看吐了,基本所有知识都是从头开始学,感谢大哥支持解惑
什么是cc1
Apache Commons Collections是一个扩展了Java标准库里的Collection结构的第三方基础库,它提供了很多强有力的数据结构类型并且实现了各种集合工具类。作为Apache开源项目的重要组件,Commons Collections被广泛应用于各种Java应用的开发.
而cc1就是利用common collections实现命令执行的一条调用链
java知识–Transformer接口
Transformer
Transformer是一个接口,任何implements它的类都要实现transform方法
ConstantTransformer
ConstantTransformer类是一个implements了transformer和serializable的类,也就意味着这个类可以序列化、反序列化。
ConstantTransformer重写的transform方法会返回一个常量对象,首先是public构造器保存到iConstant,然后transform方法返回iConstant常量
1 | Transformer transformer=new ConstantTransformer(Runtime.getRuntime()); |
单纯看这个好像确实没啥用
InvokerTransformer
InvokerTransformer算是cc1反序列化中比较重要的一个类了。
InvokerTransformer也是implements了transformer接口,看它的构造函数里面的参数内容可以看到非常像invoke方法所需要的
然后看它的transform怎么写的:
其实就是invoke的写法。先尝试把弹calc的反射代码通过InvokerTransformer写出来
1 | InvokerTransformer it1=new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime",null}); |
其实写下来这几个InvokerTransformer之后我对invoke以及InvokerTransformer的构造方法了解更深一步,首先看第一行InvokerTransformer,目的是通过Class类的getmethod方法找到getRuntime方法,但是是谁的getRuntime方法呢?现在还没说。然后看构造方法传递的参数,第一个是方法名,第二个是class [] paramTypes,第三个是args,也就是说第一个参数是方法名,第二个参数是一个数组,数组内容是方法名(第一个参数传递的方法)参数的类型,第三个参数是实际要传递的参数。
在第二行调用完transform方法后,我们下断点调试看一下:
进到transform方法之后,由于传递的是Runtime.class,所以object input也就是runtime.class
这句话其实翻译过来就是找到Runtime下的getRuntime方法,后面的invoke也就是找到并返回这个方法
。
第二个transformer和transform的结果就是调用了getRuntime()方法,类似getRuntime.invoke(Runtime,null),得到的是一个Runtime实例。
第三个transformer和transform的结果就是getRuntime().exec(xxx),在transform方法中的形式是exec.invoke(Runtime,”calc”);
最终弹出来了计算器。
ChainedTransformer
串连起来的transformer,分别调用各个transformer的transform方法,顺序调用。
因为Object是迭代的,所以说第一个transformer.transform()之后的object作为第二个transformer.transform()的输入。
将上面的InvokerTransformer转为ChainedTransformer写法:
1 | Transformer []transformers=new Transformer[]{ |
TransformedMap
TransformedMap的某些方法可以调用到ChainedTransformer的transform方法。
Map.Entry
Map的entrySet()方法返回一个实现Map.Entry接口的对象集合。集合中每个对象都是底层Map中一个特定的键/值对。通过这个集合的迭代器,获得每一个条目(唯一获取方式)的键或值并对值进行更改。
个人理解的话就是一个迭代器遍历map的每一个key/value对,通过Map.Entry entry对各个k/v进行getvalue、setvalue等操作。
debug一下setValue方法
继续跟进checksetvalue方法,有意思的来了,跟到了transformedMap类中的checkSetValue方法,返回的是**valueTransformer.transform(value)**,而valueTransformer正是我们传入的ChainedTransformer,那么是不是就跟到了ChainedTransformer的transform方法中呢?
可以发现跟到了ChainedTransformer类中的transform方法。那么我们就可以使用TransformedMap类利用ChainedTransformer实现命令执行。
LazyMap
LazyMap 和 TransformedMap 类似,都来自于 Common-Collections 库,并继承 AbstractMapDecorator
LazyMap 的漏洞触发点和 TransformedMap 唯一的差别是,TransformedMap 是在写入元素的时候执行 transform,而 LazyMap 是在其 get 方法中执行的 factory.transform 。其实这也好理解,LazyMap 的作用是“懒加载”,在 get 找不到值的时候,它会调用 factory.transform 方法去获取一个值。
下面尝试使用LazyMap进行命令执行
调试一下,跟进decorate方法
然后是get方法
get的意思是如果找不到key的话,则会调用factory的transform方法,factory是我们传入的ChainedTransformer。
那么在这个过程中就自动调用了ChainedTransformer.transform()方法,执行了我们想要的命令。
构造调用链
目前知道的是通过ChainedTransformer的transform方法可以直接命令执行,但是肯定不能让服务器端手动执行的,目标是找到一个在反序列化过程中,通过某些中间调用过程一步步调用到ChainedTransformer.transform()方法,下面将一步步分析。
LazyMap.get()->ChainedTransformer.transform()
上面在说lazyMap的时候已经提到了,这里再重复一下代码
1 | Transformer []transformers=new Transformer[]{ |
这样通过lazyMap.get()方法可以命令执行了,下面需要找的是怎么能跳转到LazyMap.get()方法
AnnotationInvocationHandler.invoke()->LazyMap.get()
AnnotationInvocationHandler implement了 InvocationHandler和Serializable接口,意味着它是一个调用处理器并且可以反序列化,重写了invoke()方法。
接下来看AnnotationInvocationHandler的invoke方法怎么写的:
注意看构造器中的membervalues是一个map,是我们可控的,同时invoke方法在检测到method.getName()不是toString、hashCode、annotationType时会调用memberValues的get方法,这正是我们需要找的利用点。现在需要做的是怎么才能到AnnotationInvocationHandler.invoke()这个方法?
AnnotationInvocationHandler.readObject()->memberValues.entrySet()->AnnotationInvocationHandler.invoke()
当调用动态代理代理对象的任意方法的时候,都会触发代理类重写的invoke方法,那么在AnnotationInvocationHandler.readObject()中调用了 memberValues.entrySet()方法,那么当前的memberValues也就是evilmap,调用了这个代理map的某个方法(**entrySet()),所以会转到代理类(AnnotationInvocationHandler)重写的invoke()**方法中去.
完整代码如下:
1 | package ysoserial.test; |
那么整体调用链如下:
1 | ObjectInputStream.readObject()//服务器读取对象 |
参考
https://www.freebuf.com/sectool/320360.html
https://zhuanlan.zhihu.com/p/349838623
https://www.bilibili.com/video/BV1no4y1U7E1?spm_id_from=333.337.search-card.all.click