Java安全之动态加载字节码( 二 )
里面是Hello.class的base64编码
注意:在 defineClass 被调用的时候,类对象是不会被初始化的,只有这个对象显式地调用其构造函数,初始化代码才能被执行 。而且,即使我们将初始化代码放在类的static块中,在 defineClass 时也无法被直接调用到 。所以 , 如果我们要使用 defineClass 在目标机器上执行任意代码,需要想办法调用构造函数 。

文章插图
因为系统的 ClassLoader#defineClass 是一个保护属性,所以我们无法直接在外部访问,不得不使用反射的形式来调用 。在实际场景中,因为defineClass方法作用域是不开放的 , 所以攻击者很少能直接利用到它,但它却是我们常用的一个攻击链 TemplatesImpl 的基石 。
利用TemplatesImpl加载字节码前面分析了defineClass方法并不好直接利用,但是Java底层还是有一些类用到了它,这就是 TemplatesImpl ,com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl 这个类中定义了一个内部类TransletClassLoader :
static final class TransletClassLoader extends ClassLoader { private final Map<String,Class> _loadedExternalExtensionFunctions; TransletClassLoader(ClassLoader parent) { super(parent); _loadedExternalExtensionFunctions = null; } TransletClassLoader(ClassLoader parent,Map<String, Class> mapEF) { super(parent); _loadedExternalExtensionFunctions = mapEF; } public Class<?> loadClass(String name) throws ClassNotFoundException { Class<?> ret = null; // The _loadedExternalExtensionFunctions will be empty when the // SecurityManager is not set and the FSP is turned off if (_loadedExternalExtensionFunctions != null) { ret = _loadedExternalExtensionFunctions.get(name); } if (ret == null) { ret = super.loadClass(name); } return ret; } /** * Access to final protected superclass member from outer class. */ Class defineClass(final byte[] b) { return defineClass(null, b, 0, b.length); }}这个类里重写了 defineClass 方法,并且这里没有显式地声明其定义域 。Java中默认情况下 , 如果一个方法没有显式声明作用域,其作用域为default 。所以也就是说这里的defineClass 由其父类的protected类型变成了一个default类型的方法,可以被类外部调用 。
从 TransletClassLoader#defineClass() 向前追溯一下调用链:
TransletClassLoader#defineClass()-> TemplatesImpl#defineTransletClasses()-> TemplatesImpl#getTransletInstance()-> TemplatesImpl#newTransformer()-> TemplatesImpl#getOutputProperties()先看TemplatesImpl#defineTransletClasses()方法:
private void defineTransletClasses() throws TransformerConfigurationException { 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 = new Class[classCount]; if (classCount > 1) { _auxClasses = new HashMap<>(); } for (int i = 0; i < classCount; i++) { _class[i] = loader.defineClass(_bytecodes[i]);//在这里调用了defineClass final Class superClass = _class[i].getSuperclass(); // Check if this is the main class if (superClass.getName().equals(ABSTRACT_TRANSLET)) { _transletIndex = i; } else { _auxClasses.put(_class[i].getName(), _class[i]); } } if (_transletIndex < 0) { ErrorMsg err= new ErrorMsg(ErrorMsg.NO_MAIN_TRANSLET_ERR, _name); throw new TransformerConfigurationException(err.toString()); } } catch (ClassFormatError e) { ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_CLASS_ERR, _name); throw new TransformerConfigurationException(err.toString()); } catch (LinkageError e) { ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name); throw new TransformerConfigurationException(err.toString()); } }
推荐阅读
- JavaScript常用工具函数
- uniapp之uni-starter小程序多端研发框架搭建与项目实践
- MySQL数据库的性能分析 ---图书《软件性能测试分析与调优实践之路》-手稿节选
- Java安全之CC6
- 如何通过Java导出带格式的 Excel 数据到 Word 表格
- 支持JDK19虚拟线程的web框架之四:看源码,了解quarkus如何支持虚拟线程
- vulnhub靶场之DRIPPING BLUES: 1
- 明日之后联盟狙击步枪怎么获取
- 硬核剖析Java锁底层AQS源码,深入理解底层架构设计
- 定位java程序中占用cpu最高的线程堆栈信息