前言

学习,听说Java9环境下defineClass会被拦截。


环境

JDK9.0.4

TemplatesImpl

既然defineClass会有问题,那TemplatesImpl也会有问题。

但是尝试实例化TemplatesImpl类时发现出现了编译报错问题:

Error:(3, 41) java: 程序包 com.sun.org.apache.xalan.internal.xsltc 不可见
  (程序包 com.sun.org.apache.xalan.internal.xsltc 已在模块 java.xml 中声明, 但该模块未导出它)

看起来是TemplatesImpl类被官方给黑名单了,根据描述在java.xml包下能找到module-info.java文件,里面定义了java.xml模块和包下所有导出的类,里面并不包括TemplatesImpl类,想要使用似乎要在编译设置中额外配置将其导出。

尝试通过反射实例化,然后反射调用函数,似乎没有问题:

Class<?> cls = Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl");
Object templates = cls.newInstance();
Class<?> cls2 = Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl");
Object factory = cls2.newInstance();
setField(templates, "_name", "Twings");
setField(templates, "_bytecodes", new byte[][]{bytes});
setField(templates, "_tfactory", factory);
Method m = cls.getDeclaredMethod("getOutputProperties");
m.invoke(templates);

但是会报出警告:

WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by org.example.App (file:/D:/Java1.8/Java9/target/classes/) to field com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl._name
WARNING: Please consider reporting this to the maintainers of org.example.App
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release

看起来该版本下对以往版本中为所欲为的反射操作有了警告,类似Field.set等操作都会被警告。

defineClass

defineClass也是反射,也同样会有警告:

WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by org.example.App (file:/D:/Java1.8/Java9/target/classes/) to method java.lang.ClassLoader.defineClass(byte[],int,int)
WARNING: Please consider reporting this to the maintainers of org.example.App
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release

可以使用Unsafe的defineAnonymousClass函数绕过这个问题:

Class<?> cls = Class.forName("sun.misc.Unsafe");
Field field = getField(cls, "theUnsafe");
Object unSafe = field.get(null);
Method method = unSafe.getClass().getDeclaredMethod("defineAnonymousClass", Class.class, byte[].class, Object[].class);
Class<?> c = (Class<?>)method.invoke(unSafe, new Object[]{Runtime.class, bytes, null});
c.newInstance();

不过要注意跟模板类所属包的问题。


参考

CVE-2022-26134 Confluence 无文件落地的内存马注入姿势