共计 4690 个字符,预计需要花费 12 分钟才能阅读完成。
最近的这两个 cve 我看国内很多情报将其评为高危,所以想着去看看原理,看完发现都比较简单,利用要求的场景也绝对无限(特地是第一个),所以就轻易看下就行了
Spring Security 用户认证绕过(CVE-2024-22234)
先看下官网的布告(https://spring.io/security/cve-2024-22234)
In Spring Security, versions 6.1.x prior to 6.1.7 and versions 6.2.x prior to 6.2.2, an application is vulnerable to broken access control when it directly uses the
AuthenticationTrustResolver.isFullyAuthenticated(Authentication)
method.Specifically, an application is vulnerable if:
- The application uses
AuthenticationTrustResolver.isFullyAuthenticated(Authentication)
directly and anull
authentication parameter is passed to it resulting in an erroneoustrue
return value.An application is not vulnerable if any of the following is true:
- The application does not use
AuthenticationTrustResolver.isFullyAuthenticated(Authentication)
directly.- The application does not pass
null
toAuthenticationTrustResolver.isFullyAuthenticated
- The application only uses
isFullyAuthenticated
via Method Security or HTTP Request Security
大略意思是间接调用`AuthenticationTrustResolver.isFullyAuthenticated(Authentication)
,若 Authentication 为 null,则办法会永远返回真,从而产生一些与预期相同的后果。
AuthenticationTrustResolver
接口中的 isFullyAuthenticated
办法用于查看 Authentication
对象是否齐全通过身份验证,即是否不是匿名用户。在 Spring Security 中,能够应用这个办法来确定用户是否曾经进行了残缺的身份验证。
影响版本为:
- 6.1.0 to 6.1.6
- 6.2.0 to 6.2.1
环境搭建
引入 pom,理论调用:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
减少下明码验证和 /index 的无鉴权的配置(交给利用手动配置)
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((requests) -> requests
.requestMatchers("/", "/index").permitAll() // 端点 /、/index 无需鉴权,交给利用间接管制
.anyRequest().authenticated()
)
.formLogin((form) -> form
.loginPage("/login")
.permitAll())
.logout((logout) -> logout.permitAll());
return http.build();}
@Bean
public UserDetailsService userDetailsService() {
UserDetails user =
User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
}
新增控制器并配置须要用户手动输出明码(isFullyAuthenticated
)后能力拜访的逻辑:
@GetMapping("/index")
@ResponseBody
public String index(){
// CVE-2024-22234
// 获取以后的认证对象
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
System.out.println(authentication);
// 创立 AuthenticationTrustResolver 实例
AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
// 应用 isFullyAuthenticated 办法查看是否齐全通过身份验证
boolean fullyAuthenticated = trustResolver.isFullyAuthenticated(authentication); // 传递 null 返回即为 true
String msg = "";
if (fullyAuthenticated) {msg = "用户已齐全通过身份验证";} else {msg = "用户可能是匿名用户或者仅局部通过身份验证";}
return msg;
}
复现
失常状况下,如果没有通过认证,返回的页面为:
进入登录页面失常登录后
返回的页面为:
如果开发在某些状况,比方手动革除 SecurityContextHolder
中的 Authentication
信息或通过 异步解决 导致在异步线程中没有可用的信息 getAuthentication()
返回null
, 则会导致认证校验的生效,咱们这里为了复现就手动置为 null,
boolean fullyAuthenticated = trustResolver.isFullyAuthenticated(null);
重启利用,在不登陆的状况下,从新拜访/index
,发现 isFullyAuthenticated 曾经间接返回了 true。拜访鉴权后的页面
修复
修复形式也比较简单在isFullyAuthenticated
中减少了对 authentication 对象为空的判断
Spring Framework SSRF or open redirect(CVE-2024-22243)
Applications that use
UriComponentsBuilder
to parse an externally provided URL (e.g. through a query parameter) AND perform validation checks on the host of the parsed URL may be vulnerable to a open redirect attack or to a SSRF attack if the URL is used after passing validation checks.
这个看官网形容只晓得应用 UriComponentsBuilder 这个办法来做 host 校验,会导致重定向和 ssrf,粗看下源码不晓得是怎么回事,看了下代码更新记录,很简略只是将 uri 匹配中 userinfo 匹配的正则表达式去掉[
。
pre:
private static final String USERINFO_PATTERN = "([^@\\[/?#]*)";
now:
private static final String USERINFO_PATTERN = "([^@/?#]*)";
环境搭建
这里假如存在一个场景,后端会将用户输出的 url 交给 UriComponentsBuilder
进行验证,通过后进行失常的拜访,后端有个简略的黑名单 host 判断(evil.com):
String url = "http://xxx.com";
UriComponents uriComponents = UriComponents uriComponents = UriComponentsBuilder.fromUriString(url).build();
String host = uriComponents.getHost();
System.out.println("userinfo:" + uriComponents.getUserInfo());
System.out.println("host:" + host);
// 如果 host 为 evil.com 则会被拦挡
if (host != null && host.equals("evil.com")) {System.out.println("403");
}else {System.out.println("pass");
}
简略场景,排除应用 302、ip、rebind 等形式,单纯从 UriComponentsBuilder 来进行绕过有什么方法?
复现
个别状况下咱们晓得绕过 ssrf 会用到@
,如果 url 为http://A.com@B.com
, 局部的 host 校验库会辨认这个 urlHost 为 A.com, 而浏览器或者 http client 理论会拜访 B.com 利用这种差别就能绕过局部黑名单限度,间接拜访歹意网站。
试下 UriComponentsBuilder
可不可以:
很显著,在这个办法中,间接这么用是不行的,但依据破绽的修复删除的正则表达式符号来看,咱们在 userinfo 最初减少一个[
, 测试一下
胜利绕过:
不过这样绕过后大部分状况下不能间接应用原 url 进行拜访,因为 url 中存在[
会让程序报错:
所以更多利用场景我猜可能是应用 UriComponentsBuilder
取的 host 从新进行 url 拼接来进行拜访
总结
Spring Security 中这个破绽可能对于实战利用不大,因为黑盒测未受权都能测试进去不须要什么用户可控的绕过姿态,相对而言 Spring Framework 这个在实战中对于 url 可控的中央减少xxx[@yyy.com
可能会有奇效。
公众号
家人们,欢送关注我的公众号“硬核平安”,跟我一起学起来!