Уязвимость в Java-springboot-codebase
Уязвимость в Java-springboot-codebase
Категория: Программы Теги: Уязвимости Опубликовано: 26 мая 2025

Уязвимость 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) – Серьёзное влияние на доступность системы.

Условия эксплуатации

  1. Доступ к API: Злоумышленник должен иметь доступ к эндпоинту /api/v1/files/{fileName} (например, через публичный IP или внутреннюю сеть).

  2. Конфигурация хранилища: В application-dev.properties задан корневой путь files.store.root = /file-store/.

  3. Абсолютный путь в запросе: Передача абсолютного пути (например, /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/passwdrootPath.resolve(filename) вернет абсолютный путь /etc/passwd, минуя корень /file-store/.


Анализ эксплоита

Рассмотрим общедоступный эксплоит CVE-2025-46822.py для понимания работы вектора атаки с использованием этой уязвимости:

  1. Формирование URL:

    encoded_path = quote(file_path, safe='')
    url = target + "/api/v1/files/" + encoded_path

    Кодирование пути гарантирует, что символы вроде / передаются как %2F.

  2. Отправка запроса:

    response = requests.get(url, allow_redirects=False)

    Эксплоит использует HTTP GET без аутентификации.


Защита от уязвимости

  1. Проверка относительных путей:

    Path resolvedPath = rootPath.resolve(filename).normalize();
    if (!resolvedPath.startsWith(rootPath)) {
        throw new SecurityException("Invalid path!");
    }
  2. Санкционирование входных данных:

    if (filename.contains("..") || filename.startsWith("/")) {
        throw new IllegalArgumentException("Invalid filename!");
    }
  3. Аутентификация и авторизация:
    Добавьте @PreAuthorize("isAuthenticated()") к методу контроллера.

Пример исправленного StorageService:

public Resource loadAsResource(String filename) {
    Path file = rootPath.resolve(filename).normalize();
    if (!file.startsWith(rootPath)) {
        return null;
    }
    return new FileSystemResource(file);
}
  1. Использование безопасных библиотек:
    Например, Apache Commons IO FilenameUtils.normalize().


Где используется уязвимый код?

Проект Java-springboot-codebase содержит примеры для обучения, но аналогичные ошибки встречаются в:

  • Веб-приложениях Spring Boot для загрузки файлов.

  • Микросервисах с публичными API для работы с хранилищами.

  • Корпоративных системах с конфигурацией files.store.root.

Алексей Черемных Алексей Черемных
64