CVE-2026-41844 Spring Framework 开放重定向漏洞浅析
渗透测试
CVE-2026-41844受影响版本中,当 Spring MVC 或 Spring WebFlux 应用配置了全局匹配路径映射且未显式指定视图名时,视图名会默认从请求路径提取。由于在解析时未校验视图名是否包含 "redirect:" 等恶意前缀,攻击者可构造类似 /redirect:https://evil.com 的请求,导致应用返回 302 重定向至外部恶意站点。
0x00 CVE-2026-41844 ===================  **主要影响范围:** Spring Framework: - 7.0.0 - 7.0.7 - 6.2.0 - 6.2.18 - 6.1.0 - 6.1.27 - 5.3.0 - 5.3.48 以及不再支持维护的版本同样受到影响。 0x01 漏洞分析与复现 ============ 1.1 分析过程 -------- 以spring-webmvc 6.0.7为例。 当Spring MVC接收到请求时,Servlet容器会调用DispatcherServlet的service方法(方法的实现在其父类FrameworkServlet中定义):  经过一系列的处理后,会调用doDispatch方法处理:  在doDispatch方法中,经过一系列处理获取到url 和 Handler 映射关系后(HandlerAdapter),springMVC就可以根据请求的uri来找到对应的Controller和method,然后处理和响应请求。详细的分析可见https://forum.butian.net/share/2214  找到对应的HandlerAdapter后,会调用对应的Handler方法,也就是执行Controller里的业务逻辑了,执行完成之后会返回一个ModleAndView对象,然后渲染视图并进行返回,这里的逻辑是本次漏洞的分析的关键:  在获取到ModelAndView对象后,这里会调用applyDefaultViewName处理,这里是Spring 的默认视图解析逻辑:  查看具体的代码逻辑,首先检查 mv 是否为 null(如果代码添加了 `@ResponseBody` 注解,mv 就为 null),然后判断 mv 中是否包含视图,如果对应的Controller代码中未显式指定视图名时,则调用 getDefaultViewName 方法去获取默认的视图名,并将获取到的默认视图名赋值给 mv:  查看getDefaultViewName,看看具体获取默认视图名的逻辑:  这里会继续调用viewNameTranslator#getViewName方法对请求进行处理。 viewNameTranslator 其实是 RequestToViewNameTranslator:   本质上,在 SpringMVC 中,RequestToViewNameTranslator 接口只有一个默认的实现类DefaultRequestToViewNameTranslator,WebFlux 则是ViewResolutionResultHandler 。 在DefaultRequestToViewNameTranslator#getViewName方法中,**会从请求路径中直接提取字符串作为视图名**:  ServletRequestPathUtils#getCachedPathValue方法是统一获取请求路径的方法。具体的解析可见https://forum.butian.net/share/2606。 提取完请求路径后,会通过 transformPath 方法对路径进行处理,再分别加上前后缀后返回,默认的前后缀都是空字符串(如有需要,也可以进行配置)。 transformPath 方法则主要功能如下: 1. 去掉路径开始的 `/` 2. 去掉路径结尾的 `/` 3. 如果请求路径有扩展名,则去掉扩展名,例如请求路径是 `/1.txt`,经过这一步处理后,就变成了 `/1`   4. 如果 separator 与 SLASH 不同,则替换原来的分隔符(一般情况下,默认是相同的)。  这里以如下Controller为例: ```java @GetMapping("/**") public void catchAll() { // 无业务逻辑、无返回值,完全依赖默认视图名推导机制 } ``` 当正常请求/demo时,可以看到,因为没有显示指定视图,所以ModelAndView对象里的内容均为null:  经过applyDefaultViewName方法处理后,取得对应的视图名,也就是默认的请求路径demo:  这里也就得到了漏洞的第一个成因:**当 Spring MVC 或 Spring WebFlux 应用未显式指定视图名时,视图名会默认从请求路径提取。** 处理完上述的一系列逻辑后,会调用processDispatchResult()进行异常处理、请求状态及触发请求完成事件,视图的渲染工作则交给了render()方法:   render()渲染过程中,如果ModelAndView中的viewName不为空,则调用resolveViewName从视图解析器获取对应的视图对象;否则使用ModelAndView#getview方法获取视图对象。  这里会进一步调用getCandidateViews方法进行处理,然后遍历所有的视图解析器,进行视图的创建与解析:   而UrlBasedViewResolver会识别视图名中的特殊前缀,例如`redirect:` 会被解析为重定向,返回 302 响应跳转到后续指定的地址:  至此,CVE-2026-41844的完整链路大致梳理清楚了。下面是具体的漏洞复现过程。 1.2 漏洞复现 -------- 以SpringMVC为例: 相关环境直接使用https://github.com/andbin/spring-boot3-thymeleaf-basic-demo 进行验证。 根据前面的分析,可以定义一个Controller如下: ```TypeScript @Controller public class MyController { /** * 漏洞触发点:通配符路径映射 + 方法返回void(不显式指定视图名) * Spring会自动从请求路径提取字符串作为视图名 */ @GetMapping("/**") public void catchAll() { // 无业务逻辑、无返回值,完全依赖默认视图名推导机制 } } ``` 启动对应的application后,只需访问`http://ip:port/redirect:https://www.attack.com.any`,通过302跳转后即可重定向到`https://www.attack.com` 注意,根据前面的分析,在通过请求获取默认视图时,如果请求路径有扩展名,则去掉扩展名,这个拓展名会通过结尾最后一个`.`来区分。也就是说类似`www.attack.com`会被处理成`www.attack`,所以在最后构造poc时,要在实际跳转的域名后,增加类似`.any`的后缀,避免截断后无法正常跳转。 下面是具体的效果:  forward的转发同理,先定义一个转发的目标: ```TypeScript /** * 用于演示内部转发的“内部敏感接口” * 正常情况下外部无法直接访问受限路径,通过forward可绕过路径限制 */ @GetMapping("/internal/secret") @ResponseBody public String internalEndpoint() { return "[敏感信息] 内部系统配置接口,仅内网可访问"; } ``` 只需请求`http://ip:port/forward:/internal/secret`即可成功转发:  Spring WebFlux同理,这里就不再赘述了。 另外,WebFlux 原生不支持 `forward:` 内部转发,因此仅受 `redirect:` 开放重定向影响。 1.3 {\*spring}模式 ---------------- 在官方的漏洞通告中,仅仅提到了`/**`的场景,实际上Spring5及之后的PathPattern解析模式,还支持类似`{*spring}`的写法,与`/**`大同小异,那么是否也会存在风险呢? 查看官方文档: Representation of a parsed path pattern. Includes a chain of path elements for fast matching and accumulates computed state for quick comparison of patterns. `PathPattern` matches URL paths using the following rules: - `?` matches one character - `*` matches zero or more characters within a path segment - `**` matches zero or more *path segments* until the end of the path - `{spring}` matches a *path segment* and captures it as a variable named "spring" - `{spring:[a-z]+}` matches the regexp `[a-z]+` as a path variable named "spring" - `{*spring}` matches zero or more *path segments* until the end of the path and captures it as a variable named "spring" **Note:** In contrast to `[AntPathMatcher](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/util/AntPathMatcher.html)`, `**` is supported only at the end of a pattern. For example, `/pages/{}` is valid but `/pages/{}/details` is not. The same applies also to the capturing variant `{*spring}`. The aim is to eliminate ambiguity when comparing patterns for specificity. 根据官方文档的描述,其实`**`跟AntPathMatcher匹配规则区别不大,PathPattern在保持其匹配规则的基础上,新增了`{*spring}`的语法支持。 `{*spring}`表示匹配余下的path路径部分并将其赋值给名为spring的变量(变量名可以根据实际情况随意命名,与`@PathVariable`名称对应即可)。同时,`{*spring}`是可以匹配剩余所有path的,类似`/**`,只是功能更强,可以获取到这部分动态匹配到的内容。 ```TypeScript @GetMapping("/{*path}") public void catchAll() { // 无业务逻辑、无返回值,完全依赖默认视图名推导机制 } ``` 可以发现,同样成功利用,这里与`/**`的配置区别只是解析模式的不同,不影响具体的漏洞触发:  0x02 利用条件 ========= 综上所述,相关漏洞的利用条件可以总结如下: 1. 使用 Spring MVC 或 Spring WebFlux 框架 2. 配置了类似 `/**` 通配符路径与`{*path}`映射(如全局视图路由) 3. 对应路径的处理器未显式指定视图名称,依赖 Spring 自动从请求路径推导 4. 使用了继承自 `UrlBasedViewResolver` 的视图解析器(Thymeleaf等主流视图技术默认均满足) 0x03 修复方案 ========= 官方具体修复如下:<https://github.com/spring-projects/spring-framework/blob/v6.2.19/spring-webmvc/src/main/java/org/springframework/web/servlet/view/DefaultRequestToViewNameTranslator.java> 通过请求获取完视图名后,新增对 `redirect:`、`forward:` 两个危险前缀的开头匹配校验。当匹配到危险前缀时直接抛出非法参数异常,由 Spring MVC 异常处理器转为 `400 Bad Request` 响应: 
发表于 2026-07-30 09:42:15
阅读 ( 3761 )
分类:
漏洞分析
0 推荐
收藏
0 条评论
tkswifty
68 篇文章
×
温馨提示
您当前没有「奇安信攻防社区」的账号,注册后可获取更多的使用权限。
×
温馨提示
您当前没有「奇安信攻防社区」的账号,注册后可获取更多的使用权限。
×
举报此文章
垃圾广告信息:
广告、推广、测试等内容
违规内容:
色情、暴力、血腥、敏感信息等内容
不友善内容:
人身攻击、挑衅辱骂、恶意行为
其他原因:
请补充说明
举报原因:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!