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

Commit8281fc1

Browse files
pythongh-109858: Protect zipfile from "quoted-overlap" zipbomb (pythonGH-110016)
Raise BadZipFile when try to read an entry that overlaps with other entry orcentral directory.(cherry picked from commit66363b9)Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
1 parent435e891 commit8281fc1

File tree

3 files changed

+75
-0
lines changed

3 files changed

+75
-0
lines changed

‎Lib/test/test_zipfile.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2216,6 +2216,66 @@ def test_decompress_without_3rd_party_library(self):
22162216
withzipfile.ZipFile(zip_file)aszf:
22172217
self.assertRaises(RuntimeError,zf.extract,'a.txt')
22182218

2219+
@requires_zlib()
2220+
deftest_full_overlap(self):
2221+
data= (
2222+
b'PK\x03\x04\x14\x00\x00\x00\x08\x00\xa0lH\x05\xe2\x1e'
2223+
b'8\xbb\x10\x00\x00\x00\t\x04\x00\x00\x01\x00\x00\x00a\xed'
2224+
b'\xc0\x81\x08\x00\x00\x00\xc00\xd6\xfbK\\d\x0b`P'
2225+
b'K\x01\x02\x14\x00\x14\x00\x00\x00\x08\x00\xa0lH\x05\xe2'
2226+
b'\x1e8\xbb\x10\x00\x00\x00\t\x04\x00\x00\x01\x00\x00\x00\x00'
2227+
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00aPK'
2228+
b'\x01\x02\x14\x00\x14\x00\x00\x00\x08\x00\xa0lH\x05\xe2\x1e'
2229+
b'8\xbb\x10\x00\x00\x00\t\x04\x00\x00\x01\x00\x00\x00\x00\x00'
2230+
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00bPK\x05'
2231+
b'\x06\x00\x00\x00\x00\x02\x00\x02\x00^\x00\x00\x00/\x00\x00'
2232+
b'\x00\x00\x00'
2233+
)
2234+
withzipfile.ZipFile(io.BytesIO(data),'r')aszipf:
2235+
self.assertEqual(zipf.namelist(), ['a','b'])
2236+
zi=zipf.getinfo('a')
2237+
self.assertEqual(zi.header_offset,0)
2238+
self.assertEqual(zi.compress_size,16)
2239+
self.assertEqual(zi.file_size,1033)
2240+
zi=zipf.getinfo('b')
2241+
self.assertEqual(zi.header_offset,0)
2242+
self.assertEqual(zi.compress_size,16)
2243+
self.assertEqual(zi.file_size,1033)
2244+
self.assertEqual(len(zipf.read('a')),1033)
2245+
withself.assertRaisesRegex(zipfile.BadZipFile,'File name.*differ'):
2246+
zipf.read('b')
2247+
2248+
@requires_zlib()
2249+
deftest_quoted_overlap(self):
2250+
data= (
2251+
b'PK\x03\x04\x14\x00\x00\x00\x08\x00\xa0lH\x05Y\xfc'
2252+
b'8\x044\x00\x00\x00(\x04\x00\x00\x01\x00\x00\x00a\x00'
2253+
b'\x1f\x00\xe0\xffPK\x03\x04\x14\x00\x00\x00\x08\x00\xa0l'
2254+
b'H\x05\xe2\x1e8\xbb\x10\x00\x00\x00\t\x04\x00\x00\x01\x00'
2255+
b'\x00\x00b\xed\xc0\x81\x08\x00\x00\x00\xc00\xd6\xfbK\\'
2256+
b'd\x0b`PK\x01\x02\x14\x00\x14\x00\x00\x00\x08\x00\xa0'
2257+
b'lH\x05Y\xfc8\x044\x00\x00\x00(\x04\x00\x00\x01'
2258+
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
2259+
b'\x00aPK\x01\x02\x14\x00\x14\x00\x00\x00\x08\x00\xa0l'
2260+
b'H\x05\xe2\x1e8\xbb\x10\x00\x00\x00\t\x04\x00\x00\x01\x00'
2261+
b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$\x00\x00\x00'
2262+
b'bPK\x05\x06\x00\x00\x00\x00\x02\x00\x02\x00^\x00\x00'
2263+
b'\x00S\x00\x00\x00\x00\x00'
2264+
)
2265+
withzipfile.ZipFile(io.BytesIO(data),'r')aszipf:
2266+
self.assertEqual(zipf.namelist(), ['a','b'])
2267+
zi=zipf.getinfo('a')
2268+
self.assertEqual(zi.header_offset,0)
2269+
self.assertEqual(zi.compress_size,52)
2270+
self.assertEqual(zi.file_size,1064)
2271+
zi=zipf.getinfo('b')
2272+
self.assertEqual(zi.header_offset,36)
2273+
self.assertEqual(zi.compress_size,16)
2274+
self.assertEqual(zi.file_size,1033)
2275+
withself.assertRaisesRegex(zipfile.BadZipFile,'Overlapped entries'):
2276+
zipf.read('a')
2277+
self.assertEqual(len(zipf.read('b')),1033)
2278+
22192279
deftearDown(self):
22202280
unlink(TESTFN)
22212281
unlink(TESTFN2)

‎Lib/zipfile.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,7 @@ class ZipInfo (object):
367367
'compress_size',
368368
'file_size',
369369
'_raw_time',
370+
'_end_offset',
370371
)
371372

372373
def__init__(self,filename="NoName",date_time=(1980,1,1,0,0,0)):
@@ -408,6 +409,7 @@ def __init__(self, filename="NoName", date_time=(1980,1,1,0,0,0)):
408409
self.external_attr=0# External file attributes
409410
self.compress_size=0# Size of the compressed file
410411
self.file_size=0# Size of the uncompressed file
412+
self._end_offset=None# Start of the next local header or central directory
411413
# Other attributes are set by class ZipFile:
412414
# header_offset Byte offset to the file header
413415
# CRC CRC-32 of the uncompressed file
@@ -1437,6 +1439,12 @@ def _RealGetContents(self):
14371439
ifself.debug>2:
14381440
print("total",total)
14391441

1442+
end_offset=self.start_dir
1443+
forzinfoinsorted(self.filelist,
1444+
key=lambdazinfo:zinfo.header_offset,
1445+
reverse=True):
1446+
zinfo._end_offset=end_offset
1447+
end_offset=zinfo.header_offset
14401448

14411449
defnamelist(self):
14421450
"""Return a list of file names in the archive."""
@@ -1590,6 +1598,10 @@ def open(self, name, mode="r", pwd=None, *, force_zip64=False):
15901598
'File name in directory %r and header %r differ.'
15911599
% (zinfo.orig_filename,fname))
15921600

1601+
if (zinfo._end_offsetisnotNoneand
1602+
zef_file.tell()+zinfo.compress_size>zinfo._end_offset):
1603+
raiseBadZipFile(f"Overlapped entries:{zinfo.orig_filename!r} (possible zip bomb)")
1604+
15931605
# check for encrypted flag & handle password
15941606
is_encrypted=zinfo.flag_bits&_MASK_ENCRYPTED
15951607
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