身份验证绕过漏洞(CVE-2023-20860)

目录

0x01 漏洞描述

1.1 影响版本

0x02 原理分析

2.1 MvcRequestMatcher

2.2 PathPattern

2.3 绕过分析

0x03 漏洞复现

0x04 其他

0x05 修复方式


Spring官方发布了Spring Framework 身份认证绕过漏洞(CVE-2023-20860),当Spring Security使用mvcRequestMatcher配置并将**作为匹配模式时,在Spring Security 和 Spring MVC 之间会发生模式不匹配,最终可能导致身份认证绕过。

0x01 漏洞描述

Spring官方发布了Spring Framework 身份认证绕过漏洞(CVE-2023-20860),当Spring Security使用mvcRequestMatcher配置并将**作为匹配模式时,在Spring Security 和 Spring MVC 之间会发生模式不匹配,最终可能导致身份认证绕过。

1.1 影响版本

  • Spring Framework 6.0.x <= 6.0.6
  • Spring Framework 5.3.x <= 5.3.25

(其他低于5.3.x的系列版本不受此漏洞影响)

0x02 原理分析

2.1 MvcRequestMatcher

根据漏洞描述,主要是mvcRequestMatcher的问题。参考Spring MVC Integration :: Spring Security

发现mvcRequestMatcher主要使用Spring MVC的HandlerMappingIntrospector来匹配路径并提取变量。相比AntPathRequestMatcher会更严谨。例如mvcMatchers("/index") ,除了匹配/index,对于/index/, /index.html, /index.do也会匹配。避免了AntPathRequestMatcher的绕过一些问题。

