漏洞分析 | Spring Framework路径遍历漏洞(CVE-2024-38816)

漏洞概述

VMware Spring Framework是美国威睿(VMware)公司的一套开源的Java、JavaEE应用程序框架。该框架可帮助开发人员构建高质量的应用。

近期,网宿安全演武实验室监测到Spring Framework在特定条件下,存在目录遍历漏洞(网宿评分:高危、CVSS 3.1 评分:7.5):

当同时满足使用 RouterFunctions 和 FileSystemResource 来处理和提供静态文件时,攻击者可构造恶意请求遍历读取系统上的文件。

目前该漏洞POC状态已在互联网公开,建议客户尽快做好自查及防护。

受影响版本

Spring Framework 5.3.0 - 5.3.39

Spring Framework 6.0.0 - 6.0.23

Spring Framework 6.1.0 - 6.1.12

其他更旧或者官方已不支持的版本

漏洞分析

根据漏洞描述(https://spring.io/security/cve-2024-38816)可知,关键变更在于如何处理静态资源路径。

https://github.com/spring-projects/spring-framework/commit/d86bf8b2056429edf5494456cffcb2b243331c49#diff-25869a3e3b3d4960cb59b02235d71d192fdc4e02ef81530dd6a660802d4f8707R4

这里改了两处,分别是:

webflux --> org.springframework.web.reactive.function.server.PathResourceLookupFunction

webmvc --> org.springframework.web.servlet.function.PathResourceLookupFunction

它们都旨在为 Web 应用程序提供静态内容的访问。

以webmvc --> org.springframework.web.servlet.function.PathResourceLookupFunction为例,展开分析。

先是动态处理了资源请求,确保只返回有效并且可访问的资源。

@Override
public Optional<Resource> apply(ServerRequest request) {PathContainer pathContainer = request.requestPath().pathWithinApplication();if (!this.pattern.matches(pathContainer)) {return Optional.empty();}pathContainer = this.pattern.extractPathWithinPattern(pathContainer);String path = processPath(pathContainer.value());if (path.contains("%")) {path = StringUtils.uriDecode(path, StandardCharsets.UTF_8);}if (!StringUtils.hasLength(path) || isInvalidPath(path)) {return Optional.empty();}try {Resource resource = this.location.createRelative(path);if (resource.isReadable() && isResourceUnderLocation(resource)) {return Optional.of(resource);}else {return Optional.empty();}}catch (IOException ex) {throw new UncheckedIOException(ex);}
}

接着对路径字符串进行规范化处理,确保返回的路径格式是有效的。

private String processPath(String path) {boolean slash = false;for (int i = 0; i < path.length(); i++) {if (path.charAt(i) == '/') {slash = true;}else if (path.charAt(i) > ' ' && path.charAt(i) != 127) {if (i == 0 || (i == 1 && slash)) {return path;}path = slash ? "/" + path.substring(i) : path.substring(i);return path;}}return (slash ? "/" : "");
}

最后从安全角度,确保路径不指向敏感目录,并且避免出现路径穿越的情况。

private boolean isInvalidPath(String path) {if (path.contains("WEB-INF") || path.contains("META-INF")) {return true;}if (path.contains(":/")) {String relativePath = (path.charAt(0) == '/' ? path.substring(1) : path);if (ResourceUtils.isUrl(relativePath) || relativePath.startsWith("url:")) {return true;}}return path.contains("..") && StringUtils.cleanPath(path).contains("../");
}

简单阐明以后,不难发现上述代码做了敏感目录检查、url检查、路径穿越检查等操作,暂时没发现可疑点,所以我们需要进一步跟进

org.springframework.web.servlet.function.PathResourceLookupFunction#isInvalidPath()

查看一下它检查相对路径时,StringUtils.cleanPath()做了哪些操作。

public static String cleanPath(String path) {if (!hasLength(path)) {return path;}String normalizedPath;// Optimize when there is no backslashif (path.indexOf('\\') != -1) {normalizedPath = replace(path, DOUBLE_BACKSLASHES, FOLDER_SEPARATOR);normalizedPath = replace(normalizedPath, WINDOWS_FOLDER_SEPARATOR, FOLDER_SEPARATOR);}else {normalizedPath = path;}String pathToUse = normalizedPath;// Shortcut if there is no work to doif (pathToUse.indexOf('.') == -1) {return pathToUse;}// Strip prefix from path to analyze, to not treat it as part of the// first path element. This is necessary to correctly parse paths like// "file:core/../core/io/Resource.class", where the ".." should just// strip the first "core" directory while keeping the "file:" prefix.int prefixIndex = pathToUse.indexOf(':');String prefix = "";if (prefixIndex != -1) {prefix = pathToUse.substring(0, prefixIndex + 1);if (prefix.contains(FOLDER_SEPARATOR)) {prefix = "";}else {pathToUse = pathToUse.substring(prefixIndex + 1);}}if (pathToUse.startsWith(FOLDER_SEPARATOR)) {prefix = prefix + FOLDER_SEPARATOR;pathToUse = pathToUse.substring(1);}String[] pathArray = delimitedListToStringArray(pathToUse, FOLDER_SEPARATOR);// we never require more elements than pathArray and in the common case the same numberDeque<String> pathElements = new ArrayDeque<>(pathArray.length);int tops = 0;for (int i = pathArray.length - 1; i >= 0; i--) {String element = pathArray[i];if (CURRENT_PATH.equals(element)) {// Points to current directory - drop it.}else if (TOP_PATH.equals(element)) {// Registering top path found.tops++;}else {if (tops > 0) {// Merging path element with element corresponding to top path.tops--;}else {// Normal path element found.pathElements.addFirst(element);}}}// All path elements stayed the same - shortcutif (pathArray.length == pathElements.size()) {return normalizedPath;}// Remaining top paths need to be retained.for (int i = 0; i < tops; i++) {pathElements.addFirst(TOP_PATH);}// If nothing else left, at least explicitly point to current path.if (pathElements.size() == 1 && pathElements.getLast().isEmpty() && !prefix.endsWith(FOLDER_SEPARATOR)) {pathElements.addFirst(CURRENT_PATH);}final String joined = collectionToDelimitedString(pathElements, FOLDER_SEPARATOR);// avoid string concatenation with empty prefixreturn prefix.isEmpty() ? joined : prefix + joined;
}

这个方法主要对用户输入路径做了规范化处理,具体包括长度检查、不同操作系统下的路径分隔符处理等。看起来也做了严格的处理,但这一步存在问题。

String[] pathArray = delimitedListToStringArray(pathToUse, FOLDER_SEPARATOR);

具体来说,它是允许空元素存在的,假设路径字符串形如:

String pathToUse = "/static///../../Windows/win.ini";

那么调用 delimitedListToStringArray 方法以后,pathArray即为

["static", "", "", "..", "..", "Windows", "win.ini"]

而pathElements即为

再来看这一串:String pathToUse = "/static/../../Windows/win.ini";

显然,pathArray中存在空元素会影响上级目录的处理,导致返回不同的结果,即存在安全隐患。

漏洞复现

实现目录穿越需要用到"../",结合上述分析,可通过这种方式实现。

package org.example.demo;

import org.springframework.util.ResourceUtils;
import org.springframework.util.StringUtils;

public class test {
public static void main(String[] args) {
String path = "/static///../../Windows/win.ini";
System.out.println(isInvalidPath(path));
}

private static boolean isInvalidPath(String path) {
if (path.contains("WEB-INF") || path.contains("META-INF")) {
return true;
}
if (path.contains(":/")) {
String relativePath = (path.charAt(0) == '/' ? path.substring(1) : path);
if (ResourceUtils.isUrl(relativePath) || relativePath.startsWith("url:")) {
return true;
}
}
return path.contains("..") && StringUtils.cleanPath(path).contains("../");
}
}

但还需要结合上下文,继续构造payload。首先路径以斜杠开头时,StringUtils.cleanPath()方法会去掉路径的第⼀个斜杠。

if (pathToUse.startsWith(FOLDER_SEPARATOR)) {prefix = prefix + FOLDER_SEPARATOR;pathToUse = pathToUse.substring(1);
}

那就需要多写一条"/",构造"///../"跳一级目录。

而在最初的org.springframework.web.servlet.function.PathResourceLookupFunction#apply()中,对路径做了规范化处理,即去掉连续的"/"

pathContainer = this.pattern.extractPathWithinPattern(pathContainer);
String path = processPath(pathContainer.value());

所以需要将多余的"/"变为"\",再借助StringUtils.cleanPath()方法重新转换回来。

normalizedPath = replace(normalizedPath, WINDOWS_FOLDER_SEPARATOR, FOLDER_SEPARATOR);

修复方案

目前官方已有可更新版本,建议受影响用户升级至最新版本:

https://github.com/spring-projects/spring-framework/tags

产品支持

网宿全站防护-WAF已支持对该漏洞利用攻击的防护,并持续挖掘分析其他变种攻击方式和各类组件漏洞,第一时间上线防护规则,缩短防护“空窗期”。

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

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

相关文章

tp接口 入口文件 500 错误原因

一、描述 二、可能的原因 1、runtime目录没权限 2、关闭了Tp记录日志的功能 3、关闭debug调试模式 4、关闭了debug模式还是报错 一、描述 Thinkphp项目本地正常&#xff0c;上传到线上后静态文件访问正常&#xff0c;访问tp接口报500错误。 经调试发现&#xff0c;在php入…

第07章 运算符的使用

一、算数运算符 算术运算符主要用于数学运算&#xff0c;其可以连接运算符前后的两个数值或表达式&#xff0c;对数值或表达式进行加 &#xff08;&#xff09;、减&#xff08;-&#xff09;、乘&#xff08;*&#xff09;、除&#xff08;/&#xff09;和取模&#xff08;%&a…

十七 MyBatis的注解式开发

十七、MyBatis的注解式开发 mybatis中也提供了注解式开发方式&#xff0c;采用注解可以减少Sql映射文件的配置。 当然&#xff0c;使用注解式开发的话&#xff0c;sql语句是写在java程序中的&#xff0c;这种方式也会给sql语句的维护带来成本。 官方是这么说的&#xff1a; 使…

用 Python 写了一个天天酷跑(附源码)

Hello&#xff0c;大家好&#xff0c;给大家说一下&#xff0c;我要开始装逼了 这期写个天天酷跑玩一下叭&#xff01; 制作一个完整的“天天酷跑”游戏涉及很多方面&#xff0c;包括图形渲染、物理引擎、用户输入处理、游戏逻辑等。由于Python是一种高级编程语言&#xff0c;…

Kettle——CSV文件转换成excel文件输出

1.点击—文件—新建—转换 拖入两个组件&#xff1a; 按shift&#xff0b;鼠标左击建立连接&#xff0c;并点击主输出步骤&#xff0c; 点击CSV文件输入&#xff0c;选择浏览的csv文件&#xff0c;然后点击确定 同样&#xff0c;Excel也同上&#xff0c;只是要删除这个xls 并…

高效管理iPhone存储:苹果手机怎么删除相似照片

在使用iPhone的过程中&#xff0c;我们经常会遇到存储空间不足的问题&#xff0c;尤其是当相册中充满了大量相似照片时。这些照片不仅占用了宝贵的存储空间&#xff0c;还可能使iPhone出现运行卡顿的情况。因此&#xff0c;我们迫切需要寻找苹果手机怎么删除相似照片的方法&…

用示例来看C2Rust工具的使用和功能介绍

C2Rust可以将C语言的源代码转换成Rust语言的源代码。下面是一个简单的C语言代码示例&#xff0c;以及使用c2Rust工具将其转换为Rust安全代码的过程。 C语言源代码示例 // example.c #include <stdio.h>int add(int a, int b) {return a b; }int main() {int result a…

赛普EAP平台 Download.aspx 任意文件读取漏洞复现

0x01 产品描述&#xff1a; ‌赛普EAP平台‌是一款专门为房地产企业打造的数字化管理系统&#xff0c;旨在帮助企业实现业务流程的优化、管理效率的提升和客户体验的改善。该系统集成了项目管理、销售管理、客户关系管理、财务管理、报表分析等多个模块&#xff0c;能够满足企业…

前端三件套-css

一、元素选择器 元素选择器&#xff1a;利用标签名称。p,h1-h6...... 行内样式&#xff08;内联样式&#xff09;&#xff1a;例如<p style"color:red;font-size:50px"> id选择器&#xff1a;针对某一个特定的标签来使用。以#定义。 class&#xff08;类&a…

服务器被攻击排查记录

起因 我的深度学习的所有进程突然被killed&#xff0c;我以为是检修&#xff0c;后面发现好像简单的python代码可以正常运行。但是我的训练进程一启动就会被killed 第一时间没有用htop查看cpu&#xff0c;用top看着挺正常的&#xff0c;但是后面看htop&#xff0c;全是绿的&a…

项目实战:基于Linux的Flappy bird游戏开发

一、项目介绍 项目总结 1.按下空格键小鸟上升&#xff0c;不按小鸟下落 2.搭建小鸟需要穿过的管道 3.管道自动左移和创建 4.小鸟撞到管道游戏结束 知识储备 1.C语言 2.数据结构-链表 3.Ncurses库 4.信号机制 二、Ncurses库介绍 Ncurses是最早的System V Release 4.0 (SVr4)中…

抖音小程序看广告变现秘籍:构建用户粘性与点击收益长期价值解析

在抖音小程序看广告变现的宏伟蓝图中&#xff0c;构建用户粘性和挖掘用户长期价值是核心环节&#xff0c;这是实现丰厚收益和打造高效盈利新引擎的重要保障。 要构建用户粘性&#xff0c;首先要提供优质且持续更新的内容。以一个知识科普类小程序为例&#xff0c;需要不断推出新…

L0G1000:Linux+InternStudio 闯关作业

1. 配置基础环境 首先&#xff0c;打开 Intern Studio 界面&#xff0c;点击 创建开发机 配置开发机系统。 InternStudio 填写 开发机名称 后&#xff0c;点击 选择镜像 使用 Cuda11.7-conda 镜像&#xff0c;然后在资源配置中&#xff0c;使用 10% A100 * 1 的选项&#xff…

【ArcGISPro】单次将自己建立的工具箱添加至Arcpy中

新建工具箱 添加至Arcpy中 调用刚添加的工具箱

【vue2.7.16系列】手把手教你搭建后台系统__登录使用状态管理(15)

使用store进行登录信息管理 其实就是把登录放到vuex的actions中去执行&#xff0c;然后保存用户信息、权限等 在store/modules/account.js中添加如下代码&#xff1a; import { login, logout, getInfo, menusApi } from /api/account; // getExpiresTime import {getToken,s…

Java项目实战II基于Spring Boot的秒杀系统设计与实现(开发文档+数据库+源码)

目录 一、前言 二、技术介绍 三、系统实现 四、文档参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。 一、前言 在互联网电商蓬勃发展的今天&#xff0…

HTML5实现小鸟过管道小游戏源码

文章目录 1.设计来源1.1 主界面1.2 游戏中主界面1.3 游戏结束界面 2.效果和源码2.1 动态效果2.2 源代码 源码下载万套模板&#xff0c;程序开发&#xff0c;在线开发&#xff0c;在线沟通 作者&#xff1a;xcLeigh 文章地址&#xff1a;https://blog.csdn.net/weixin_43151418/…

基础算法练习--滑动窗口(日更中)

算法介绍 滑动窗口算法来自tcp协议的一种特性,它的高效使得其也变成了算法题的一种重要考点.滑动窗口的实现实际上也是通过两个指针前后遍历集合实现,但是因为它有固定的解题格式,我将其单独做成一个篇章. 滑动窗口的解题格式: 首先,定义两个指针left和right,与双指针不同的…

C#如何快速获取P/Invoke方法签名

使用API函数已经好几年了&#xff0c;封装函数签名基本是参照MSDN上的文档&#xff0c;然后再做数据类型对应。 虽然有 pinvoke.net 这个网站&#xff0c;但基本很少使用。一方面是想多动手&#xff0c;另一方面是因为各种数据类型基本都用过了&#xff0c;都能自己在C#中 对应…

人脑与机器连接:神经科技的伦理边界探讨

内容概要 在当今科技飞速发展的时代&#xff0c;人脑与机器连接已成为一个引人注目的前沿领域。在这一背景下&#xff0c;神经科技的探索为我们打开了一个全新的世界&#xff0c;从脑机接口到人工智能的飞跃应用&#xff0c;不仅加速了技术的进步&#xff0c;更触动了我们内心…