漏洞分析 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/895028.shtml

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

相关文章

笔记:理解借贷相等的公式

强烈推荐非会计人士&#xff0c;快速了解会计看这个系列的视频&#xff0c;其中比较烧脑的“借贷相等”公式&#xff0c;这个视频讲解的不错&#xff1a; 4.小白财务入门-借贷记账法_哔哩哔哩_bilibili 比如这里&#xff0c;钱在银行卡重&#xff0c;所以银行存款就是借方…

Java算法技术文章:深入解析排序、搜索与数据结构

引言 在软件开发的世界里&#xff0c;算法不仅是程序设计的基础&#xff0c;更是提升软件性能、优化用户体验的关键。Java&#xff0c;作为一种广泛使用的编程语言&#xff0c;提供了丰富的API和标准库来支持各种算法的实现。本文将深入探讨Java中的排序算法、搜索算法以及一些…

Android15音频进阶之MediaRecorder支持通道(一百零五)

简介: CSDN博客专家、《Android系统多媒体进阶实战》一书作者 新书发布:《Android系统多媒体进阶实战》🚀 优质专栏: Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏: 多媒体系统工程师系列【原创干货持续更新中……】🚀 优质视频课程:AAOS车载系统+…

个人 Vite 构建性能分析插件开发实践

Vite 构建分析插件开发实践 一、开发背景 在个人项目开发中遇到以下问题&#xff1a; &#x1f552; 构建时间波动大&#xff08;30%&#xff09;&#x1f50d; 难以定位耗时模块&#x1f4c8; 缺乏构建进度反馈 开发目标&#xff1a; 实现模块级耗时分析提供实时进度预测识…

【Spring】什么是Spring?

什么是Spring&#xff1f; Spring是一个开源的轻量级框架&#xff0c;是为了简化企业级开发而设计的。我们通常讲的Spring一般指的是Spring Framework。Spring的核心是控制反转(IoC-Inversion of Control)和面向切面编程(AOP-Aspect-Oriented Programming)。这些功能使得开发者…

学习笔记:机器学习中的数学原理(一)

1. 集合 集合分为有限集和无限集&#xff1b; 对于有限集&#xff0c;两集合元素数相等即为等势&#xff1b; 对于无限集&#xff0c;两集合元素存在一一映射关系即为等势&#xff1b; 无限集根据是否与正整数集等势分为可数集和不可数集。 2. sigmoid函数&#xff08;也叫…

【信息系统项目管理师-案例真题】2016下半年案例分析答案和详解

更多内容请见: 备考信息系统项目管理师-专栏介绍和目录 文章目录 试题一【问题1】4 分【问题2】12 分【问题3】3 分【问题4】6 分试题二【问题1】3 分【问题2】4 分【问题3】8 分【问题4】5 分【问题5】5 分试题三【问题1】4 分【问题2】8 分【问题3】5 分【问题4】8 分试题一…

基于javaweb的SpringBoothis智能医院管理系统(源码+文档+部署讲解)

&#x1f3ac; 秋野酱&#xff1a;《个人主页》 &#x1f525; 个人专栏:《Java专栏》《Python专栏》 ⛺️心若有所向往,何惧道阻且长 文章目录 运行环境开发工具适用功能说明一、项目运行 环境配置&#xff1a; 运行环境 Java≥8、MySQL≥5.7、Node.js≥14 开发工具 后端&…

JS实现灯光闪烁效果

在 JS中&#xff0c;我们可以实现灯光闪烁效果&#xff0c;这里主要用 setInterval 和 clearInterval 两个重要方法。 效果图 源代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>灯闪烁效果<…

Linux ltrace跟踪入门

文章目录 背景ltrace原理ltrace使用跟踪程序调用库函数跟踪指定pid进程调用 参考 本文介绍ltrace跟踪 背景 ltrace 会拦截并记录正在执行的进程所调用的动态库调用以及该进程接收到的信号&#xff0c;它还可以拦截并打印程序执行的系统调用。 其代码位置在&#xff1a;https:/…

PCA9685 16路PWM 控制板 STM32F103 驱动

PCA9685 拥有16路PWM&#xff0c;通过 IIC 与 STM32 进行通信&#xff0c;以下驱动代码已通过测试&#xff0c;你可以进行更多代码优化 #include "pca9685.h"// 向 PCA9685 写入一个字节数据 static void PCA9685_write8( uint8_t addr, uint8_t d) {while (I2C_Get…

使用 Apache Spark 进行大数据分析

使用 Apache Spark 进行大数据分析 环境准备 为了能够在本地环境中运行Spark程序&#xff0c;需要先完成环境搭建。确保已经安装了Jupyter Notebook和Apache Spark&#xff0c;并完成了两者之间的集成。 创建 SparkSession 在 Python 中使用 PySpark 时&#xff0c;通常会创…

2025 专业的物联网软件开发公司有哪些

物联网&#xff08;Internet of Things&#xff0c;简称IoT&#xff09;具有多个显著的优势&#xff0c;主要包括提高效率、节省成本、数据收集与分析、自动化控制、改善用户体验、增强决策能力和创新业务模式‌。2025&#xff0c;有哪些比较专业的物联网开发公司呢&#xff1f…

7.PPT:“中国梦”学习实践活动【20】

目录 NO1234​ NO5678​ NO9\10\11 NO1234 考生文件夹下创建一个名为“PPT.pptx”的新演示文稿Word素材文档的文字&#xff1a;复制/挪动→“PPT.pptx”的新演示文稿&#xff08;蓝色、黑色、红色&#xff09; 视图→幻灯片母版→重命名&#xff1a;“中国梦母版1”→背景样…

学习笔记十九:K8S生成pod过程

K8S生成pod过程 流程图具体生成过程用户提交 Pod 定义API Server 处理请求调度器分配节点&#xff08;Scheduling&#xff09;目标节点上的 Pod 创建网络配置状态上报与监控控制器管理&#xff08;Controller Manager&#xff09;就绪与服务发现 关键错误场景高级特性 流程图 具…

封装descriptions组件,描述,灵活

效果 1、组件1&#xff0c;dade-descriptions.vue <template><table><tbody><slot></slot></tbody> </table> </template><script> </script><style scoped>table {width: 100%;border-collapse: coll…

21.2.6 字体和边框

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 通过设置Rang.Font对象的几个成员就可以修改字体&#xff0c;设置Range.Borders就可以修改边框样式。 【例 21.6】【项目&#xff…

FPGA VGA timing

概念 VGA(Video Graphics Array)时序是控制VGA接口显示图像的关键参数,它主要包括行时序和场时序两部分。以下是对VGA时序的详细解释: 一、VGA接口简介 VGA接口是IBM公司在1987年推出的一种使用模拟信号的视频传输标准,具有成本低、结构简单、应用灵活等优点,至今仍被广…

中级通信工程师综合教材(5、6章节)

五、现代通信网 1、通信网的构成要素 通信网在硬件设备方面的构成要素是交换设备、传输链路和终设备。 构成要素 功能作用 常见设备举例 终端设备 通信的源点和目的地 电话机、传真机、计算机、视频终端、多媒体终端等 交换设备 通信网的核心设备,主要完成呼叫处理、信令处理…

360手机刷机 360手机解Bootloader 360手机ROOT

360手机刷机 360手机解Bootloader 360手机ROOT 问&#xff1a;360手机已停产&#xff0c;现在和以后&#xff0c;能刷机吗&#xff1f; 答&#xff1a;360手机&#xff0c;是肯定能刷机的 360手机资源下载网站 360手机-360手机刷机RootTwrp 360os.top 360rom.github.io 一、…