Spring Security RegexRequestMatcher 认证绕过 (CVE-2022-22978)
SpringSecurity是Spring的一个访问控制框架,跟Shiro类似,基本功能是“认证”(Authentication)与 “授权” (Authorization)。
这个洞是身份认证的绕过,感觉有点像PHP在正则匹配的时候没有使用m参数进行多行匹配,导致可以使用%0a
或%0d
进行换行,从而绕过正则表达式。在 Spring Security 正则表达式中使用带有 .
的 RegexRequestMatcher 的应用程序可能容易受到授权绕过。
影响版本如下:
- 5.5.x prior to 5.5.7
- 5.6.x prior to 5.6.4
- Earlier unsupported versions
SpringSecurity设置
首先,配置SpringSecurity需要一个配置类并继承WebSecurityConfigurerAdapter,重写里面的configure
方法:
package com.example.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
@EnableWebSecurity
public class SecurityConfigDemo extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().regexMatchers("/admin/.*").authenticated();
}
}
解释:
- 设置http请求是否需要进行认证配置:
http.authorizeRequests()
主要是对url进行访问权限控制,通过这个方法来实现url授权操作:- 然后就是对URL进行匹配:
anyRequest()
:表示匹配所有的url请求antMatcher(String regx)
:传递一个ant表达式参数,表示匹配所有满足ant表达式的请求regexMatchers(String regexPattern)
:传递一个参数,使用正则表达式进行匹配。
regexMatchers()
和antMatchers()
主要的区别就是参数,antMatchers()
参数是ant表达式,而regexMatchers()
参数是正则表达式。
- 然后就是对匹配上的URL配置认证,常用的有:
permitAll()
:表示所匹配的URL任何人都允许访问anonymous()
:表示可以匿名访问匹配的URL。和permitAll()
效果类似,只是设置为anonymous()
的url会执行filterChain中的filterdenyAll()
:表示所匹配的URL都不允许被访问。authenticated()
:表示所匹配的URL都需要被认证才能访问rememberMe()
:允许通过remember-me登录的用户访问
因此,这里配置为:对HTTP请求中使用正则匹配对/admin/
后面接任意字符的URL进行认证。
漏洞分析
首先找到RegexRequestMatcher类下的matches
方法:
这里可以发现,先获取请求的URL,然后然后进行获取匹配器进行匹配,由于之前在配置中使用的是正则表达式的匹配模式,因此这里就是使用正则表达式进行对URL的匹配。
对比 5.6.4 及 5.6.3 版本的 RegexRequestMatcher.java
:
Pattern 类是 java.util.regex
包的三个类之一,负责处理正则表达式相关
Pattern.DOTALL
:表示更改.
的含义,使它与每一个字符匹配(包括换行符\n
),默认情况下,,正则表达式中点.
不会匹配换行符,设置了Pattern.DOTALL
模式,才会匹配所有字符包括换行符。
Pattern.CASE_INSENSITIVE
:忽略大小写。
可以看到 RegexRequestMatcher.java 文件的修复是增加了对换行符的匹配以及忽略大小写。而且下边的RegexRequestMatchertests.java
文件也给了绕过的提示(\r的URl编码为%0d
,\n
的URL编码为%0a
)。
因此这里可以理解为:在URL中使用%0a
或%0d
就可以绕过SpringSecurity中正则表达式的匹配,从而绕过认证访问到需要认证的资源。
漏洞复现
在上面SpringSecurity配置的基础上,新增一个控制器:
package com.example.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ControllerDemo {
@GetMapping("/admin/*")
public String ToAdmin() {
return "hello admin";
}
}
其路由为/admin/*
,因此HTTP访问该方法时会先经过SpringSecurity的认证才能够访问。
正常情况下,请求/admin/hh
:
显示禁止访问,因为我们都没有经过认证。
然而,请求/admin/%0d123
:
发现绕过了认证,说明SpringSecurity的正则匹配失效了。
参考资料
Spring Security RegexRequestMatcher 认证绕过漏洞分析(CVE-2022-22978)
CVE-2022-22978 Spring Security RegexRequestMatcher 认证绕过漏洞与利用场景分析
SpringSecurity权限管理框架系列(六)-Spring Security框架自定义配置类详解(二)之authorizeRequests配置详解