Commit 4b129ac8 authored by John-Mark Bell's avatar John-Mark Bell Committed by Tim Graham
Browse files

Fixed #26325 -- Made MultiPartParser ignore filenames that normalize to an empty string.

parent 75614f6d
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -181,10 +181,11 @@ class MultiPartParser(object):
                elif item_type == FILE:
                    # This is a file, use the handler...
                    file_name = disposition.get('filename')
                    if not file_name:
                        continue
                    if file_name:
                        file_name = force_text(file_name, encoding, errors='replace')
                        file_name = self.IE_sanitize(unescape_entities(file_name))
                    if not file_name:
                        continue

                    content_type, content_type_extra = meta_data.get('content-type', ('', {}))
                    content_type = content_type.strip()
+3 −1
Original line number Diff line number Diff line
@@ -9,4 +9,6 @@ Django 1.8.12 fixes several bugs in 1.8.11.
Bugfixes
========

* ...
* Made ``MultiPartParser`` ignore filenames that normalize to an empty string
  to fix crash in ``MemoryFileUploadHandler`` on specially crafted user input
  (:ticket:`26325`).
+3 −1
Original line number Diff line number Diff line
@@ -9,4 +9,6 @@ Django 1.9.5 fixes several bugs in 1.9.4.
Bugfixes
========

* ...
* Made ``MultiPartParser`` ignore filenames that normalize to an empty string
  to fix crash in ``MemoryFileUploadHandler`` on specially crafted user input
  (:ticket:`26325`).
+35 −0
Original line number Diff line number Diff line
@@ -179,6 +179,41 @@ class FileUploadTests(TestCase):
        response = self.client.request(**r)
        self.assertEqual(response.status_code, 200)

    def test_blank_filenames(self):
        """
        Receiving file upload when filename is blank (before and after
        sanitization) should be okay.
        """
        # The second value is normalized to an empty name by
        # MultiPartParser.IE_sanitize()
        filenames = ['', 'C:\\Windows\\']

        payload = client.FakePayload()
        for i, name in enumerate(filenames):
            payload.write('\r\n'.join([
                '--' + client.BOUNDARY,
                'Content-Disposition: form-data; name="file%s"; filename="%s"' % (i, name),
                'Content-Type: application/octet-stream',
                '',
                'You got pwnd.\r\n'
            ]))
        payload.write('\r\n--' + client.BOUNDARY + '--\r\n')

        r = {
            'CONTENT_LENGTH': len(payload),
            'CONTENT_TYPE': client.MULTIPART_CONTENT,
            'PATH_INFO': '/echo/',
            'REQUEST_METHOD': 'POST',
            'wsgi.input': payload,
        }
        response = self.client.request(**r)
        self.assertEqual(response.status_code, 200)

        # Empty filenames should be ignored
        received = json.loads(response.content.decode('utf-8'))
        for i, name in enumerate(filenames):
            self.assertIsNone(received.get('file%s' % i))

    def test_dangerous_file_names(self):
        """Uploaded file names should be sanitized before ever reaching the view."""
        # This test simulates possible directory traversal attacks by a