+67
-3
lines changedFilter options
+67
-3
lines changed Original file line number Diff line number Diff line change
@@ -27,6 +27,8 @@
27
27
import tarfile
28
28
import zipfile
29
29
30
+
from django.core.exceptions import SuspiciousOperation
31
+
30
32
31
33
class ArchiveException(Exception):
32
34
"""
@@ -133,6 +135,13 @@ def has_leading_dir(self, paths):
133
135
return False
134
136
return True
135
137
138
+
def target_filename(self, to_path, name):
139
+
target_path = os.path.abspath(to_path)
140
+
filename = os.path.abspath(os.path.join(target_path, name))
141
+
if not filename.startswith(target_path):
142
+
raise SuspiciousOperation("Archive contains invalid path: '%s'" % name)
143
+
return filename
144
+
136
145
def extract(self):
137
146
raise NotImplementedError('subclasses of BaseArchive must provide an extract() method')
138
147
@@ -155,7 +164,7 @@ def extract(self, to_path):
155
164
name = member.name
156
165
if leading:
157
166
name = self.split_leading_dir(name)[1]
158
-
filename = os.path.join(to_path, name)
167
+
filename = self.target_filename(to_path, name)
159
168
if member.isdir():
160
169
if filename:
161
170
os.makedirs(filename, exist_ok=True)
@@ -198,8 +207,10 @@ def extract(self, to_path):
198
207
info = self._archive.getinfo(name)
199
208
if leading:
200
209
name = self.split_leading_dir(name)[1]
201
-
filename = os.path.join(to_path, name)
202
-
if filename.endswith(('/', '\\')):
210
+
if not name:
211
+
continue
212
+
filename = self.target_filename(to_path, name)
213
+
if name.endswith(('/', '\\')):
203
214
# A directory
204
215
os.makedirs(filename, exist_ok=True)
205
216
else:
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
1
+
===========================
2
+
Django 2.2.18 release notes
3
+
===========================
4
+
5
+
*February 1, 2021*
6
+
7
+
Django 2.2.18 fixes a security issue with severity "low" in 2.2.17.
8
+
9
+
CVE-2021-3281: Potential directory-traversal via ``archive.extract()``
10
+
======================================================================
11
+
12
+
The ``django.utils.archive.extract()`` function, used by
13
+
:option:`startapp --template` and :option:`startproject --template`, allowed
14
+
directory-traversal via an archive with absolute paths or relative paths with
15
+
dot segments.
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
1
+
===========================
2
+
Django 3.0.12 release notes
3
+
===========================
4
+
5
+
*February 1, 2021*
6
+
7
+
Django 3.0.12 fixes a security issue with severity "low" in 3.0.11.
8
+
9
+
CVE-2021-3281: Potential directory-traversal via ``archive.extract()``
10
+
======================================================================
11
+
12
+
The ``django.utils.archive.extract()`` function, used by
13
+
:option:`startapp --template` and :option:`startproject --template`, allowed
14
+
directory-traversal via an archive with absolute paths or relative paths with
15
+
dot segments.
Original file line number Diff line number Diff line change
@@ -25,6 +25,7 @@ versions of the documentation contain the release notes for any later releases.
25
25
.. toctree::
26
26
:maxdepth: 1
27
27
28
+
3.0.12
28
29
3.0.11
29
30
3.0.10
30
31
3.0.9
@@ -43,6 +44,7 @@ versions of the documentation contain the release notes for any later releases.
43
44
.. toctree::
44
45
:maxdepth: 1
45
46
47
+
2.2.18
46
48
2.2.17
47
49
2.2.16
48
50
2.2.15
Original file line number Diff line number Diff line change
@@ -4,6 +4,8 @@
4
4
import tempfile
5
5
import unittest
6
6
7
+
from django.core.exceptions import SuspiciousOperation
8
+
from django.test import SimpleTestCase
7
9
from django.utils import archive
8
10
9
11
@@ -45,3 +47,22 @@ def test_extract_file_permissions(self):
45
47
# A file is readable even if permission data is missing.
46
48
filepath = os.path.join(tmpdir, 'no_permissions')
47
49
self.assertEqual(os.stat(filepath).st_mode & mask, 0o666 & ~umask)
50
+
51
+
52
+
class TestArchiveInvalid(SimpleTestCase):
53
+
def test_extract_function_traversal(self):
54
+
archives_dir = os.path.join(os.path.dirname(__file__), 'traversal_archives')
55
+
tests = [
56
+
('traversal.tar', '..'),
57
+
('traversal_absolute.tar', '/tmp/evil.py'),
58
+
]
59
+
if sys.platform == 'win32':
60
+
tests += [
61
+
('traversal_disk_win.tar', 'd:evil.py'),
62
+
('traversal_disk_win.zip', 'd:evil.py'),
63
+
]
64
+
msg = "Archive contains invalid path: '%s'"
65
+
for entry, invalid_path in tests:
66
+
with self.subTest(entry), tempfile.TemporaryDirectory() as tmpdir:
67
+
with self.assertRaisesMessage(SuspiciousOperation, msg % invalid_path):
68
+
archive.extract(os.path.join(archives_dir, entry), tmpdir)
You can’t perform that action at this time.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4