SpringSecurity(CVE-2022-22978)权限校验分析
date
Jun 8, 2022
slug
SpringSecurity-CVE-2022-22978
status
Published
tags
Java安全
安全研究
summary
关于SpringSecurity权限校验的一个洞,可以拿来当一个trick之类的吧,之前没整过SpringSecurity,自己搭建一次熟悉一下,影响了5.5.7 之前的 5.5.x5.6.4 之前的 5.6.x早期不支持的版本
type
Post
关于SpringSecurity权限校验的一个洞,可以拿来当一个trick之类的吧,之前没整过SpringSecurity,自己搭建一次熟悉一下,影响了5.5.7 之前的 5.5.x 5.6.4 之前的 5.6.x早期不支持的版本
在漏洞公告上说是RegexRequestMatcher这个东西出了问题
然后看github上的diff,发现只修了一个文件,然后添加了两个测试案例,根据上一次Spring Cloud Function RCE 的调试经验来看,这个test案例里面内容就是绕过检测的测试样例了,使用了%0a或者%0d进行绕过
搭建环境 && 复现
新建一个Springboot项目,然后在pom文件中引入SpringSecurity
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
将SpringSecurity版本切换至5.6.3版本
创建controller
使用SpringSecurity设置相关权限,这个跟Shiro的Relam有点像,但是这里我们需要继承
WebSecurityConfigurerAdapter
并实现其中的configure
方法这里使用了正则去匹配admin路由下的内容,涉及到的函数:
http.authorizeRequests()
:主要是对url进行访问权限控制,通过这个方法来实现url授权操作。authenticated()
:是访问控制方法的一种,表示所匹配的URL都需要被认证才能访问
此时授权与未授权的接口访问是不一样的
根据单元测试里面的payload,在路由最后添加上%0a或者%0d就能够绕过了
修复分析
观察修复内容,在
RegexRequestMatcher.java
文件的修复是增加了对换行符的匹配以及忽略大小写Pattern.DOTALL
:表示更改.
的含义,使它与每一个字符匹配(包括换行符\n),默认情况下, 正则表达式中点(.
)不会匹配换行符, 设置了Pattern.DOTALL
模式, 才会匹配所有字符包括换行符。Pattern.CASE_INSENSITIVE
:忽略大小写。
写个测试样例看一下,可以观察到非
Pattern.DOTALL
模式下是直接给忽略掉了中间匹配的内容,最后导致并没有匹配输出,这也是导致bypass的本质原因,而Pattern.DOTALL
就能正常匹配内容了,所以修复方案使用了这种方式,保证\n\r
匹配上StrictHttpFirewall
在看到这位老哥的分析文章的时候看到
StrictHttpFirewall
这个名词,又学到一个新鲜玩意了这东西好像是SpringSecurity自带的东西,参考:Spring Security 自带防火墙!你都不知道自己的系统有多安全! - 简书 (jianshu.com)
在 SpringSecurity 中提供了一个
HttpFirewall
接口,是一个请求防火墙,它可以自动处理掉一些非法请求,该接口具体实现了两个类,一个是严格模式的防火墙设置(StrictHttpFirewall),还有一个默认防火墙设置(DefaultHttpFirewall),Spring Security 中默认使用的是 StrictHttpFirewall。这个类里面设置一堆的限制内容,具体地可以查看源码:
如果需要修改这些限制,只需要自己提供一个 StrictHttpFirewall 实例,大都是这样的格式,具体地也在那篇文章里描述了
StrictHttpFirewall firewall = new StrictHttpFirewall();
firewall.setxxxxxxxxxxx(true);
总的来说,这个东西限制住了很多东西,比如平常在Tomcat场景下的一些绕过方法比如
/../
,./
,;/
不允许出现,就算这些东西编码了,也还是会被杀掉,感觉这东西还是比较牛逼的,但是%0a,%0d
好像并没有出现在这段代码里面,可能这就是这个东西在这个CVE场景下没有其作用的原因吧再仔细瞅瞅SpringSecurity是怎么处理路由的
调试过程关于
SpringSecurity
认证处理的部分数据流会从
org.springframework.security.web.access.intercept.RequestMatcherDelegatingAuthorizationManager#check
函数进入,而SpringSecurity 路径正则匹配的关键点在org.springframework.security.web.util.matcher.RegexRequestMatcher#matches
函数里面,注释也说了这个函数的作用:Performs the match of the request URL (servletPath + pathInfo + queryString ) against the compiled pattern. If the query string is present, a question mark will be prepended.
其实本质上又是用了
HttpServletRequest
那几个函数进行重新构造然后再合成字符串,然后再去正则匹配,前面的处理没问题,这个CVE最后问题是出现正则匹配上总结
- %0a,%0d的Bypass方式,前提是正则匹配规则是类似这样的形式
RegexRequestMatcher("/aaa/.*", null)
- SpringSecurity自身的一些特性,比如
Firewall