问答
发起
提问
文章
攻防
活动
Toggle navigation
首页
(current)
问答
商城
实战攻防技术
漏洞分析与复现
NEW
活动
摸鱼办
搜索
登录
注册
CVE-2024-38821-Spring Security 静态资源权限绕过漏洞分析复现
漏洞分析
Spring官方发布了CVE-2024-38821,当WebFlux使用Spring的静态资源支持时,在特定情况下会存在权限绕过的风险。
0x00 漏洞简介 ========= ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/10/attach-04bdc586b090b8d14f43481a75ac219ed0f022b6.png) 0x01 影响版本 ========= Spring Security 版本: - 5.7.0 - 5.7.12 - 5.8.0 - 5.8.14 - 6.0.0 - 6.0.12 - 6.1.0 - 6.1.10 - 6.2.0 - 6.2.6 - 6.3.0 - 6.3.3 - Older, unsupported versions are also affected 0x02 漏洞原理分析 =========== `@EnableWebFluxSecurity` 是 Spring Security 提供的一个注解,用于在 Spring WebFlux 应用程序中启用 Spring Security 功能。这个注解会激活 Spring Security 的 WebFlux 支持,允许你定义安全配置,比如认证、授权、CSRF 保护等。 而pathMatchers() 方法用于指定哪些路径需要被特定的安全配置所应用,可以通过该方法来设置哪些路径应该被认证、哪些路径可以公开访问等。例如下面的例子: ```Java @Bean public SecurityWebFilterChain securityWebFilterChain(final ServerHttpSecurity http) { return http .csrf().disable() .authorizeExchange().matchers(PathRequest.toStaticResources().atCommonLocations()).permitAll() .pathMatchers(HttpMethod.GET, "/portal/*.log").hasAuthority("ADMIN") .anyExchange().permitAll() .and() .formLogin() .loginPage("/login") .and() .logout() .logoutUrl("/logout") .requiresLogout(ServerWebExchangeMatchers.pathMatchers(HttpMethod.GET, "/logout")) .and() .build(); } ``` WebFlux.fn 是 Spring WebFlux 中提供的一种轻量级的函数式编程模型,它允许开发者使用函数来处理 HTTP 请求和响应。这个模型特别适合与响应式编程范式一起使用,提供了一种声明性和非阻塞的方式来处理 Web 请求。 &emsp 在 WebFlux.fn 中,HTTP 请求由 HandlerFunction 处理,这是一个接受 ServerRequest 并返回延迟的 ServerResponse(即 Mono\\)的函数。 漏洞的成因主要是WebFlux.fn静态资源解析在特定情况下与pathMatchers的匹配存在解析差异,从而导致了权限绕过的风险。下面是具体的分析: 2.1 pathMatchers解析过程 -------------------- 在SpringSecurity中,对于Spring WebFlux,会使用`pathMatchers`来实现基于请求路径进行权限配置的功能。 pathMatchers的匹配主要跟PathPatternParserServerWebExchangeMatcher有关: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/10/attach-5e72e0cccdb1a95f2111d2caf8a96d4d4bbed11e.png) 首先根据用户配置创建基于路径匹配的 `ServerWebExchangeMatcher` 对象。创建一个空的 `matchers` 列表,用于存储创建的 `PathPatternParserServerWebExchangeMatcher` 对象。匹配请求路径的功能是由 PathPatterParserServerWebExchangeMatcher 来实现的。其会拦截请求路径,并且提取请求路径的参数。遍历传入的 `patterns` 数组,并对于每个路径模式,创建一个 `PathPatternParserServerWebExchangeMatcher` 对象,并传入该模式和请求方法,然后添加到`matchers` 列表中: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/10/attach-e8c4b333ffe16a468d9064ef07d9b02c4947102b.png) 查看`PathPatternParserServerWebExchangeMatcher`的实例化过程,其中传入的pattern属性会调用parse方法进行处理,在parse方法中调用了initFullPathPattern进行处理,对不是以`/`开头的情况进行补全(修复CVE-2023-34034): ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/10/attach-c80a76fa045ef67ae8d4bfd130878f0152797dd1.png) ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/10/attach-e83b4115ec2b123e70591983cdf19a5038b95072.png) 然后调用`org.springframework.web.util.pattern.InternalPathPatternParser#parser`进行处理: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/10/attach-a1d30b72516cab50987dc4280d035fc06991874a.png) 在parse方法中,首先遍历路径模式字符串的每个字符,在遍历过程中,首先检查是否遇到路径分隔符(`separator`),如果是,则创建对应的 `SeparatorPathElement` 或 `WildcardTheRestPathElement` 并添加到解析结果中: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/10/attach-542bc5f934e2710c839c8a269daf621a4f56ddd4.png) 再者是对一些特殊字符的处理,主要包括`?{}:*`,以`:` 字符为例,其表示变量捕获的正则表达式结束,会进行相应的状态更新: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/10/attach-821816089c9cc2d7b9ff14afc796cea1d8c5cbf2.png) 如果处于变量捕获状态,则根据规则检查字符的合法性,并抛出对应的异常: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/10/attach-d9ecbd7ad318ce2c823fa81fd029bab4da10abe1.png) 遍历完成后,将最后一个路径元素添加到解析结果中。并使用解析得到的路径模式字符串、解析器和解析结果创建并返回 `PathPattern` 对象,用于后续的路径匹配和处理: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/10/attach-3e07c04bcdcb57e0040de41497b05a574da361c3.png) 当请求对应的path时,Spring Security会遍历前面封装好的安全配置,进行匹配: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/10/attach-d024b122f1859b53edeefc6d7c6ee57a63b52136.png) 而PathPatternParserServerWebExchangeMatcher的matches方法主要用来用来判断请求是否匹配。**实际上使用的PathPattern模式进行解析**。具体解析模式的分析可以参考:<https://forum.butian.net/share/2214> 一开始exchange使用 `getRequest()` 方法获取 `ServerHttpRequest` 对象,然后再通过`getPath()` 方法获取请求路径,然后获取当前请求的方法,判断请求方法与当前规则是否一致: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/10/attach-abf0c923c46ae1179931c67d107a111a67736931.png) 如果请求方法匹配或者没有指定请求方法,会调用 `PathPattern` 对象的 `matches` 方法,将当前请求的路径和请求方法传递给路径模式对象,进行路径匹配判断,如果匹配失败,则返回一个不匹配的结果,并在日志中记录对应的信息: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/10/attach-acbed99a3317000fc1856c9bf3f281e2c1e75213.png) 如果路径匹配成功,则使用当前的路径模式 (`pattern`) 提取路径变量,并将路径变量保存在 `pathVariables` 中: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/10/attach-13b9d7a849ba5090f806e9ee46d967bc1fdc11fd.png) 最终返回匹配的结果供后续权限校验使用。 2.2 WebFlux.fn静态资源解析过程 ---------------------- PathResourceLookupFunction在响应式路由中处理静态资源请求。将请求的路径映射到文件系统中的资源,如图片、样式表或 JavaScript 文件等。以spring-webflux-5.3.29为例,查看具体的解析过程。 在解析时主要调用的是org.springframework.web.reactive.function.server.PathResourceLookupFunction#apply方法进行处理: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/10/attach-994a0fb56652120b7eb6be96650e343f58f5e0e0.png) 若原始请求路径中包含`%`时,会进行一次URL解码: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/10/attach-9aba4aa0992d07115aa97edac4185696c65754be.png) 然后会调用isInvalidPath进行一些安全检查: - 检查路径字符串 `path` 是否包含 `WEB-INF` 或 `META-INF` - 使用 ResourceUtils.isUrl(relativePath) 检查相对路径是否是一个有效的 URL(类似classpath:的调用)。如果是,或者路径以 url: 开头,表明这是一个指向外部资源的路径。也是不合理的 - 检查路径中是否包含 `..`,这可能是尝试进行路径遍历的尝试。通过 `StringUtils.cleanPath(path)` 处理路径后会再次检查是否包含 `../` ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/10/attach-28e0ef37a280901f96df1842ce75282e9415953d.png) `StringUtils.cleanPath`中,会对路径中的`../`进行处理,例如`/admin/../test.log`在处理后`../`会跟之前的目录进行抵消: ```Java String path = "/admin/../test.log"; System.out.println(StringUtils.cleanPath(path)); ``` ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/10/attach-834e3f0c3e957a07859bd6ef604b71ffbf629683.png) 然后会通过this.location.createRelative(path) 创建一个 Resource 对象,这个对象代表了请求的资源。然后检查创建的资源是否可读,并且是否位于定义的资源位置下: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/10/attach-61cfb432fe83f5eaacaad718cdff2cf58a6c3def.png) createRelative主要是实例化了org.springframework.core.io.FileUrlResource: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/10/attach-f0dd5d58eddd6f58d96164fee18be71f310ced0b.png) 实际是封装成了java.net.URL对象: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/10/attach-7a0fa50c039a92e742761faf8281f7038aa745fe.png) 在解析时会通过org.springframework.core.io.UrlResource#getInputStream方法来获取对应的资源,这里会再对请求路径解码一层: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/10/attach-81879ffdd461e7be7b2e9c0a7ee69de3749cc3fa.png) 熟悉PathPattern的话,其在解析`../`会当成一个目录进行处理,不会进行额外的目录回溯,通过仅支持一层URL的解码操作,也就是说,相比pathMatchers的解析,WebFlux.fn在进行静态资源解析时还额外支持如下解析: - 支持`../`的目录回溯 - 通过File协议请求资源时支持URL双重解码 正是这些差异导致了相关的Bypass。下面是具体的复现过程: 0x03 环境搭建 ========= SpringSecurity配置如下,对于portal路径下的所有log后缀结尾的内容,均需要ADMIN权限才可以访问: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/10/attach-9ea93bf2deca41e53f311dc2bebc8ac0b9a64c1a.png) WebFlux.fn注册的静态路由映射如下,将/tmp目录的内容通过/portal路由进行访问: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/10/attach-fd1a9880e9fea02742af200185c18ee33c0e4b89.png) 当尝试访问portal下的test.log内容时,因为缺少ADMIN权限返回302 status: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/10/attach-c145f918fede878c8769ace55a30370b0908f484.png) 0x04 漏洞复现 ========= 基于前面的分析,下面列举一些可能的绕过方式(由于**CVE-2024-38816&CVE-2024-38819**的修复,部分绕过方式可能受版本限制): **绕过方式一**: 正如前面的分析,类似`/admin/../test.log`的请求会进行目录回溯,同时不影响相关的安全检查,但是在SpringSecurity解析时会认为`../`是额外的目录节奏,从而绕过了`/portal/*.log`的鉴权配置: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/10/attach-3354226673725ecfb6343b68c4551050bae1051c.png) 在修复**CVE-2024-3881**9时,在调用processPath时增加了normalizePath的处理: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/10/attach-2fece09cc7a4946b0a942ba6b58119e74f2a0551.png) normalizePath中对`../`进行了处理: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/10/attach-f4e41157e8414085c421a1c37f4c601946aed2c1.png) 包括isInvalidPath也进行了修改,最后只判断path中是否包含`../`,避免了类似方式一种`/admin/../test.log`经过之前`cleanPath`方法转换后变成`test.log`导致误认为path合法的情况: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/10/attach-9bf166da63dd5b4f603e345b68dcc8e6e0bd186d.png) 并且在最后isResourceUnderLocation方法处理时考虑了双重url编码以及`../`的问题,所以高版本默认情况下是无法通过方式一进行绕过的: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/10/attach-af59534cf4fe8c58a20aadf8b8fb2f5f5086f203.png) 0x05 其他 ======= 因为具体的匹配方式是`/portal/*.log`,即使高版本对方式一进行了处理,仍可以利用File协议解码的特点,通过双重URL编码的方式,绕过对应的权限检查: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/10/attach-d9f4b9296d3f9bf5820d7ffd3d71bb1b29ceb532.png) 5.1 为什么Spring WebMvc.fn不受影响 --------------------------- `WebMvc.fn` 是 Spring Web MVC 的一部分,它提供了一种轻量级的函数式编程模型,允许开发者使用函数来定义路由和处理 HTTP 请求。这种模型是注解编程模型的替代方案。 在 `WebMvc.fn` 中,HTTP 请求由 `HandlerFunction` 处理,这是一个接收 `ServerRequest` 并返回 `ServerResponse` 的函数。一般可以通过RouterFunctions.route()方法进行处理。同样的也支持File协议的静态资源映射,在解析过程中也进行了相应的URL解码处理: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/10/attach-96cb9eb40372ca32979fc7675db9d65f89541e91.png) 但是实际上当使用SpringSecurity进行防护时,利用双重URL编码的方式并不能很好的绕过对应的安全防护。原因是因为org.springframework.security.web.firewall.StrictHttpFirewall默认场景下对请求中的非法字符进行了拦截处理: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/10/attach-b1d2528cbee40c19ccad1b45a2ca7abdef66d59a.png) 但是因为整体逻辑是基于serlvet/filter实现的,WebFlux并不适用,所以没办法进行覆盖。 5.2 修复方式 -------- Spring官方的修复方式也很简单,主要是基于WebFlux的场景,在SpringSecurity中新增了org.springframework.security.web.server.firewall.StrictServerWebExchangeFirewall,对请求过程中的一些恶意字符进行了处理: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/10/attach-05d5ae160e5b87baa5bccbf421c8aa4d45971a90.png) 也包括在前面复现场景中看到的的`../`以及对应的URL编码等: ![image.png](https://shs3.b.qianxin.com/attack_forum/2024/10/attach-dfcf51d3a1e7ffccc5844b4b44d7736d74cf726d.png)
发表于 2024-10-29 10:07:18
阅读 ( 830 )
分类:
开发框架
1 推荐
收藏
1 条评论
wan9x
1秒前
复现漏洞的源码可以分享一下吗,谢谢师傅
请先
登录
后评论
请先
登录
后评论
tkswifty
2 篇文章
×
发送私信
请先
登录
后发送私信
×
举报此文章
垃圾广告信息:
广告、推广、测试等内容
违规内容:
色情、暴力、血腥、敏感信息等内容
不友善内容:
人身攻击、挑衅辱骂、恶意行为
其他原因:
请补充说明
举报原因:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!