Уязвимость CVE-2025-46822 в Java-springboot-codebase
Уязвимость в проекте Java-springboot-codebase позволяет злоумышленнику читать произвольные файлы на сервере через API-эндпоинт /api/v1/files/{fileName}. Проблема возникает из-за некорректной обработки абсолютных путей в методе Path.resolve() и отсутствия аутентификации.
Анализ уязвимости
Уровень опасности: Критический (CVSS 3.1: 9.8)
Вектор атаки: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
-
AV:N (Attack Vector: Network) – Уязвимость эксплуатируется через сеть, удалённо.
-
AC:L (Attack Complexity: Low) – Низкая сложность атаки: не требуется специальных условий.
-
PR:N (Privileges Required: None) – Привилегии не нужны.
-
UI:N (User Interaction: None) – Участие пользователя не требуется.
-
S:U (Scope: Unchanged) – Уязвимость не выходит за пределы компонента.
-
C:H (Confidentiality: High) – Полное раскрытие конфиденциальных данных.
-
I:H (Integrity: High) – Возможность модификации критических файлов.
-
A:H (Availability: High) – Серьёзное влияние на доступность системы.
Условия эксплуатации
-
Доступ к API: Злоумышленник должен иметь доступ к эндпоинту
/api/v1/files/{fileName}(например, через публичный IP или внутреннюю сеть). -
Конфигурация хранилища: В
application-dev.propertiesзадан корневой путьfiles.store.root = /file-store/. -
Абсолютный путь в запросе: Передача абсолютного пути (например,
/etc/passwd) в параметрfileName.
Пример уязвимого кода в FileController:
@GetMapping("/{fileName}")
public ResponseEntity<?> getFileByName(@PathVariable String name) {
var resource = storageService.loadAsResource(name); // Уязвимость!
return ResponseEntity.ok().body(resource);
}
В классе StorageService метод loadAsResource использует Path.resolve(), который не проверяет, находится ли итоговый путь внутри корневой директории:
public Resource loadAsResource(String filename) {
Path file = rootPath.resolve(filename).normalize(); // Небезопасно!
return new FileSystemResource(file);
}
Если передать filename=/etc/passwd, rootPath.resolve(filename) вернет абсолютный путь /etc/passwd, минуя корень /file-store/.
Анализ эксплоита
Рассмотрим общедоступный эксплоит CVE-2025-46822.py для понимания работы вектора атаки с использованием этой уязвимости:
-
Формирование URL:
encoded_path = quote(file_path, safe='') url = target + "/api/v1/files/" + encoded_path
Кодирование пути гарантирует, что символы вроде
/передаются как%2F. -
Отправка запроса:
response = requests.get(url, allow_redirects=False)
Эксплоит использует HTTP GET без аутентификации.
Защита от уязвимости
-
Проверка относительных путей:
Path resolvedPath = rootPath.resolve(filename).normalize(); if (!resolvedPath.startsWith(rootPath)) { throw new SecurityException("Invalid path!"); } -
Санкционирование входных данных:
if (filename.contains("..") || filename.startsWith("/")) { throw new IllegalArgumentException("Invalid filename!"); } -
Аутентификация и авторизация:
Добавьте@PreAuthorize("isAuthenticated()")к методу контроллера.
Пример исправленного StorageService:
public Resource loadAsResource(String filename) {
Path file = rootPath.resolve(filename).normalize();
if (!file.startsWith(rootPath)) {
return null;
}
return new FileSystemResource(file);
}
-
Использование безопасных библиотек:
Например, Apache Commons IOFilenameUtils.normalize().
Где используется уязвимый код?
Проект Java-springboot-codebase содержит примеры для обучения, но аналогичные ошибки встречаются в:
-
Веб-приложениях Spring Boot для загрузки файлов.
-
Микросервисах с публичными API для работы с хранилищами.
-
Корпоративных системах с конфигурацией
files.store.root.