最近的这两个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@EnableWebSecuritypublic 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
可能会有奇效。
公众号
家人们,欢送关注我的公众号“硬核平安”,跟我一起学起来!