类的动态加载文章目录类的动态加载[TOC](文章目录)前言一、双亲委派二、具体类加载的过程漏洞利用前言本文主要讲一下类的动态加载机制以及漏洞利用相关问题一、双亲委派双亲委派机制是 Java 类加载器的一个核心工作规则当一个类加载器需要加载某个类时它不会自己立刻去加载而是先把请求向上交给父类加载器逐级向上直到最顶层的启动类加载器Bootstrap ClassLoader只有当父加载器确认无法加载该类时子加载器才会尝试自己去加载。这样设计的好处是保证核心类库如 java.lang.*不会被重复加载或被用户自定义类“篡改”从而提升安全性和一致性同时也避免类的重复加载导致冲突。双亲委派机制是 JVM 的类加载规则类加载请求先交给父加载器处理保证核心类由 JVM 统一加载从而避免类重复定义和核心类被覆盖。publicstaticvoidmain(String[]args)throwsClassNotFoundException{Class?strClassString.class;System.out.println(String ClassLoader strClass.getClassLoader());PersondemonewPerson();System.out.println(Demo ClassLoader demo.getClass().getClassLoader());ClassLoadersystemLoaderClassLoader.getSystemClassLoader();Class?csystemLoader.loadClass(java.lang.String);System.out.println(manual load String ClassLoader c.getClassLoader());}其运行结果为String ClassLoader null表示类加载器是使用的Bootstrap ClassLoader加载的Demo ClassLoader sun.misc.Launcher$AppClassLoader14dad5dc表示使用的类加载器是AppClassLoader加载的而第三行我们使用了AppClassLoader来加载String类但是最终输出还是null说明其类的加载还是被Bootstrap ClassLoader加载类加载请求会优先交给父加载器处理导致核心类如 String始终由 Bootstrap ClassLoader 加载而用户类由 AppClassLoader 加载从而避免类冲突和核心类被覆盖二、具体类加载的过程接下来Debug一下具有类加载的过程在此处下断点有一些小伙伴点击Step Into程序直接结束我们需要强制步入按alt shift F7首先我们会进入ClassLoader类中其调用了两个参数的loadClass方法再次步入后我们会进入AppCLassLoader的loadClass方法继续跟踪前面是一些安全检查我们直接跟到super.loadClass(name, resolve)这里并步入注意这里又回到了ClassLoader的loadClass方法中且类加载器为AppClassLoader在这里就步入了双亲委派机制了该loadClass方法会首先判断其有没有父类这里其实父属性若有父类则调用其父类的类加载器而AppClassLoader的父类就是ExtClassLoader我们继续步入步入到ExtClassLoader的loadClass方法其父类为null但他的父类其实是Bootstrap ClassLoader但他是native的就显示null了继续跟跑到findClass方法我们跟进去发现跟到了URLClassLoader的findClass方法有小伙伴会好奇怎么突然出来一个URLClassLoader其实是ExtClassLoader和AppClassLoader的父类是URLClassLoader这俩没有findClass方法所以调用了父类的方法这里就开始进行类加载了首先在ExtClassLoader的类加载器中寻找Person方法但其实是找不到的继续跟代码我们会退回到AppClassLoader的loadClass方法和上面一样会调用URLCLassLoader的findClass方法这里就会成功找到Person的path最终在defineClass方法中完成类加载我们再跟一下这里需要强制步入会进入URLClassLoader的defineClass方法完成类的加载我们在跟入会先调用SecureClassLoader的defineClass再回到ClassLoader的defineClass完成类的加载这里可以画一个图总结一下类加载的过程漏洞利用作为攻击者我们就有两个点可以作为我们漏洞利用的地方首先就是URLClassLoader.loadClass我们可以注入URL使得攻击者访问我们的恶意代码从而实现攻击publicstaticvoidmain(String[]args)throwsClassNotFoundException,MalformedURLException,InstantiationException,IllegalAccessException{URLClassLoaderurlClassLoadernewURLClassLoader(newURL[]{newURL(file:D:\\evilCode\\)});Class?curlClassLoader.loadClass(org.src.Test);c.newInstance();}另一种就是使用defineClass的反射调用来实现任意类加载ClasscClassLoader.class;Methodmethodc.getDeclaredMethod(defineClass,String.class,byte[].class,int.class,int.class);method.setAccessible(true);byte[]codeFiles.readAllBytes(Paths.get(D:\\evilCode\\Test.class));ClassaClass(Class)method.invoke(ClassLoader.getSystemClassLoader(),org.src.Test,code,0,code.length);aClass.newInstance();但是这里的defineClass是protected的在真实漏洞利用的情况下使用反射并不是一种好手段关于后续动态类加载的漏洞利用再补充