cc1调用链
1. 配置环境:
cc1调用链需要环境如下:
- jdk1.8.0_65
- commons-collections 版本号为
3.2.1
- jdk1.8_65源码
- 下载
jdk 8u65
Oracle JDK 8u65 全平台安装包下载 - 码霸霸 (lupf.cn) - 导入坐标如下
1 |
|
- 解压jdk1.8.0_65下是src文件,将jdk1.8.0_65源码中的
src/share/clasess/sun
添加到你配置的1.8.0_65中的src
目录中。
教程:
Java反序列化CommonsCollections篇(一) CC1链手写EXP_哔哩哔哩_bilibili
2. 思路:
从调用危险方法到调用顶层readObject
实现反序列化
3. 探索:
3.1 简单找个危险函数:
- 突破口 transform方法:
找到一个接口,查看他的实现类
找到一个InvokerTranformer
类的transform
方法,接收参数是可控的,即获取了当前传入obejct类,然后调用反射去调用成员变量的函数名和函数参数,找到他的构造函数
第一个参数是方法名,第二个参数是参数类型,第三个参数是参数值。我们通过构造函数然后去调用transform
方法即可调用我们传入类的方法了。
我们任意调用的方法是这样的Runtime.getRuntime().exec("calc");
这里使用InvokerTransformer
就是这样:
1 |
|
- 解决Runtime不能反序列化
找到突破口之后,我们要想readObject
方法是反序列化才会使用,但是Runtime
没有实现SSerializable
方法,因此不能实现反序列化。
如何解决?Class类都是可序列化的,因此我们序列化Runtime.class
。
查看源码发现,Runtime
类的构造方法都是私有的,只有一个静态方法getRuntime
返回currentRuntime
,用到的是单例模式。因此只能反射调用getRuntime
。
1 |
|
- 首先获取Runtime.class这个class对象
- 然后调用
getRuntime
静态方法获取当前的runtimeClassMethod
方法。 - 然后使用
runtimeClassMethod
方法类去invoke
,即调用getRuntime
方法,invoke
方法第一个参数是类的实例对象,第二个参数是这个方法执行的参数。因为需要Runtime
类才能调用这个私有方法,因此第一个参数是我们上面获取到的对象。
3.2 TransformedMap类:
上面我们查找到了调用TransformedMap
类中的checkSetValue
方法,我们接着网上找,发现AbstractInputCheckedMapDecorator
类中的内部类MapEntry
的setValue
方法调用了他,只要我们执行map的setValue
将我们上面的Object Input
传入进去就可以执行了,如下:
发现是AbstractInputCheckedMapDecorator
中的MapEntry
的setValue
方法。
编写构造链如图所示:
1 |
|
继续网上查询,查找谁调用了setValue()
方法,发现存在许多方法,我们的目的是查找readObejct
方法,在readObejct
方法中调用setValue()
方法既可以实现放序列化,查找到sun.reflect.annotation
包中的AnnotationInnvocationHandler
的readObejct
方法调用了AbstractInputCheckedMapDecorator
中的setVale()
方法。
至此调用链就清楚了:
readObjetc
中的判断如下:
- 将我们的map的key设置为一个注解中的成员变量,如
Target
注解存在一个成员变量value
。
然后创建一个代理对象,去调用了我们熟悉的AbstractInputCheckedMapDecorator
的setValue
方法。
因此思路在于如何修改这个parent
对象的属性,可以没有办法。查找其他transform
发现ConstantTransformer
中transform
不管输入什么都是调用他的成员变量,因此可以只要我们在创建的时候将Runtime.class
赋值给他的成员变量,然后去调用transform
方法就会返回Runtime.class
3.3 完整exp:
1 |
|
4. 疑惑:
4.1 疑惑点一:为什么要加上new ConstantTransformer(Runtime.class)?
开始我们知道使用chainedTransformer中的transfomer
方法可以方便我们去调用,我们传入多个对象就会不断循环去调用这些对象的transfomer
方法。
如图:
我们只要将我们需要传入的Runtime.class
就可以实现我们的链路了。