在查看mvcRequestMatcher首先简单描述下两个概念:

  • Pattern:

    httpSecurity.authorizeRequests().mvcMatchers("admin/**").authenticated();
    

    这里的/admin/**就是Pattern。

  • Path:实际请求的路径

以spring-webmvc-5.3.20版本为例,查看具体实现,主要是在org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher#matches方法进行匹配:

image.png

首先会在notMatchMethodOrServletPath方法对请求方法以及servletPath进行简单的比对:

image.png

然后调用getMapping方法对当前请求进行处理(实际调用的是HandlerMappingIntrospector的getMatchableHandlerMapping方法):

image.png

image.png

主要是寻找能处理指定请求的HandlerMapping,继续往下跟进会发现实际调用的是org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#getHandlerInternal方法,然后调用lookupHandlerMethod方法,首先直接根据路径获取对应的Mapping,获取不到的话调用addMatchingMappings遍历所有的ReuqestMappingInfo对象并进行匹配,实际上就是spring web解析的逻辑:

image.png

获取到mapping后调用对应的match方法,跟pattern进行匹配,然后将匹配的结果封装在RequestMatchResult中返回:

image.png

继续跟进具体的match方法:

image.png

实际上调用的是org.springframework.web.servlet.handler.PathPatternMatchableHandlerMapping#match方法:

image.png

继续调用的PathPattern(根据影响的版本可以确定对应的Spring使用的是PathPattern进行解析)的matches方法将pattern跟path进行匹配:

image.png

而PathPattern首先会根据/将URL拆分成多个PathElement对象,以/admin/index/为例,这里会分割成多个对象,然后根据PathPattern的链式节点中对应的PathElement的matches方法逐个进行匹配。
简单地分析了mvcRequestMatcher以后,看看PathPattern的工作原理。

2.2 PathPattern

2.6以及之后的Spring会使用PathPatternsRequestCondition通过PathPattern来进行URL匹配。

主要在org.springframework.web.util.pattern.PathPattern#matches方法:

image.png

首先会根据/将URL拆分成多个PathElement对象,以/admin/index/为例,这里会分割成多个对象,然后根据PathPattern的链式节点中对应的PathElement的matches方法逐个进行匹配:

image.png

例如Pattern为/admin/*的话,首先第一个元素是分隔符/,会调用SeparatorPathElement的matches方法进行处理:

image.png

处理完后pathIndex++,继续遍历下一个元素进行处理,下一个是admin,会通过LiteralPathElement#matches进行处理,同样的最后会对pathindex进行+1,然后继续遍历PathElement元素直到遍历结束为止:

image.png

在最后会根据matchOptionalTrailingSeparator(此参数为true时,默认为true)进行一定的处理,如果Pattern尾部没有斜杠,请求路径有尾部斜杠也能成功匹配(类似TrailingSlashMatch的作用):

image.png

image.png

所以这里/admin/index和/admin/index/都是可以访问到对应的路由的。

除此之外,根据不同Pattern的写法,还有很多PathElement:

  • WildcardPathElement(/api/*)
  • SingleCharWildcardedPathElement(/api/?)
  • WildcardTheRestPathElement(/api/**)
  • CaptureVariablePathElement(/api/{param})
  • CaptureTheRestPathElement(/api/{*param})
  • LiteralPathElement(/api/index)
  • RegexPathElement(/api/.*)

2.3 绕过分析

根据前面的分析,因为mvcRequestMatcher主要使用Spring MVC的HandlerMappingIntrospector来匹配路径并提取变量。猜测大致的问题也应该出现在这里。对比修复前后版本的HandlerMappingIntrospector代码:

这里的返回值从PathSettingHandlerMapping变成了LookupPathMatchableHandlerMapping:

image.png

image.png

结合前面的分析可知,修改的其实是在调用PathPattern的match方法前的处理。对比下代码可以发现,在调用PathPattern的match方法之前多了一个步骤,首先判断pattern是否以/开头,如果不是的话进行补全

  • spring-webmvc-5.3.26

image.png

  • spring-webmvc-6.0.7

image.png

根据前面的分析,做以下猜想,在Spring Controller中,以下两个路由访问是等价的:

@GetMapping("/admin/*")
@GetMapping("admin/*")

当Spring Security使用mvcRequestMatcher模式进行权限控制时,如果对应的配置没有以/开头,根据前面的分析,猜测会因为解析差异导致绕过的问题。

例如如下配置,admin目录下的路由会经过认证处理,非认证通过的会返回403:

@Override
protected void configure(HttpSecurity httpSecurity) throws Exception{
       httpSecurity.authorizeRequests().mvcMatchers("admin/**").authenticated();
}

Controller:

@GetMapping("/admin/index")
public String Manage(){
    return "manage";
}

根据前面对PathPattern的matches的分析,这里会根据PathPattern的链式节点中对应的PathElement的matches方法逐个进行匹配,当pattern为admin/**时,此时第一个Element是admin,对应LiteralPathElement#matches解析:

image.png

此时会获取path的第一个Element(如果访问的path是/admin/index,那么第一个Element是/):

image.png

/明显不是PathSegment的实例,此时匹配失败会返回false,但是Spring Controller却能正常解析,那么便导致了绕过问题。

0x03 漏洞复现

根据前面的猜想,同样的是前面的case,当对应的配置没有以/开头,会因为解析差异导致绕过的问题,可以看到成功绕过了设置的Spring security规则,访问了/admin/index:

image.png

这里再做一个对比,将spring-webmvc切换到5.3.9版本,此时上述的case是无法绕过的:

image.png

0x04 其他

在Spring生态中,除了PathPattern以外,还有一种解析模式是AntPathMatcher。

同样的根据之前的分析,其实主要是PathPattern的解析方式问题,这里再做一个假设,同样是存在缺陷的版本spring-webmvc-5.3.20版本,此时通过properties配置切换匹配模式为AntPathMatcher:

spring.mvc.pathmatch.matching-strategy = ant_path_matcher

此时发现没办法绕过了:

image.png

简单说下原因,主要是AntPathMatcher的实现,其大概方式是将需要匹配的path和Pattern分割成string数组,分别是pathDirs和pattDirs两个数组,然后从左到右开始匹配,主要是一些正则的转换还有通配符的匹配。例如/admin/*的*实际上是正则表达式.*,然后通过java.util.regex.compile#matcher进行匹配,这里进行分割时不会将/作为内容引入分析,从调试信息也可以看到,在此之前也将/进行了补全:

图片.png

/进行了补全的操作主要是在RequestMappingHandlerMapping#match方法中进行的:

图片.png

这里实际上调用的是RequestMappingInfo#build方法:

图片.png

这里对Pattern进行了重新处理,在调用PatternsRequestCondition的构造方法的时候,调用了initPatterns方法:

图片.png

如果Pattern不是以/开头会进行补全:

图片.png

0x05 修复方式

目前官方已有可更新版本,建议升级至:

  • Spring Framework 6.0.x >= 6.0.7
  • Spring Framework 5.3.x >= 5.3.26

同样是上面的case,将spring-webmvc版本升级到5.3.26后,上述case已无法绕过:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.3.26</version>
</dependency>

image.png

关注我学更多的黑客知识 

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值