JAVA安全—反射机制攻击链类对象成员变量方法构造方法
前言
还是JAVA安全,哎,真的讲不完,太多啦。
今天主要是讲一下JAVA中的反射机制,因为反序列化的利用基本都是要用到这个反射机制,还有一些攻击链条的构造,也会用到,所以就讲一下。
什么是反射
Java提供了一套反射API,该API由Class类与java.lang.reflect类库组成。
该类库包含了Field、Method、Constructor等类。
对成员变量,成员方法和构造方法的信息进行的编程操作可以理解为反射机制。
从官方定义中就能找到其存在的价值,在运行时获得程序或程序集中每一个类型的成员和成员的信息,从而动态的创建、修改、调用、获取其属性,而不需要事先知道运行的对象是谁。划重点:在运行时而不是编译时。(不改变原有代码逻辑,自行运行的时候动态创建和编译即可)

参考连接:文章 - JAVA安全基础(二)-- 反射机制 - 先知社区
项目创建
创建一个Java项目,名字叫ReflectDemo。

我这里选择JAVAEE8。

把这几个东西删除掉,因为没啥用。

新建一个类叫User。

先写入以下代码,这里说明一下以下四个为成员变量,分别对应3个不同的属性,公共属性、私有属性、保护属性。
public String name = "wlw";public int age = 20;private String gender = "man";protected String job = "sec";
再写入成员方法,一个为public属性,一个为protected属性。
public void userinfo(String name, int age, String gender, String job) {this.name = name;this.age = age;this.gender = gender;this.job = job;}
protected void users(String name, String gender) {this.name = name;this.gender = gender;System.out.println("user的成员方法"+name);System.out.println("user的成员方法"+gender);}
最后再写入两个构造方法,可以看到方法名字都是User,和我们类的名字一样。
public User(){}public User(String name){System.out.println("my name"+name);}private User(String name,int age){System.out.println(name);System.out.println(age);}
Class对象类获取
OK我们的User类已经写好了,现在来获取它里面的方法。可能有人有疑惑我都知道这个类名叫User为啥还要获取它呢,是这样的,你要对一个类进行操作或者调用,首先必须要获取这个类的类名才行进行下一步,并不是说我们人知道类名就行了,还得让代码知道。
根据全限定类名获取
我们直接Class.forName(“全路径类名”),运行起来成功获取类名。
public static void main(String[] args) throws ClassNotFoundException {Class aClass = Class.forName("com.sf.maven.reflectdemo.User");System.out.println(aClass);}

根据类名获取
第二种是直接类名.class即可获取到类名
Class bClass = User.class;
System.out.println(bClass);

根据对象获取
第三种是对象.getClass()直接获取类名。
User user = new User();
Class aClass1 = user.getClass();
System.out.println(aClass1);

通过类加载器获取
第四种就是我们可以通过类加载器 ClassLoader.getSystemClassLoader().loadClass(“全路径类名”); 来获取类名。
ClassLoader clsload=ClassLoader.getSystemClassLoader();Class aClass2 = clsload.loadClass("com.sf.maven.reflectdemo.User");System.out.println(aClass2);

利用反射获取成员变量
前面我们已经获取到类名了,现在我们利用反射来获取类里面的成员变量。
新建一个类叫GetField,在里面写入我们获取成员变量的方法,先在开头加入我们获取类名的代码才行。

常见的获取成员变量的方法有以下几种。

获取所有公共成员变量
可以看到输出的是我们在User定义的两个public成员变量,name和age。
Field[] fields = aClass.getFields();
for (Field field : fields) {System.out.println(field);}

获取所有成员变量
可以看到三个不同属性的成员变量均获取到。
Field[] fields1 = aClass.getDeclaredFields();
for (Field field : fields1) {System.out.println(field);}

获取单个公共成员变量
可以看到只获取了一个name公共成员变量。
//获取单个公共成员变量Field field2 = aClass.getField("name");System.out.println(field2);

获取任意单个成员变量
可以看到无论是什么属性的成员变量都可以获取到。
//获取单个成员变量Field field3 = aClass.getDeclaredField("gender");System.out.println(field3);

