Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit66363b9

Browse files
gh-109858: Protect zipfile from "quoted-overlap" zipbomb (GH-110016)
Raise BadZipFile when try to read an entry that overlaps with other entry orcentral directory.
1 parent183b97b commit66363b9

File tree

3 files changed

+73
-0
lines changed

3 files changed

+73
-0
lines changed

‎Lib/test/test_zipfile/test_core.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2272,6 +2272,64 @@ def test_decompress_without_3rd_party_library(self):
22722272
withzipfile.ZipFile(zip_file)aszf:
22732273
self.assertRaises(RuntimeError,zf.extract,'a.txt')
22742274

2275+
deftest_full_overlap(self):
2276+
data= (
2277+
b'PK\x03\x04\x14\x00\x00\x00\x08\x00\xa0lH\x05\xe2\x1e'
2278+
b'8\xbb\x10\x00\x00\x00\t\x04\x00\x00\x01\x00\x00\x00a\xed'
2279+
b'\xc0\x81\x08\x00\x00\x00\xc00\xd6\xfbK\\d\x0b`P'
2280+
b'K\x01\x02\x14\x00\x14\x00\x00\x00\x08\x00\xa0lH\x05\xe2'
2281+
b'\x1e8\xbb\x10\x00\x00\x00\t\x04\x00\x00\x01\x00\x00\x00\x00'
2282+
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00aPK'
2283+
b'\x01\x02\x14\x00\x14\x00\x00\x00\x08\x00\xa0lH\x05\xe2\x1e'
2284+
b'8\xbb\x10\x00\x00\x00\t\x04\x00\x00\x01\x00\x00\x00\x00\x00'
2285+
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00bPK\x05'
2286+
b'\x06\x00\x00\x00\x00\x02\x00\x02\x00^\x00\x00\x00/\x00\x00'
2287+
b'\x00\x00\x00'
2288+
)
2289+
withzipfile.ZipFile(io.BytesIO(data),'r')aszipf:
2290+
self.assertEqual(zipf.namelist(), ['a','b'])
2291+
zi=zipf.getinfo('a')
2292+
self.assertEqual(zi.header_offset,0)
2293+
self.assertEqual(zi.compress_size,16)
2294+
self.assertEqual(zi.file_size,1033)
2295+
zi=zipf.getinfo('b')
2296+
self.assertEqual(zi.header_offset,0)
2297+
self.assertEqual(zi.compress_size,16)
2298+
self.assertEqual(zi.file_size,1033)
2299+
self.assertEqual(len(zipf.read('a')),1033)
2300+
withself.assertRaisesRegex(zipfile.BadZipFile,'File name.*differ'):
2301+
zipf.read('b')
2302+
2303+
deftest_quoted_overlap(self):
2304+
data= (
2305+
b'PK\x03\x04\x14\x00\x00\x00\x08\x00\xa0lH\x05Y\xfc'
2306+
b'8\x044\x00\x00\x00(\x04\x00\x00\x01\x00\x00\x00a\x00'
2307+
b'\x1f\x00\xe0\xffPK\x03\x04\x14\x00\x00\x00\x08\x00\xa0l'
2308+
b'H\x05\xe2\x1e8\xbb\x10\x00\x00\x00\t\x04\x00\x00\x01\x00'
2309+
b'\x00\x00b\xed\xc0\x81\x08\x00\x00\x00\xc00\xd6\xfbK\\'
2310+
b'd\x0b`PK\x01\x02\x14\x00\x14\x00\x00\x00\x08\x00\xa0'
2311+
b'lH\x05Y\xfc8\x044\x00\x00\x00(\x04\x00\x00\x01'
2312+
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
2313+
b'\x00aPK\x01\x02\x14\x00\x14\x00\x00\x00\x08\x00\xa0l'
2314+
b'H\x05\xe2\x1e8\xbb\x10\x00\x00\x00\t\x04\x00\x00\x01\x00'
2315+
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$\x00\x00\x00'
2316+
b'bPK\x05\x06\x00\x00\x00\x00\x02\x00\x02\x00^\x00\x00'
2317+
b'\x00S\x00\x00\x00\x00\x00'
2318+
)
2319+
withzipfile.ZipFile(io.BytesIO(data),'r')aszipf:
2320+
self.assertEqual(zipf.namelist(), ['a','b'])
2321+
zi=zipf.getinfo('a')
2322+
self.assertEqual(zi.header_offset,0)
2323+
self.assertEqual(zi.compress_size,52)
2324+
self.assertEqual(zi.file_size,1064)
2325+
zi=zipf.getinfo('b')
2326+
self.assertEqual(zi.header_offset,36)
2327+
self.assertEqual(zi.compress_size,16)
2328+
self.assertEqual(zi.file_size,1033)
2329+
withself.assertRaisesRegex(zipfile.BadZipFile,'Overlapped entries'):
2330+
zipf.read('a')
2331+
self.assertEqual(len(zipf.read('b')),1033)
2332+
22752333
deftearDown(self):
22762334
unlink(TESTFN)
22772335
unlink(TESTFN2)

‎Lib/zipfile/__init__.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,7 @@ class ZipInfo (object):
395395
'compress_size',
396396
'file_size',
397397
'_raw_time',
398+
'_end_offset',
398399
)
399400

400401
def__init__(self,filename="NoName",date_time=(1980,1,1,0,0,0)):
@@ -429,6 +430,7 @@ def __init__(self, filename="NoName", date_time=(1980,1,1,0,0,0)):
429430
self.external_attr=0# External file attributes
430431
self.compress_size=0# Size of the compressed file
431432
self.file_size=0# Size of the uncompressed file
433+
self._end_offset=None# Start of the next local header or central directory
432434
# Other attributes are set by class ZipFile:
433435
# header_offset Byte offset to the file header
434436
# CRC CRC-32 of the uncompressed file
@@ -1488,6 +1490,12 @@ def _RealGetContents(self):
14881490
ifself.debug>2:
14891491
print("total",total)
14901492

1493+
end_offset=self.start_dir
1494+
forzinfoinsorted(self.filelist,
1495+
key=lambdazinfo:zinfo.header_offset,
1496+
reverse=True):
1497+
zinfo._end_offset=end_offset
1498+
end_offset=zinfo.header_offset
14911499

14921500
defnamelist(self):
14931501
"""Return a list of file names in the archive."""
@@ -1644,6 +1652,10 @@ def open(self, name, mode="r", pwd=None, *, force_zip64=False):
16441652
'File name in directory %r and header %r differ.'
16451653
% (zinfo.orig_filename,fname))
16461654

1655+
if (zinfo._end_offsetisnotNoneand
1656+
zef_file.tell()+zinfo.compress_size>zinfo._end_offset):
1657+
raiseBadZipFile(f"Overlapped entries:{zinfo.orig_filename!r} (possible zip bomb)")
1658+
16471659
# check for encrypted flag & handle password
16481660
is_encrypted=zinfo.flag_bits&_MASK_ENCRYPTED
16491661
ifis_encrypted:
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Protect:mod:`zipfile` from "quoted-overlap" zipbomb. It now raises
2+
BadZipFile when try to read an entry that overlaps with other entry or
3+
central directory.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp