[2.2.x] Fixed CVE-2021-3281 -- Fixed potential directory-traversal via archive.extract().
Thanks Florian Apolloner, Shai Berger, and Simon Charette for reviews. Thanks Wang Baohua for the report. Backport of 05413afa8c18cdb978fcdf470e09f7a12b234a23 from master.
This commit is contained in:
parent
ee9d623831
commit
21e7622dec
@ -27,6 +27,8 @@ import stat
|
|||||||
import tarfile
|
import tarfile
|
||||||
import zipfile
|
import zipfile
|
||||||
|
|
||||||
|
from django.core.exceptions import SuspiciousOperation
|
||||||
|
|
||||||
|
|
||||||
class ArchiveException(Exception):
|
class ArchiveException(Exception):
|
||||||
"""
|
"""
|
||||||
@ -133,6 +135,13 @@ class BaseArchive:
|
|||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def target_filename(self, to_path, name):
|
||||||
|
target_path = os.path.abspath(to_path)
|
||||||
|
filename = os.path.abspath(os.path.join(target_path, name))
|
||||||
|
if not filename.startswith(target_path):
|
||||||
|
raise SuspiciousOperation("Archive contains invalid path: '%s'" % name)
|
||||||
|
return filename
|
||||||
|
|
||||||
def extract(self):
|
def extract(self):
|
||||||
raise NotImplementedError('subclasses of BaseArchive must provide an extract() method')
|
raise NotImplementedError('subclasses of BaseArchive must provide an extract() method')
|
||||||
|
|
||||||
@ -155,7 +164,7 @@ class TarArchive(BaseArchive):
|
|||||||
name = member.name
|
name = member.name
|
||||||
if leading:
|
if leading:
|
||||||
name = self.split_leading_dir(name)[1]
|
name = self.split_leading_dir(name)[1]
|
||||||
filename = os.path.join(to_path, name)
|
filename = self.target_filename(to_path, name)
|
||||||
if member.isdir():
|
if member.isdir():
|
||||||
if filename and not os.path.exists(filename):
|
if filename and not os.path.exists(filename):
|
||||||
os.makedirs(filename)
|
os.makedirs(filename)
|
||||||
@ -198,11 +207,13 @@ class ZipArchive(BaseArchive):
|
|||||||
info = self._archive.getinfo(name)
|
info = self._archive.getinfo(name)
|
||||||
if leading:
|
if leading:
|
||||||
name = self.split_leading_dir(name)[1]
|
name = self.split_leading_dir(name)[1]
|
||||||
filename = os.path.join(to_path, name)
|
if not name:
|
||||||
|
continue
|
||||||
|
filename = self.target_filename(to_path, name)
|
||||||
dirname = os.path.dirname(filename)
|
dirname = os.path.dirname(filename)
|
||||||
if dirname and not os.path.exists(dirname):
|
if dirname and not os.path.exists(dirname):
|
||||||
os.makedirs(dirname)
|
os.makedirs(dirname)
|
||||||
if filename.endswith(('/', '\\')):
|
if name.endswith(('/', '\\')):
|
||||||
# A directory
|
# A directory
|
||||||
if not os.path.exists(filename):
|
if not os.path.exists(filename):
|
||||||
os.makedirs(filename)
|
os.makedirs(filename)
|
||||||
|
15
docs/releases/2.2.18.txt
Normal file
15
docs/releases/2.2.18.txt
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
===========================
|
||||||
|
Django 2.2.18 release notes
|
||||||
|
===========================
|
||||||
|
|
||||||
|
*February 1, 2021*
|
||||||
|
|
||||||
|
Django 2.2.18 fixes a security issue with severity "low" in 2.2.17.
|
||||||
|
|
||||||
|
CVE-2021-3281: Potential directory-traversal via ``archive.extract()``
|
||||||
|
======================================================================
|
||||||
|
|
||||||
|
The ``django.utils.archive.extract()`` function, used by
|
||||||
|
:option:`startapp --template` and :option:`startproject --template`, allowed
|
||||||
|
directory-traversal via an archive with absolute paths or relative paths with
|
||||||
|
dot segments.
|
@ -25,6 +25,7 @@ versions of the documentation contain the release notes for any later releases.
|
|||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 1
|
:maxdepth: 1
|
||||||
|
|
||||||
|
2.2.18
|
||||||
2.2.17
|
2.2.17
|
||||||
2.2.16
|
2.2.16
|
||||||
2.2.15
|
2.2.15
|
||||||
|
@ -5,6 +5,8 @@ import sys
|
|||||||
import tempfile
|
import tempfile
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
|
from django.core.exceptions import SuspiciousOperation
|
||||||
|
from django.test import SimpleTestCase
|
||||||
from django.utils.archive import Archive, extract
|
from django.utils.archive import Archive, extract
|
||||||
|
|
||||||
TEST_DIR = os.path.join(os.path.dirname(__file__), 'archives')
|
TEST_DIR = os.path.join(os.path.dirname(__file__), 'archives')
|
||||||
@ -87,3 +89,22 @@ class TestGzipTar(ArchiveTester, unittest.TestCase):
|
|||||||
|
|
||||||
class TestBzip2Tar(ArchiveTester, unittest.TestCase):
|
class TestBzip2Tar(ArchiveTester, unittest.TestCase):
|
||||||
archive = 'foobar.tar.bz2'
|
archive = 'foobar.tar.bz2'
|
||||||
|
|
||||||
|
|
||||||
|
class TestArchiveInvalid(SimpleTestCase):
|
||||||
|
def test_extract_function_traversal(self):
|
||||||
|
archives_dir = os.path.join(os.path.dirname(__file__), 'traversal_archives')
|
||||||
|
tests = [
|
||||||
|
('traversal.tar', '..'),
|
||||||
|
('traversal_absolute.tar', '/tmp/evil.py'),
|
||||||
|
]
|
||||||
|
if sys.platform == 'win32':
|
||||||
|
tests += [
|
||||||
|
('traversal_disk_win.tar', 'd:evil.py'),
|
||||||
|
('traversal_disk_win.zip', 'd:evil.py'),
|
||||||
|
]
|
||||||
|
msg = "Archive contains invalid path: '%s'"
|
||||||
|
for entry, invalid_path in tests:
|
||||||
|
with self.subTest(entry), tempfile.TemporaryDirectory() as tmpdir:
|
||||||
|
with self.assertRaisesMessage(SuspiciousOperation, msg % invalid_path):
|
||||||
|
extract(os.path.join(archives_dir, entry), tmpdir)
|
||||||
|
BIN
tests/utils_tests/traversal_archives/traversal.tar
Normal file
BIN
tests/utils_tests/traversal_archives/traversal.tar
Normal file
Binary file not shown.
BIN
tests/utils_tests/traversal_archives/traversal_absolute.tar
Normal file
BIN
tests/utils_tests/traversal_archives/traversal_absolute.tar
Normal file
Binary file not shown.
BIN
tests/utils_tests/traversal_archives/traversal_disk_win.tar
Normal file
BIN
tests/utils_tests/traversal_archives/traversal_disk_win.tar
Normal file
Binary file not shown.
BIN
tests/utils_tests/traversal_archives/traversal_disk_win.zip
Normal file
BIN
tests/utils_tests/traversal_archives/traversal_disk_win.zip
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user