成员变量的值修改和获取
看完获取成员变量了,我们再看一下对成员变量的值进行修改还有获取。
首先创建一个对象也就是获取类名,然后获取age这个公共的成员变量,接着获取user对象的age值,最后输出。
可能这里大家有点不明白,前面开头我们不是已经获取类名了,为啥这里还要获取啊。是这样的,前面获取的类名我们只是为了获取其里面的age成员变量,此时我们的age成员变量已经赋值给field4了,field4.get(user)就是获取user类里面的age值,换句话说后面的是我们要从这个User类里面得到这个age的值,也就是说我们new一个其它的类,只要这个类里面有age的成员变量,也会被获取!!!(讲的有点乱,不对还请指正)
//获取成员变量的值User user = new User();Field field4 = aClass.getField("age");Object a = field4.get(user);System.out.println(a);

接着对User类里面age的值进行修改,通过 field4.set(user,30); 修改user类里面的age值,可以看到输出为30,但是我们并没有去修改user类age成员变量的代码,这就是JAVA反射机制!!!
field4.set(user,30);
Object b = field4.get(user);
System.out.println(b);

利用反射获取构造方法
获取类中的构造方法也是有四种方式。

新建一个类叫GetConstructor,用来专门写获取构造方法的代码,同样记得再开头加上获取类名的代码才行。
获取所有公共构造方法
可以看到获取到了我们前面写好的User(String name) 和 USer() 这两个公共的成员方法。
//获取公共构造方法Constructor[] constructors1 = class1.getConstructors();for (Constructor constructor : constructors1) {System.out.println(constructor);}

获取所有构造方法
可以看到无论是public属性还是private属性的构造方法都被获取到了。
//获取所有构造方法Constructor[] constructors2 = class1.getDeclaredConstructors();for (Constructor constructor : constructors2) {System.out.println(constructor);}

获取单个公共构造方法
这个和获取所有的公共构造方法的代码差不多,只不过是指定了 String 类型的构造方法,前面我们写好的String类型的公共构造方法就只有 User(String name) 所以就返回了这个。
//获取单个公共构造方法Constructor constructor3 = class1.getConstructor(String.class);System.out.println(constructor3);

获取单个私有构造方法
和上一个的差不多,只不过是多了个Declared而已。
//获取单个私有构造方法
Constructor constructor4 = class1.getDeclaredConstructor(String.class, int.class);
System.out.println(constructor4);

对构造方法进行操作
setAccessible(true) 临时开启对私有的访问,newInstance 使用构造方法创建对象,传递参数,允许在运行时通过 Constructor 对象调用类的构造方法。
代码逻辑和上面的成员变量修改差不多,上面是从User类里面找age这个成员变量,这里是从User类里面找到符合的构造方法。可以看到我们的两个参数成功传入到 User(String name,int age) 这个构造方法里面,并且成功调用这个构造方法。
//对构造方法进行操作
Constructor constructor5 = class1.getDeclaredConstructor(String.class, int.class);
//临时开启对私有构造方法的访问
constructor5.setAccessible(true);
User uu = (User) constructor5.newInstance("wlwnb666",30);
System.out.println(uu);
利用反射获取成员方法
获取成员方法的方式也是四种,新建一个类叫GetMethod。

获取包括继承的所有公共成员方法,可以看到输出有很多公共成员方法,这是由于它连JAVA中自带的公共成员方法也一并输出了,并不单单输出我们自己写的。
//获取包括继承的所有公共成员方法Method[] methods1 = class1.getMethods();for (Method method : methods1) {System.out.println(method);}

获取不包括继承的所有成员方法,这里输出了所有我们自己写的成员方法,并没有输出JAVA内置的。
//获取不包括继承的所有成员方法Method[] methods2 = class1.getDeclaredMethods();for (Method method : methods2) {System.out.println(method);}

获取单个成员方法,这个要指定我们获取的成员方法名称为 name ,参数类型也要对应上才行。
//获取单个成员方法
Method method3= class1.getDeclaredMethod("users", String.class, String.class);
System.out.println(method3);

和上面几乎一样。
//获取单个公共成员方法
Method method4= class1.getMethod("userinfo", String.class, int.class, String.class, String.class);
System.out.println(method4);

对成员方法进行调用,对我们前面写好的 user 成语方法进行调用。
//调用成员方法
User user = new User();
Method method5= class1.getDeclaredMethod("users", String.class, String.class);
method5.invoke(user,"wlwnb666","sex");
反序列化链条构造
OK,反射的知识点基本都讲完了,那现在我们来构造以下利用链。
先简单写一个调用计算机的命令执行,这个是调用JAVA中自带的包,我们称之为原生调用。

