0%

Spring-Security大小写敏感比较授权绕过(CVE-2024-38827)

Spring-Security大小写敏感比较授权绕过(CVE-2024-38827)

漏洞描述

img.png

漏洞分析

很明显的原理了,在不同的语言环境中String.toLowerCase()String.toUpperCase() 得到的结果不一致导致可能的授权绕过。
比如在英文环境:i 的大写为 I
在土耳其语环境中 i 的大写为 İ
这种不一致导致可能的绕过。
然而在实践中这种情况发生的概率几乎为零。
举个例子,在Spring Security的补丁中由下面的修改
img_1.png
InMemoryUserDetailsManagercreateUser方法中在调用 toLowerCase方法对用户名进行处理的时候严格限制了本地化方案。
设想这样一种场景,一个应用在启动的时候会调用 InMemoryUserDetailsManager 创建一些默认用户,如下面的代码

1
2
3
4
5
6
7
8
9
10
11
@Bean
public UserDetailsService userDetailsService() {
Locale.setDefault(new Locale("tr", "TR")); // 设置当前语言环境为土耳其语
UserDetails user = User.withDefaultPasswordEncoder()
.username("useri")
.password("password")
.roles("USER")
.build();

return new InMemoryUserDetailsManager(user);
}

InMemoryUserDetailsManager实例化是最终会调用到createUser方法。
在某一个控制器中提供了另一个套逻辑用于动态的增加用户,如下面的代码

1
2
3
4
5
6
7
8
9
10
11
12
@GetMapping("/test")
public ResponseEntity<String> blog() {
UserDetails user = User.withDefaultPasswordEncoder()
.username("userİ")
.password("password123")
.roles("USER")
.build();
if (userDetailsService instanceof InMemoryUserDetailsManager) {
((InMemoryUserDetailsManager) userDetailsService).createUser(user);
}
return ResponseEntity.ok("success");
}

添加用户时使用的是用户名userİ 其在被添加时会被转为小写useri,攻击者可能通过这种方式尝试去覆盖掉默认用户的密码,这看似时可行的,可事实真的如此吗
在调用createUser的时候会调用userExists方法检查当前用户是否存在

1
this.users.containsKey(username.toLowerCase());  

此处对用户输入的用户名进行了小写处理,所以当用户名是userİ时,userExists方法会返回true,从而导致createUser方法会直接返回,不能覆盖添加用户。
这样看起来这个漏洞时很鸡肋的,Spring Security做出的修改貌似也只是为了避免一种绕过的可能性。
那么什么情况下会存在绕过呢?
一个是当前系统的语言环境发生了变化却仍然沿用老数据的时候。
另一种情况是在进行一些比较的时候
例如,开发者在开发时按照ascii标准进行大小写变换处理,假设由一个用户admin是管理员账户,通过将admin转换为大写ADMIN从而获得到其角色,然后与
ADMIN做比较确认其具有管理员权限。
此时如果程序运行在土耳其语的语言环境中,用户输入用户名admin,此时转换为大写为ADMİNADMIN比较导致比较结果为false,从而导致系统拒绝admin用户访问。
这个例子算是拒绝访问,认证绕过就是需要在某个语言环境中存在某一个特殊的字符串转为大写后等于ADMIN,从而使得该用户具有了管理员权限从而完成提权。
总之是一个很难使用的漏洞

参考链接

Buy me a coffee.

欢迎关注我的其它发布渠道