路径遍历漏洞:CVE-2021-3281 的不完全补丁
报告提交者: stackered 报告日期: 2025年9月5日 UTC 下午1:21 报告状态: 已解决
漏洞概述
在对历史漏洞补丁进行代码审查时,我发现针对 CVE-2021-3281 的修复并不完整。该漏洞的原始缓解措施是在 ZipArchive 和 TarArchive 类的 extract 函数中增加了防护逻辑,以确保所有文件都被提取到基础文件夹(target_path)之下。
技术分析
原始防护代码
|
|
这段代码使用 abspath 函数获取绝对且规范化的唯一路径,然后利用 startswith 函数验证目标路径是否位于预期的基础文件夹内。
漏洞根源
abspath 函数会移除路径末尾的分隔符,这使得防护逻辑不足以防御部分路径遍历攻击。
攻击示例:
假设基础文件夹定义为 /var/lib/,初始文件名为 /var/library/test.txt。由于末尾斜杠被移除,攻击者仍然可以通过部分路径遍历到另一个以相同字符开头的目录,因为此检查会通过:
|
|
在Python命令行中执行以下代码不会引发预期的异常:
|
|
实际影响
这导致了一个部分路径遍历漏洞,使得攻击者在解压归档文件(tar 和 zip)时,能够将文件写入基础目录之外。
交互与验证过程
初始回应
Django 安全团队成员 nessita 于 2025年9月11日回应,确认收到报告并请求保密,同时告知评估可能需要数周时间。
请求更多信息
2025年9月16日,Django 工作人员 theorangeone 将状态更改为"需要更多信息",表示无法自行复现该问题,要求提供使用 Django 工具并展示漏洞利用的概念验证(PoC)代码。
提供 PoC
报告提交者 stackered 随后提供了一个功能性的 PoC 代码:
|
|
PoC 说明:
在 /home 目录下创建两个可由运行 PoC 的同一用户写入的目录(john 和 johnny)。即使目标解压目录设置为 /home/john,此代码也会在 /home/johnny/.ssh/authorized_keys 中添加(如果不存在则创建)攻击者的 SSH 密钥。
漏洞确认与修复
2025年9月18日,Django 工作人员 sarahvboyce 将漏洞严重性从"中(5.3)“调整为"低(3.7)",并将状态更改为"已分类”。她指出,要使此攻击生效,攻击者必须知道用户将通过 startapp --template 等命令在哪个目录进行解压。
Django 团队确认了该漏洞,并已申请 CVE 编号。他们附上了提议的缓解解决方案(补丁文件 0001-Fixed-CVE-2025-XXXXX-Fixed-potential-partial-directo.patch),请报告者测试该补丁以确保其可靠地修复问题。
关于严重性的讨论
报告者 stackered 对严重性评级提出异议,认为在许多情况下(例如通过拦截和分析请求、开源应用程序或攻击者可控制解压目录),攻击者可能猜出或知晓解压目录,因此最初评估为"中危"是合理的。
Django 团队 sarahvboyce 回应称,他们维持当前的评估,因为 archive.extract 是一个未记录的方法,根据其安全政策,通常不在测试范围内。该方法的有效使用范围仅限于 python manage.py startproject/app --template,这些是开发者在设置项目时运行的命令,并不在已部署的应用程序中使用。
最终处理
漏洞修复
该漏洞于 2025年10月1日随 Django 版本 5.2.7、5.1.13 和 4.2.25 的发布得到修复。Django 工作人员 jacobtylerwalls 于 2025年10月2日将报告状态关闭并标记为"已解决"。
赏金决定
互联网漏洞赏金计划(The Internet Bug Bounty)于 2025年11月11日决定此报告不符合获得赏金的条件。
报告披露
报告者 stackered 于 2025年11月21日左右请求披露此报告,并获得了 Django 工作人员的同意。报告随后被公开。
报告元数据
-
报告 ID: #3328367
-
报告给: Django
-
状态: 已解决
-
严重性: 低(3.7)
-
披露日期: 2025年11月21日 UTC 下午7:05
-
弱点类型: 路径遍历
-
赏金: 无