但是我们想一想,如果是第三方的包,是不是就得要用反射机制来得到命令执行,由于这里我没有引入第三方的包,所以我们就用JAVA自带的包来做一下通过反射实现命令执行的演示,当作是外部的包即可。
首先我们可以看到这个Runtime.getRuntime().exec() 这个命令执行方法是来自 java,lang.Runtime这个类的。

那么我们就先获取类名和所有的公共成员方法,记得这里要把路径写全,不能只写Runtime。

可以看到有很多,找到getRuntime这个方法。

查询一下。

现在我们单独把这个getRuntime 获取出来。

此外我们还需获取exec方法,由于exec 需要传参String类型,所以要加String.class。
Method exec = class1.getMethod("exec", String.class);

整个链条如下,由于exec方法属于实例方法,所以所以 exec. invoke 的第一个参数是 Runtime 实例。
这里可能有人不理解第三第四行代码,一开始我也不是很懂,后来查了一下大致理解了。首先我们要知道什么是实例对象,实例指的是通过某个类(Class)创建出来的具体对象,例如:Use user = new Use() 这样就创建了一个实例。那么回到我们的代码,可以看到 getRuntime 方法返回了 currentRuntime,而currentRuntime 正是开头创建的实例,也就是说getRuntime 方法返回的是一个实例。

那么回到我们构造的链条,Object runtime = method4.invoke(class1); 调用 getRuntime 方法,并且返回一个实例赋值给 runtime ,所以 exec.invoke(runtime, "calc.exe"); 第一个参数是runtime,第二个参数才是命令。

