CVE-2022-22978 Spring-Security 漏洞复现
1 说明
在Spring Security中使用RegexRequestMatcher且规则中包含带点号的正则表达式时,攻击者可以通过构造恶意数据包绕过身份认证
2 环境搭建
环境搭建地址可以参考如下的github 工程:https://github.com/DeEpinGh0st/CVE-2022-22978
3 漏洞复现
- 正常访问环境信息
- 通过%0a绕过访问限制
可以看到通过%0a绕过了spring security的用户鉴权
4 漏洞分析
4.1 源码对比
- 从github上拉取工程,拉取工程的地址为:https://github.com/DeEpinGh0st/CVE-2022-22978
- 参考官网的修改方案:https://github.com/spring-projects/spring-security/commit/70863952aeb9733499027714d38821db05654856
-
Pattern
类是java.util.regex
包的三个类之一,负责处理正则表达式相关 -
Pattern.DOTALL
:表示更改.的含义,使它与每一个字符匹配(包括换行符\n),默认情况下, 正则表达式中点(.)不会匹配换行符, 设置了Pattern.DOTALL
模式, 才会匹配所有字符包括换行符。 -
Pattern.CASE_INSENSITIVE
:忽略大小写。
从代码上看:可以看到RegexRequestMatcher.java
文件的修复是增加了对换行符的匹配以及忽略大小写。
接着看下对应的测试代码
RegexRequestMatchertests.java
文件也给了绕过的提示(\r的URl编码为%0d,\n的URL编码为%0a)。
4.2 查看java 正则说明
- 查看java doc 关于pattern的说明:https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html#DOTALLDoTALL 说明
DOTALL
public static final int DOTALL
Enables dotall mode.
在dotall模式中,表达式.
匹配任何字符,包括行结束符。默认情况下,此表达式不匹配行终止符。
也可以通过嵌入的标志表达式(?s)
,启用点所有模式。(s是“单行”模式的助记符,在Perl中这么说。)
- See Also:
Constant Field Values
UNICODE_CASE
public static final int UNICODE_CASE
Enables Unicode-aware case folding.
如果指定了该标志,则在通过case_sensitive标志启用时,将以与Unicode标准一致的方式进行不区分大小写的匹配。默认情况下,不区分大小写的匹配假设仅匹配US-ASCII字符集中的字符。
还可以通过嵌入标志表达式(?u)启用Unicode感知的大小写折叠。
指定此标志可能会造成性能损失。
- See Also:
Constant Field Values
从上述的doc的说明,可以查出,对于默认的Pattern模式,不开启DOTALL
时候,在默认匹配的时候不会匹配\r
\n
字符。
- 对比spring security的修改代码
public final class RegexRequestMatcher implements RequestMatcher {
private static final int DEFAULT = Pattern.DOTALL;
private static final int CASE_INSENSITIVE = DEFAULT | Pattern.CASE_INSENSITIVE;
private static final Log logger = LogFactory.getLog(RegexRequestMatcher.class);
@@ -68,7 +70,7 @@ public RegexRequestMatcher(String pattern, String httpMethod) {
* {@link Pattern#CASE_INSENSITIVE} flag set.
*/
public RegexRequestMatcher(String pattern, String httpMethod, boolean caseInsensitive) {
this.pattern = Pattern.compile(pattern, caseInsensitive ? CASE_INSENSITIVE : DEFAULT);
this.httpMethod = StringUtils.hasText(httpMethod) ? HttpMethod.valueOf(httpMethod) : null;
}
此修改已经默认开启了DOTALL,所有的字符都会对比。
4.3 漏洞说明
因此该漏洞主要是因为在正则匹配的时候产生的问题,由于匹配的模式选择的问题,导致了该漏洞。下面写个代码验证下
- 使用默认的正则
该正则默认模式,显示的结果为正则不匹配
- 正则开启DOTALL模式
开启DOTALL模式,正则显示匹配
4.4 漏洞分析
回过头来看下存在漏洞的代码
在匹配的时候只要输入url 为:/admin/111\n
即可绕过url限制,因为和/admin/.*
不匹配,因此绕过了鉴权。
Refer
1.https://github.com/spring-projects/spring-security/compare/5.6.3...5.6.4
2.https://nosec.org/home/detail/5006.html