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組件 - 先知社區

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/68045.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/68045.shtml
英文地址,請注明出處:http://en.pswp.cn/web/68045.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

TfidfVectorizer

TF-IDF / Term Frequency - Inverse Document Frequency 作用:是自然語言處理NLP中常用的文本特征提取工具,用于將文本數據轉換為數據向量。 核心思想:是通過統計詞頻和逆文檔頻率來量化詞語在文本中的重要性。 T F ? I D F ( t , d ) T F…

DeepSeek-R1 論文解讀:強化學習如何 “煉” 出超強推理模型?

深度解析DeepSeek-R1:強化學習驅動大語言模型推理能力新突破 論文鏈接:DeepSeek-R1: Incentivizing Reasoning Capability in LLMs via Reinforcement Learning 在大語言模型(LLMs)飛速發展的當下,提升模型推理能力成…

【數據結構】循環鏈表

循環鏈表 單鏈表局限性單向循環鏈表判斷鏈表是否有環思路code 找到鏈表入口思路代碼結構與邏輯 code 單鏈表局限性 單鏈表作為一種基本的數據結構,雖然在很多場景下都非常有用,但它也存在一些局限性: 單向訪問:由于每個節點僅包含…

ip屬地是手機號還是手機位置?一文理清

在數字化和網絡化的今天,IP屬地這一概念逐漸成為了人們關注的焦點。特別是在社交媒體和在線平臺上,IP屬地的顯示往往讓人聯想到用戶的地理位置。然而,關于IP屬地到底與手機號還是手機位置有關,卻存在著不少誤解和混淆。本文將深入…

【嵌入】基于nomic-embed-text-v1.5和HuggingFaceEmbeddings實現

測試代碼 model_name = /media/zhangbin/DATA/DataCache/nomic-ai/nomic-embed-text-v1.5import osos.environ[HF_HOME] = /media/zhangbin/DATA/DataCache/#os.environ["TRANSFORMERS_CACHE"] = "/media/zhangbin/DATA/DataCache/" # 確保目錄結構正確 if…

離散時間傅里葉變換(DTFT)公式詳解:周期性與連續性剖析

摘要 離散時間傅里葉變換(DTFT)是數字信號處理領域的重要工具,它能將離散時間信號從時域轉換到頻域,揭示信號的頻率特性。本文將深入解讀DTFT公式,詳細闡述其具有周期性和連續性的原因,幫助讀者全面理解DT…

哈希表與散列表的原理及C++實現

1. 什么是哈希表? 哈希表(Hash Table)是一種高效的數據結構,用于存儲鍵值對(Key-Value Pairs)。它通過哈希函數(Hash Function)將鍵(Key)映射到一個固定大小…

圖像分類與目標檢測算法

在計算機視覺領域,圖像分類與目標檢測是兩項至關重要的技術。它們通過對圖像進行深入解析和理解,為各種應用場景提供了強大的支持。本文將詳細介紹這兩項技術的算法原理、技術進展以及當前的落地應用。 一、圖像分類算法 圖像分類是指將輸入的圖像劃分為…

前端框架中 HTML 的應用技巧:React、Vue、Angular 深度解析

系列文章目錄 01-從零開始學 HTML:構建網頁的基本框架與技巧 02-HTML常見文本標簽解析:從基礎到進階的全面指南 03-HTML從入門到精通:鏈接與圖像標簽全解析 04-HTML 列表標簽全解析:無序與有序列表的深度應用 05-HTML表格標簽全面…

Vue - customRef 自定義ref

customRef 作用:創建一個自定義的 ref , 并對其依賴項跟蹤和更新觸發進行邏輯控制。 在原生 ref 的基礎上,添加自己的邏輯等... 在 Vue 3 中,customRef 是一個用于創建自定義響應式引用的 API。它允許開發者控制和優化響應式引用的行為&…

數字化轉型:概念性名詞淺談(第四講)

?大家好,本篇文章是在新年之際寫的,所以在這里先給大家拜個年。 今天要介紹的名詞為ETL: ETL,是英文Extract-Transform-Load的縮寫,用來描述將數據從來源端經過抽取(extract)、轉換(transfor…

UE學習日志#22 C++筆記#8 基礎復習8 string和string_view2

1 std::string_view類 string_view基本上就是const string&的簡單替代品,但不會產生開銷。他不復制字符串。 string_view添加了remove_prefix(size_t)和remove_suffix(size_t)方法,前者將起始指針給定的偏移量來收縮字符串,后者則將結尾指…

UVM factory機制

目錄 1. factory-register 1.1 uvm_object_registry#(type T=uvm_object, string Tname="") 1.1 uvm_default_factory::register 2. factory-override 2.1 set_type_override(uvm_object_wrapper override_type) 2.2 set_inst_override(uvm_object_wrapper ove…

Spring MVC學習——發送請求(@RequestMapping注解及請求參數綁定)

前言 Spring MVC作為Spring框架中的核心組件之一,其強大的功能在于能簡潔高效地處理HTTP請求和響應。在開發Web應用時,理解和正確使用Spring MVC的注解,尤其是RequestMapping注解,至關重要。本文將詳細講解RequestMapping注解的使…

C# Action和 Func的用法

C#中的數據類型 函數數據類型 Action 是一個數據類型 但是是沒有返回值得函數數據類型 Func 用于指定一個有返回值的委托 internal class Program{static void Main(string[] args){TT.F1(NoVoid);TT.F2(Void1);Void2(() > { Console.WriteLine("Void2執行了");…

C++中的模板(上)

C中的模板(上) 模板參數和函數參數是很像的,函數參數定義的形參對象,而模板參數定義的是類型. 模板分為函數模板和類模板 函數模板 一個交換兩個數的函數模板: template<class T> // 此處typename和class是等價的 void Swap(T &a, T &b) {T temp a;a b;b …

MySQL面試題----如何進行 MySQL 數據庫備份與恢復

MySQL 數據庫備份 1. 使用 mysqldump 工具(邏輯備份) 全量數據庫備份 該方式會備份指定數據庫中的所有數據和表結構。在命令行中輸入以下命令,將 username 替換為你的 MySQL 用戶名,password 替換為對應的密碼,database_name 替換為要備份的數據庫名,backup.sql 為備份文…

Java集合面試總結(題目來源JavaGuide)

問題1&#xff1a;說說 List,Set,Map 三者的區別&#xff1f; 在 Java 中&#xff0c;List、Set 和 Map 是最常用的集合框架&#xff08;Collection Framework&#xff09;接口&#xff0c;它們的主要區別如下&#xff1a; 1. List&#xff08;列表&#xff09; 特點&#xf…

deepseek接入pycharm 進行AI編程

要將DeepSeek接入PyCharm進行AI編程,可以按照以下步驟操作: ### 1. 獲取DeepSeek API訪問權限 DeepSeek通常以API的形式對外提供服務,你需要在其官方網站注冊賬號,申請API訪問權限。在申請通過后,會獲得API密鑰(API Key),這是后續調用API的關鍵憑證。 ### 2. 安裝必要…

奧迪改名風波再起,A6L能否率隊創下新奇跡

文/王俁祺 導語&#xff1a;春節假期剛過&#xff0c;奧迪的車型命名規則又變了。在如今以內卷為主基調的環境下&#xff0c;車型改名可不是小事&#xff0c;而奧迪的這次調整背后藏著許多深意&#xff0c;也預示著2025年奧迪在產品布局上的新動向。 改名能否“改命” 回溯到…