1
0
mirror of https://github.com/django/django.git synced 2025-07-05 10:19:20 +00:00

[3.2.x] Fixed CVE-2023-41164 -- Fixed potential DoS in django.utils.encoding.uri_to_iri().

Thanks MProgrammer (https://hackerone.com/mprogrammer) for the report.

Co-authored-by: nessita <124304+nessita@users.noreply.github.com>
This commit is contained in:
Mariusz Felisiak 2023-08-22 08:53:03 +02:00
parent 73350a6369
commit 6f030b1149
3 changed files with 30 additions and 4 deletions

View File

@ -229,6 +229,7 @@ def repercent_broken_unicode(path):
repercent-encode any octet produced that is not part of a strictly legal repercent-encode any octet produced that is not part of a strictly legal
UTF-8 octet sequence. UTF-8 octet sequence.
""" """
changed_parts = []
while True: while True:
try: try:
path.decode() path.decode()
@ -236,9 +237,10 @@ def repercent_broken_unicode(path):
# CVE-2019-14235: A recursion shouldn't be used since the exception # CVE-2019-14235: A recursion shouldn't be used since the exception
# handling uses massive amounts of memory # handling uses massive amounts of memory
repercent = quote(path[e.start:e.end], safe=b"/#%[]=:;$&()+,!?*@'~") repercent = quote(path[e.start:e.end], safe=b"/#%[]=:;$&()+,!?*@'~")
path = path[:e.start] + repercent.encode() + path[e.end:] changed_parts.append(path[:e.start] + repercent.encode())
path = path[e.end:]
else: else:
return path return b"".join(changed_parts) + path
def filepath_to_uri(path): def filepath_to_uri(path):

View File

@ -6,4 +6,9 @@ Django 3.2.21 release notes
Django 3.2.21 fixes a security issue with severity "moderate" in 3.2.20. Django 3.2.21 fixes a security issue with severity "moderate" in 3.2.20.
... CVE-2023-41164: Potential denial of service vulnerability in ``django.utils.encoding.uri_to_iri()``
===================================================================================================
``django.utils.encoding.uri_to_iri()`` was subject to potential denial of
service attack via certain inputs with a very large number of Unicode
characters.

View File

@ -1,9 +1,10 @@
import datetime import datetime
import inspect
import sys import sys
import unittest import unittest
from pathlib import Path from pathlib import Path
from unittest import mock from unittest import mock
from urllib.parse import quote_plus from urllib.parse import quote, quote_plus
from django.test import SimpleTestCase from django.test import SimpleTestCase
from django.utils.encoding import ( from django.utils.encoding import (
@ -101,6 +102,24 @@ class TestEncodingUtils(SimpleTestCase):
except RecursionError: except RecursionError:
self.fail('Unexpected RecursionError raised.') self.fail('Unexpected RecursionError raised.')
def test_repercent_broken_unicode_small_fragments(self):
data = b"test\xfctest\xfctest\xfc"
decoded_paths = []
def mock_quote(*args, **kwargs):
# The second frame is the call to repercent_broken_unicode().
decoded_paths.append(inspect.currentframe().f_back.f_locals["path"])
return quote(*args, **kwargs)
with mock.patch("django.utils.encoding.quote", mock_quote):
self.assertEqual(repercent_broken_unicode(data), b"test%FCtest%FCtest%FC")
# decode() is called on smaller fragment of the path each time.
self.assertEqual(
decoded_paths,
[b"test\xfctest\xfctest\xfc", b"test\xfctest\xfc", b"test\xfc"],
)
class TestRFC3987IEncodingUtils(unittest.TestCase): class TestRFC3987IEncodingUtils(unittest.TestCase):