除了上面的说到的链条构造样子,还可以这样子去构造,不过感觉没有第一种简单明了。
// 使用 Class.forName 获取 Runtime 类
Class c1 = Class.forName("java.lang.Runtime");// 获取 Runtime 类的默认构造方法
Constructor m = c1.getDeclaredConstructor();// 设置构造方法为可访问
m.setAccessible(true);// 使用反射调用 Runtime 类的 exec 方法,执行系统命令 "calc"
c1.getMethod("exec", String.class).invoke(m.newInstance(), "calc");
不安全的反射对象
指应用程序使用具有反射功能的外部输入来选择要使用的类或代码,
可能被攻击者利用而输入或选择不正确的类。绕过身份验证或访问控制检查
参考连接:悟空云课堂 | 第七期:不安全的反射漏洞 - 知乎
文章 - JAVA反序列化 - Commons-Collections组件 - 先知社区
相关文章:
JAVA安全—反射机制攻击链类对象成员变量方法构造方法
前言 还是JAVA安全,哎,真的讲不完,太多啦。 今天主要是讲一下JAVA中的反射机制,因为反序列化的利用基本都是要用到这个反射机制,还有一些攻击链条的构造,也会用到,所以就讲一下。 什么是反射…...
【深度学习】softmax回归的简洁实现
softmax回归的简洁实现 我们发现(通过深度学习框架的高级API能够使实现)(softmax)线性(回归变得更加容易)。 同样,通过深度学习框架的高级API也能更方便地实现softmax回归模型。 本节继续使用Fashion-MNIST数据集,并保持批量大小为256。 import torch …...
基础篇03-图像的基本运算
本节将简要介绍Halcon中有关图像的两类基本运算,分别是代数运算和逻辑运算。除此之外,还介绍几种特殊的代数运算。 目录 1.引言 2. 基本运算 2.1 加法运算 2.2 减法运算 2.3 乘法运算 2.4 除法运算 2.5 综合实例 3. 逻辑运算 3.1 逻辑与运算 …...
工具的应用——安装copilot
一、介绍Copilot copilot是一个AI辅助编程的助手,作为需要拥抱AI的程序员可以从此尝试进入,至于好与不好,应当是小马过河,各有各的心得。这里不做评述。重点在安装copilot的过程中遇到了一些问题,然后把它总结下&…...
面试问题知识
文章目录 1. Linux 和 CentOS基础指令:VMware 和 CentOS:扩充问题: 2. 前端开发(JS、CSS)JavaScript:CSS:扩充问题: 3. 数据库(MySQL)基础语法:事…...
Alibaba开发规范_编程规约之命名风格
文章目录 命名风格的基本原则1. 命名不能以下划线或美元符号开始或结束2. 严禁使用拼音与英文混合或直接使用中文3. 类名使用 UpperCamelCase 风格,但以下情形例外:DO / BO / DTO / VO / AO / PO / UID 等4. 方法名、参数名、成员变量、局部变量使用 low…...
MATLAB中的IIR滤波器设计
在数字信号处理中,滤波器是消除噪声、提取特征或调整信号频率的核心工具。其中,无限脉冲响应(IIR)滤波器因其低阶数实现陡峭滚降的特性,被广泛应用于音频处理、通信系统和生物医学工程等领域。借助MATLAB强大的工具箱&…...
vector容器(详解)
本文最后是模拟实现全部讲解,文章穿插有彩色字体,是我总结的技巧和关键 1.vector的介绍及使用 1.1 vector的介绍 https://cplusplus.com/reference/vector/vector/(vector的介绍) 了解 1. vector是表示可变大小数组的序列容器。…...
nginx目录结构和配置文件
nginx目录结构 [rootlocalhost ~]# tree /usr/local/nginx /usr/local/nginx ├── client_body_temp # POST 大文件暂存目录 ├── conf # Nginx所有配置文件的目录 │ ├── fastcgi.conf # fastcgi相关参…...
deepseek本地部署会遇到哪些坑
在本地部署DeepSeek(或其他类似AI模型)时,可能会遇到以下常见问题及解决方案: 1. 硬件资源不足 问题表现: GPU不兼容(如型号过旧)、显存不足(OOM错误)或CPU模式性能极低。解决方案: 确认GPU支持CUDA,检查显存需求(如至少16GB显存)。使用nvidia-smi监控显存,通过降…...
使用 PyTorch 实现逻辑回归并评估模型性能
1. 逻辑回归简介 逻辑回归是一种用于解决二分类问题的算法。它通过一个逻辑函数(Sigmoid 函数)将线性回归的输出映射到 [0, 1] 区间内,从而将问题转化为概率预测问题。如果预测概率大于 0.5,则将样本分类为正类;否则分…...
python学opencv|读取图像(五十二)使用cv.matchTemplate()函数实现最佳图像匹配
【1】引言 前序学习了图像的常规读取和基本按位操作技巧,相关文章包括且不限于: python学opencv|读取图像-CSDN博客 python学opencv|读取图像(四十九)原理探究:使用cv2.bitwise()系列函数实现图像按位运算-CSDN博客…...
【VUE案例练习】前端vue2+element-ui,后端nodo+express实现‘‘文件上传/删除‘‘功能
近期在做跟毕业设计相关的数据后台管理系统,其中的列表项展示有图片展示,添加/编辑功能有文件上传。 “文件上传/删除”也是我们平时开发会遇到的一个功能,这里分享个人的实现过程,与大家交流谈论~ 一、准备工作 本次案例使用的…...
使用真实 Elasticsearch 进行高级集成测试
作者:来自 Elastic Piotr Przybyl 掌握高级 Elasticsearch 集成测试:更快、更智能、更优化。 在上一篇关于集成测试的文章中,我们介绍了如何通过改变数据初始化策略来缩短依赖于真实 Elasticsearch 的集成测试的执行时间。在本期中࿰…...
【R语言】函数
一、函数格式 如下所示: hello:函数名;function:定义的R对象是函数而不是其它变量;():函数的输入参数,可以为空,也可以包含参数;{}:函数体,如果…...
Vue 3 30天精进之旅:Day 12 - 异步操作
在现代前端开发中,异步操作是一个非常常见的需求,例如从后端API获取数据、进行文件上传等任务。Vue 3 结合组合式API和Vuex可以方便地处理这些异步操作。今天我们将重点学习如何在Vue应用中进行异步操作,包括以下几个主题: 异步操…...
VSCode插件Live Server
简介:插件Live Server能够实现当我们在VSCode编辑器里修改 HTML、CSS 或者 JavaScript 文件时,它都能自动实时地刷新浏览器页面,让我们实时看到代码变化的效果。再也不用手动刷新浏览器了,节省了大量的开发过程耗时! 1…...
50. 正点原子官方系统镜像烧写实验
一、Windows下使用OTG烧写系统 1、在Windos使用NXP提供的mfgtool来向开发烧写系统。需要用先将开发板的USB_OTG接口连接到电脑上。 Mfgtool工具是向板子先下载一个Linux系统,然后通过这个系统来完成烧写工作。 切记!使用OTG烧写的时候要先把SD卡拔出来&…...
在C#中,什么是多态如何实现
在C#中,什么是多态?如何实现? C#中的多态性 多态性是面向对象编程的一个核心概念,他允许对象以多种形式表现.在C#中,多态主要通过虚方法,抽象方法和接口来实现. 多态性的存在使得同一个行为可以有多个不同的表达形式 即同一个接口可以使用不同的实例来执行不同的操作 虚方…...
搜索引擎友好:设计快速收录的网站架构
本文来自:百万收录网 原文链接:https://www.baiwanshoulu.com/14.html 为了设计一个搜索引擎友好的网站架构,以实现快速收录,可以从以下几个方面入手: 一、清晰的目录结构与层级 合理划分内容:目录结构应…...
扩散模型(三)
相关阅读: 扩散模型(一) 扩散模型(二) Latent Variable Space 潜在扩散模型(LDM;龙巴赫、布拉特曼等人,2022 年)在潜在空间而非像素空间中运行扩散过程,这…...
it基础使用--5---git远程仓库
it基础使用–5—git远程仓库 1. 按顺序看 -git基础使用–1–版本控制的基本概念 -git基础使用–2–gti的基本概念 -git基础使用–3—安装和基本使用 -git基础使用–4—git分支和使用 2. 什么是远程仓库 在第一篇文章中,我们已经讲过了远程仓库,每个本…...
Baklib如何改变内容管理平台的未来推动创新与效率提升
内容概要 在信息爆炸的时代,内容管理平台成为了企业和个人不可或缺的工具。它通过高效组织、存储和发布内容,帮助用户有效地管理信息流。随着技术的发展,传统的内容管理平台逐渐暴露出灵活性不足、易用性差等局限性,这促使市场需…...
100.1 AI量化面试题:解释夏普比率(Sharpe Ratio)的计算方法及其在投资组合管理中的应用,并说明其局限性
目录 0. 承前1. 夏普比率的基本概念1.1 定义与计算方法1.2 实际计算示例 2. 在投资组合管理中的应用2.1 投资组合选择2.2 投资组合优化 3. 夏普比率的局限性3.1 统计假设的限制3.2 实践中的问题 4. 改进方案4.1 替代指标4.2 实践建议 5. 回答话术 0. 承前 如果想更加全面清晰地…...
Ubuntu 下 nginx-1.24.0 源码分析 ngx_debug_init();
目录 ngx_debug_init() 函数: NGX_LINUX 的定义: ngx_debug_init() 函数: ngx_debug_init() 函数定义在 src\os\unix 目录下的 ngx_linux_config.h 中 #define ngx_debug_init() 也就是说这个环境下的 main 函数中的 ngx_debug_init() 这…...
基于人脸识别的课堂考勤系统
该项目是一个基于人脸识别的课堂考勤系统,使用Python开发,结合了多种技术实现考勤功能。要开发类似的基于人脸识别的考勤系统,可参考以下步骤: 环境搭建:利用Anaconda创建虚拟环境,指定Python版本为3.8&am…...
开启 AI 学习之旅:从入门到精通
最近 AI 真的超火,不管是工作还是生活里,到处都能看到它的身影。好多小伙伴都跑来问我,到底该怎么学 AI 呢?今天我就把自己学习 AI 的经验和心得分享出来,希望能帮到想踏入 AI 领域的朋友们! 一、学习内容有哪些 (一)编程语言 Python 绝对是首选!它在 AI 领域的生态…...
13 尺寸结构模块(size.rs)
一、size.rs源码 // Copyright 2013 The Servo Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution. // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE…...
16.[前端开发]Day16-HTML+CSS阶段练习(网易云音乐五)
完整代码 网易云-main-left-rank(排行榜) <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name&q…...
ARM嵌入式学习--第十天(UART)
--UART介绍 UART(Universal Asynchonous Receiver and Transmitter)通用异步接收器,是一种通用串行数据总线,用于异步通信。该总线双向通信,可以实现全双工传输和接收。在嵌入式设计中,UART用来与PC进行通信,包括与监控…...

