ClassLoader类加载机制

一切的Java类都需要经过JVM加载后才能运行,而ClassLoader的主要作用就是Java类文件的加载。
JVM类加载器:

  • Bootstrap ClassLoader(启动类加载器):负责加载jdk核心类库:rt.jar、resources.jar、charsets.jar
  • Extension ClassLoader(扩展类加载器):负责加载Java的扩展类库,默认加载JAVA_HOME/jre/lib/ext/目下的所有jar。
  • App ClassLoader(系统类加载器):负责加载应用程序classpath目录下的所有jar和class文件。

AppClassLoader是默认的类加载器,如果类加载时我们不指定类加载器的情况下,默认会使用AppClassLoader加载类,ClassLoader.getSystemClassLoader()返回的系统类加载器也是AppClassLoader

某些时候我们获取一个类的类加载器时候可能会返回一个null值,如:java.io.File.class.getClassLoader()将返回一个null对象,因为java.io.File类在JVM初始化的时候会被Bootstrap ClassLoader(启动类加载器Natives)加载(该类加载器实现于JVM层,采用C++编写),我们在尝试获取被Bootstrap ClassLoader类加载器所加载的类的ClassLoader时候都会返回null

ClassLoader类有如下核心方法:

  1. loadClass(加载指定的Java类)
  2. findClass(查找指定的Java类)
  3. findLoadedClass(查找JVM已经加载过的类)
  4. defineClass(定义一个Java类)
  5. resolveClass(链接指定的Java类)

Java动态类加载方式

  • 显式:通过Java反射或者ClassLoader来动态加载一个类对象

    image.png

  • 隐式:类名.方法名()、new类实例

    自定义ClassLoader

    Java.lang.ClassLoader是所有的类加载器的父类;
    类加载器的继承机制:
    image.png

  • URLClassLoader继承了ClassLoaderURLClassLoader提供了加载远程资源的能力,在写漏洞利用的payload或者webshell的时候我们可以使用这个特性来加载远程的jar来实现远程的类方法调用。

    什么是Java的字节码

    Java一直以来都称为是,一次编写到处运行。是因为运行在不同的平台的JMV能够载入和执行同一种与平台无关的字节码。 源代码中的各种变量,关键字和运算符号的语义最终都会编译成多条字节码命令。而字节码命令所能提供的语义描述能力是要明显强于Java本身的,所以有其他一些同样基于JVM的语言能提供许多Java所不支持的语言特性。
    image.png

    利用URLClassLoader加载远程class文件

    URLClassLoader 实际上是我们平时默认使用的 AppClassLoader 的父类。那么讨论URLClassLoader实际上就是解释默认类加载的过程。

    正常情况下,Java会根据配置项 sun.boot.class.path 和 java.class.path 中列举到的基础路径(这 些路径是经过处理后的 java.net.URL 类)来寻找.class文件来加载,而这个基础路径有分为三种情况:

    • URL未以斜杠 / 结尾,则认为是一个JAR文件,使用 JarLoader 来寻找类,即为在Jar包中寻找.class文件
    • URL以斜杠 / 结尾,且协议名是 file ,则使用 FileLoader 来寻找类,即为在本地文件系统中寻找.class文件
    • URL以斜杠 / 结尾,且协议名不是 file ,则使用最基础的 Loader 来寻找类

我们正常开发的时候通常遇到的是前两者,那什么时候才会出现使用 Loader 寻找类的情况呢?当然是
非 file 协议的情况下,最常见的就是 http 协议。

Java的URLClassLoader支持哪一些协议-file,ftp,gopher,http,https,jar,mailto,netdoc

测试一下Java能否借助URLClassLoader发起Http请求去请求对应服务器上的class字节码,python拉起一个http服务(该服务对应的文件路径就是拉起http服务的路径)。
image.png
如图所示:作为攻击者,如果我们能够控制目标Java ClassLoader的基础路径为一个http服务器,则可以利
用远程加载的方式执行任意代码了。

Java 文件系统

Java 本地命令执行

  • Runtime命令执行
  • ProcessBuilder命令执行
  • 反射UNIXProcess/ProcessImpl执行本地命令
  • forkAndExec命令执行-Unsafe+反射+Native方法调用
  • JNI命令执行