Files
Penetration_Testing_POC/books/CVE-2026-41844 Spring Framework 开放重定向漏洞浅析.md

12 KiB
Raw Permalink Blame History

CVE-2026-41844 Spring Framework 开放重定向漏洞浅析

QIANXIN Team 来源:https://forum.butian.net/share/4951

0x00 CVE-2026-41844

image.png
主要影响范围:

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中定义):

image.png

经过一系列的处理后,会调用doDispatch方法处理:

image.png

在doDispatch方法中,经过一系列处理获取到url 和 Handler 映射关系后(HandlerAdapter),springMVC就可以根据请求的uri来找到对应的Controller和method,然后处理和响应请求。详细的分析可见https://forum.butian.net/share/2214

image.png

找到对应的HandlerAdapter后,会调用对应的Handler方法,也就是执行Controller里的业务逻辑了,执行完成之后会返回一个ModleAndView对象,然后渲染视图并进行返回,这里的逻辑是本次漏洞的分析的关键:

image.png

在获取到ModelAndView对象后,这里会调用applyDefaultViewName处理,这里是Spring 的默认视图解析逻辑:

image.png

查看具体的代码逻辑,首先检查 mv 是否为 null(如果代码添加了 @ResponseBody 注解,mv 就为 null),然后判断 mv 中是否包含视图,如果对应的Controller代码中未显式指定视图名时,则调用 getDefaultViewName 方法去获取默认的视图名,并将获取到的默认视图名赋值给 mv:

image.png

查看getDefaultViewName,看看具体获取默认视图名的逻辑:

image.png

这里会继续调用viewNameTranslator#getViewName方法对请求进行处理。

viewNameTranslator 其实是 RequestToViewNameTranslator

image.png

image.png

本质上,在 SpringMVC 中,RequestToViewNameTranslator 接口只有一个默认的实现类DefaultRequestToViewNameTranslatorWebFlux 则是ViewResolutionResultHandler 。

在DefaultRequestToViewNameTranslator#getViewName方法中,会从请求路径中直接提取字符串作为视图名

image.png

ServletRequestPathUtils#getCachedPathValue方法是统一获取请求路径的方法。具体的解析可见https://forum.butian.net/share/2606。

提取完请求路径后,会通过 transformPath 方法对路径进行处理,再分别加上前后缀后返回,默认的前后缀都是空字符串(如有需要,也可以进行配置)。

transformPath 方法则主要功能如下:

  1. 去掉路径开始的 /
  2. 去掉路径结尾的 /
  3. 如果请求路径有扩展名,则去掉扩展名,例如请求路径是 /1.txt,经过这一步处理后,就变成了 /1

image.png

image.png

  1. 如果 separator 与 SLASH 不同,则替换原来的分隔符(一般情况下,默认是相同的)。

image.png

这里以如下Controller为例:

@GetMapping("/**")
public void catchAll() {

}

当正常请求/demo时,可以看到,因为没有显示指定视图,所以ModelAndView对象里的内容均为null

image.png

经过applyDefaultViewName方法处理后,取得对应的视图名,也就是默认的请求路径demo:

image.png

这里也就得到了漏洞的第一个成因:当 Spring MVC 或 Spring WebFlux 应用未显式指定视图名时,视图名会默认从请求路径提取。

处理完上述的一系列逻辑后,会调用processDispatchResult()进行异常处理、请求状态及触发请求完成事件,视图的渲染工作则交给了render()方法:

image.png

image.png

render()渲染过程中,如果ModelAndView中的viewName不为空,则调用resolveViewName从视图解析器获取对应的视图对象;否则使用ModelAndView#getview方法获取视图对象。

image.png

这里会进一步调用getCandidateViews方法进行处理,然后遍历所有的视图解析器,进行视图的创建与解析:

image.png

image.png

而UrlBasedViewResolver会识别视图名中的特殊前缀,例如redirect: 会被解析为重定向,返回 302 响应跳转到后续指定的地址:

image.png

至此,CVE-2026-41844的完整链路大致梳理清楚了。下面是具体的漏洞复现过程。

1.2 漏洞复现

以SpringMVC为例:

相关环境直接使用https://github.com/andbin/spring-boot3-thymeleaf-basic-demo 进行验证。

根据前面的分析,可以定义一个Controller如下:

@Controller
public class MyController {

    @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的后缀,避免截断后无法正常跳转。

下面是具体的效果:

image.png

forward的转发同理,先定义一个转发的目标:


@GetMapping("/internal/secret")
@ResponseBody public String internalEndpoint() {
    return "[敏感信息] 内部系统配置接口,仅内网可访问";
}

只需请求http://ip:port/forward:/internal/secret即可成功转发:

image.png

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的,类似/**,只是功能更强,可以获取到这部分动态匹配到的内容。

@GetMapping("/{*path}")
public void catchAll() {
    
}

可以发现,同样成功利用,这里与/**的配置区别只是解析模式的不同,不影响具体的漏洞触发:

image.png

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 响应:

image.png