路径遍历漏洞报告:CVE-2021-3281 补丁不完整
报告ID:#3328367 报告者:stackered 提交给:Django 报告时间:2025年9月5日,下午1:21(UTC) 状态:已验证、已解决、已公开
漏洞概述
在对历史漏洞补丁进行代码审查时,发现CVE-2021-3281的修复措施并不完整。为缓解该漏洞,曾在ZipArchive和TarArchive类的extract函数中添加了防护逻辑,以确保所有文件都在基础文件夹(target_path)下解压。
关键防护代码如下(位于django/django/utils/archive.py):
|
|
该逻辑使用abspath函数获取绝对且规范化的唯一路径,然后利用startswith函数验证目标路径是否属于预期的基础文件夹。然而,abspath函数会移除路径末尾的分隔符,这使得防护逻辑不足以防御部分路径遍历攻击。
漏洞原理
假设基础文件夹定义为/var/lib/,初始文件名为/var/library/test.txt。由于末尾的斜杠被移除,攻击者仍然可以部分路径遍历到另一个以相同字符开头的目录,因为检查仍会通过。
|
|
在Python命令行中执行以下代码不会引发预期的异常:
|
|
漏洞影响
这导致了部分路径遍历漏洞,使得攻击者在解压归档文件(tar和zip)时能够将文件写入基础目录之外。一个真实的部分路径遍历漏洞示例如下。
交互与验证过程
初始提交与响应
- 2025年9月11日:Django安全团队成员
nessita确认收到报告,要求保密并告知评估流程。 - 2025年9月16日:Django团队成员
theorangeone将状态更改为“需要更多信息”,请求提供能利用Django工具的概念验证(PoC)。
概念验证(PoC)提供
报告者stackered提供了功能性PoC:
|
|
前提是在/home目录下创建两个可由运行PoC的同一用户写入的目录(john和johnny)。即使目标解压目录设置为/home/john,此PoC也会在/home/johnny/.ssh/authorized_keys中添加(或创建)攻击者的SSH密钥。
漏洞确认与修复
- 2025年9月18日:Django团队成员
sarahvboyce将漏洞严重性从中等(5.3)调整为低(3.7),理由是攻击者需要知道用户将通过startapp --template等方式进行解压的目录。随后状态更改为“已分类”,确认了漏洞并请求了CVE编号。 - 团队提供了拟议的缓解方案补丁(
0001-Fixed-CVE-2025-XXXXX-Fixed-potential-partial-directo.patch),要求报告者测试。计划在博客文章中提及发现者“stackered”。 - 报告者反馈:报告者确认补丁能修复问题,但就严重性评估提出了不同看法,认为在某些场景下(如应用开源、目录易猜测或解压目录受攻击者控制),漏洞严重性应视为中等。
- 2025年9月24日:Django团队确认已分配CVE-2025-59682,修复版本计划于10月1日发布。团队维持当前严重性评估,理由是
archive.extract是未公开的方法,根据安全政策通常不在测试范围内。漏洞范围仅限于python manage.py startproject/app --template的使用场景,这些是开发者在设置项目时运行的命令,不用于已部署的应用程序。
报告关闭与公开
- 2025年10月2日:Django团队成员
jacobtylerwalls将报告状态更改为“已解决”,漏洞已于10月1日在Django版本5.2.7、5.1.13和4.2.25中修复。 - 2025年11月11日:互联网漏洞赏金(Internet Bug Bounty)判定此报告不符合赏金奖励条件。
- 2025年11月21日:报告者请求公开报告,Django团队同意,报告被公开。
报告元数据
- 弱点类型:路径遍历(Path Traversal)
- CVE ID:CVE-2021-3281(提及),CVE-2025-59682(新分配)
- 赏金状态:隐藏
- 参与者:stackered (报告者), Django安全团队 (nessita, theorangeone, sarahvboyce, jacobtylerwalls)