Что касается этих двух недавних CVE, я читал, что многие отечественные разведки оценили их как высокорисковые, поэтому я подумал о том, чтобы взглянуть на принципы. Прочитав их, я обнаружил, что они относительно просты, а сценарии, необходимые для использования. относительно ограничены (особенно первый), поэтому я просто случайно Просто взгляну
Давайте сначала посмотрим объявление на официальном сайте.(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 passnull
toAuthenticationTrustResolver.isFullyAuthenticated
The application only usesisFullyAuthenticated
via Method Security or HTTP Request Security
Вероятно, это означает прямой вызов AuthenticationTrustResolver.isFullyAuthenticated(Authentication)`. Если Authentication имеет значение null, метод всегда будет возвращать true, что приводит к некоторым результатам, противоречащим ожиданиям.
AuthenticationTrustResolver
в интерфейсе isFullyAuthenticated
Метод, используемый для проверки Authentication
Является ли объект полностью аутентифицированным, т. е. не анонимным пользователем. существовать Spring Security , вы можете использовать этот метод, чтобы определить, прошел ли пользователь полную аутентификацию.
Затронутые версии:
Представьте 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() // Конечная точка/,/индекс Не требуется аутентификация, управление осуществляется напрямую приложением.
.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
Добавлено суждение о том, что объект аутентификации пуст.
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
Проверять,Обычный доступ после прохождения,Бэкэнд имеет простое решение хоста по черному списку (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);
// Если хост evil.com будет перехвачен
if (host != null && host.equals("evil.com")) {
System.out.println("403");
}else {
System.out.println("pass");
}
В простом сценарии, исключающем использование 302, ip, перепривязку и т. д., есть ли способ обойти это, просто используя UriComponentsBuilder?
Обычно мы знаем, как обходитьssrfбудет использоваться@
,еслиurlдляhttp://A.com@B.com
, некоторые библиотеки проверки хоста идентифицируют этот urlHost как A.com, а браузер или http Клиент фактически получит доступ к B.com. Используя эту разницу, вы можете обойти некоторые ограничения черного списка и напрямую получить доступ к вредоносным веб-сайтам.
Попробуйте этоUriComponentsBuilder
Является ли это возможным:
Это очевидно,В этом методе,Невозможно использовать его напрямую таким образом.,Но судя по символам регулярного выражения, удаленным при ремонте уязвимости,мыuserinfoНаконец добавьте один[
,протестируй это
Успешно обойдено:
Однако, обойдя этот путь, в большинстве случаев вы не сможете напрямуюиспользовать Оригиналurlпосетить,потому чтодляurlсуществовать в[
Программа сообщит об ошибке:
Поэтому я думаю, что может быть больше сценариев использования.использоватьUriComponentsBuilder
ТоритоhostпеределыватьurlСоединены вместепосетить
Spring Эта уязвимость в системе безопасности не может быть использована в реальном бою, поскольку тестирование черного ящика может обнаружить ее без авторизации без какой-либо управляемой пользователем обходной схемы. Для сравнения: Spring. FrameworkВ реальном бою этоurlУвеличение контролируемых площадейxxx[@yyy.com
Это может творить чудеса.