Skip to content
KitploitKITPLOIT
ToolsBlog
Einreichen
ToolsBlog
Einreichen

Hacking-, PenTest- und Cybersicherheits-Tools für Ihr Sicherheitsarsenal!

Kitploit ist ein Verzeichnis von Hacking-, Cybersicherheits- und Pentesting-Tools. Entdecken Sie die neuesten Projekt-Updates, um Schwachstellen zu finden, Systeme zu analysieren, Tests zu automatisieren und Ihre Sicherheit zu stärken.

··Feeds·Kontakt·Datenschutz·© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
CVE-2021-35042 — Eine grundlegende Analyse zu CVE-2021-35942. SQL-Injection in Django. | Kitploit
Tools/GitHubGitHub/zer0qs/cve-2021-35042
SchwachstellenanalyseExploitationWebsicherheitPapers & ForschungLernen & Bildung
GitHubzer0qs/cve-2021-35042

CVE-2021-35042

Eine grundlegende Analyse zu CVE-2021-35942. SQL-Injection in Django.

Repository anzeigen
2vor 4 JahrenNoch nicht geprüft

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen

CVE-2021-35042: Django SQL-Injection-Schwachstelle

I. Überblick

Django ist ein Open-Source-Webanwendungs-Framework, das in Python geschrieben und nach dem MVC-Modell (Model - View - Controller) aufgebaut ist. Ursprünglich wurde es entwickelt, um Nachrichteninhalts-Websites der Lawrence-Verlagsgruppe zu verwalten, eine CMS-Software (Content Management System).

In Django Version 3.1.x -> 3.1.13 und Version 3.2.x -> 3.2.5 existiert eine SQL-Injection-Schwachstelle.

Die Ursache für diese Schwachstelle liegt darin, dass die Funktion zur Filterung von benutzergesteuerten Eingabedaten bei QuerySet.order_by() nicht ausreicht, um SQL-Injection-Angriffe zu verhindern. Diese Schwachstelle kann ausgenutzt werden, um einem Angreifer unbefugte Aktionen zu ermöglichen, die zur Offenlegung sensibler Daten führen.

CVE - IDCVE-2021-35042
Schweregrad9.8 - KRITISCH
CWE - IDCWE-89: Fehlerhafte Neutralisierung spezieller Elemente, die in einem SQL-Befehl verwendet werden ('SQL Injection')
Veröffentlichungsdatum der Schwachstelle1.7.2021
Betroffene Software3.1.x < 3.1.13, 3.2.x < 3.2.5
Authentifizierung erforderlichNicht erforderlich

II. Überblick x2

0x01. Djangos Model

In Django erfolgt das Erstellen von Tabellen und das Definieren von Feldern in der Datenbank durch die Deklaration einer Model-Klasse in der Datei models.py. In diesem Beispiel deklarieren wir eine Tabelle mit dem Namen Wolf und ein Feld mit dem Namen name.

0x02. QuerySet und Order_by() in Django

Das in Django integrierte ORM-Framework wird verwendet, um mit der Datenbank zu arbeiten, und das Ergebnis der Abfrage ist eine Sammlung, diese Sammlung ist ein QuerySet.

order_by(fields) Standardmäßig gibt order_by() ein QuerySet zurück, das in einer Reihenfolge sortiert ist, die in der Option ordering im Meta des Models festgelegt ist. Wir können die order_by-Bedingung in jeder Abfrage überschreiben, indem wir die Methode order_by() verwenden.

Beispiel

wolves = Wolf.objects.order_by('-name', 'id')

Das Ergebnis der obigen Abfrage wird absteigend nach dem Feld name und dann aufsteigend nach id sortiert. Das Minuszeichen vor dem Feldnamen name zeigt an, dass das Ergebnis absteigend sortiert wird.

Das folgende Beispiel sortiert das zurückgegebene Ergebnis nach dem vom Benutzer empfangenen Feld; wenn kein Wert übergeben wird, wird nach dem Feld id sortiert.

Ergebnis

In den Versionen 3.1 und 3.2 erlaubt Django die Kombination der Abfragemethode mit dem Tabellennamen in der order_by-Abfrage. Dies ist auch die Hauptursache für diese Schwachstelle.

Das Übergeben eines Tabellennamens liefert uns dasselbe Ergebnis wie das Übergeben eines Feldnamens auf normale Weise

cve202135042_wolf ist der Tabellenname

Zuerst ruft die Anwendung direkt die Funktion order_by() auf; der Code, der die Funktion order_by() verarbeitet, ist definiert unter: django/db/models/query.py

Die Funktion order_by() führt zwei Aufgaben aus

  1. Löscht alle aktuellen Methoden, die von order_by() aufgerufen werden, und löscht den Standardparameter, der übergeben wird, wenn order_by einen anderen Wert erhält.
  1. Übergibt den Parameter an order_by. Die Funktion add_ordering() führt diese Aufgabe aus.
root@kitploit:~
def add_ordering(self, *ordering):
        """
        Fügt Elemente aus der 'ordering'-Sequenz zur "order by"-Klausel
        der Abfrage hinzu. Diese Elemente sind entweder Feldnamen (nicht
        Spaltennamen) -- möglicherweise mit einem Richtungspräfix ('-' oder
        '?') -- oder OrderBy-Ausdrücke.

        Wenn 'ordering' leer ist, wird die gesamte Sortierung aus der Abfrage
        entfernt.
        """
        errors = []
        for item in ordering:
            if isinstance(item, str):
                if '.' in item:
                    warnings.warn(
                        'Passing column raw column aliases to order_by() is '
                        'deprecated. Wrap %r in a RawSQL expression before '
                        'passing it to order_by().' % item,
                        category=RemovedInDjango40Warning,
                        stacklevel=3,
                    )
                    continue
                if item == '?':
                    continue
                if item.startswith('-'):
                    item = item[1:]
                if item in self.annotations:
                    continue
                if self.extra and item in self.extra:
                    continue
                # names_to_path() validiert die Suche. Ein beschreibender
                # FieldError wird ausgelöst, wenn dies nicht der Fall ist.
                self.names_to_path(item.split(LOOKUP_SEP), self.model._meta)
            elif not hasattr(item, 'resolve_expression'):
                errors.append(item)
            if getattr(item, 'contains_aggregate', False):
                raise FieldError(
                    'Using an aggregate in order_by() without also including '
                    'it in annotate() is not allowed: %s' % item
                )
        if errors:
            raise FieldError('Invalid order_by arguments: %s' % errors)
        if ordering:
            self.order_by += ordering
        else:
            self.default_ordering = False
            

Der an add_ordering() übergebene Parameter ist ein Array.

Beispiel, wenn der Parameter wie folgt übergeben wird: wolves = Wolf.objects.order_by( 'name' , 'id' ) Dann konvertiert die Anwendung dies in die folgende Datenbankabfrage:

root@kitploit:~
SELECT "cve202135042_wolf"."id", "cve202135042_wolf"."name" FROM "cve202135042_wolf" ORDER BY "cve202135042_wolf"."name" ASC, "cve202135042_wolf"."id" ASC

Wenn übergeben, führt die Funktion add_ordering eine Prüfung jedes Elements im Array durch; wenn es sich um einen string handelt, wird es in den folgenden 5 Fällen geprüft:

  1. if '.' in item: Es prüft, ob es sich um eine Abfrage mit einem Spaltennamen handelt und ob diese Spalte einen Tabellennamen hat, der in der SQL-Anweisung angegeben ist. Wenn ja, wird eine Warnung ausgegeben und continue ausgeführt.
  2. if item == '?': Wenn der Wert des Elements das Zeichen '?' ist, wird das Ausgabeergebnis zufällig sortiert, continue.
  3. if item.startswith('-'): Wenn das Element mit dem Zeichen '-' beginnt, wird das Ergebnis der Abfrage DESC (absteigend) sortiert.
  4. if item in self.annotations: Es prüft, ob ein Kommentar enthalten ist; wenn ja, continue.
  5. if self.extra and item in self.extra: Bestimmt, ob eine Ergänzung hinzugefügt wird, und wenn ja, continue.

Nach den 5 Prüfungen wird der Parameter weiterhin an die Funktion self.names_to_path(item.split(LOOKUP_SEP), self.model._meta) übergeben, um weiter zu prüfen, ob es sich um einen gültigen Spaltennamen handelt. Wenn er gültig ist, werden sie zur weiteren Verarbeitung zu self.ordering der Klasse Query hinzugefügt.

III. Analyse der SQL-Injection-Schwachstelle in Django

0x31. Ursache

Djangos ORM filtert die in die Abfrage eingegebenen Daten sehr streng, aber die diesmalige Änderung des Quellcodes, die zu SQL-Injection führt, liegt daran, dass der Autor die Hypothese aufgestellt hat, dass, wenn der Spaltenname eine UUID (Universal Unique Identifier) -Spalte ist, die order_by-Abfrage nicht ausgeführt werden kann.

Das bedeutet, wenn die eingegebenen Daten xxx-xxx-xxx-xxx (das Format einer UUID) sind, kann die Abfrage nicht ausgeführt werden.

Der Code vor der Änderung

root@kitploit:~
# django/db/models/sql/constants.py 
ORDER_PATTERN  =  _lazy_re_compile ( r '\?|[-+]?[.\w]+$' )

# django/db/models/sql/query.py 
def  add_ordering ( self ,  * ordering ): 
        errors  =  [] 
        for  item  in  ordering : 
            if  isinstance ( item ,  str )  and  ORDER_PATTERN . match ( item ): 
                if  '.'  in  item : 
                    warnings . warn ( 
                        'Passing column raw column aliases to order_by() is ' 
                        'deprecated. Wrap %r in a RawSQL expression before '
                        'passing it to order_by().'  %  item , 
                        category = RemovedInDjango40Warning , 
                        stacklevel = 3 , 
                    ) 
            elif  not  hasattr ( item ,  'resolve_expression' ): 
                errors . append ( item ) 
            if  getattr ( item ,  'contains_aggregate' ,  False ): 
                raise  FieldError ( 
                    'Using an aggregate in order_by() without also including ' 
                    'it in annotate() is not allowed: %s ' %  item 
                ) 
        if  errors : 
            raise  FieldError ( 'Invalid order_by arguments: %s '  %  errors ) 
        if  ordering : 
            self . order_by  +=  ordering 
        else : 
            self . default_ordering  =  False

Aus dem obigen Code können wir ersehen, dass die Abfrage nur ausgeführt wird, wenn der Parameter mit ? übereinstimmt oder mit - beginnt und danach normale Zeichen oder ein . folgen.

Daher ist ein UUID-Spaltenname ein ungültiger Wert und kann nicht in order_by eingefügt werden. Die Änderung des Codes für diese Verarbeitung wurde akzeptiert und wie folgt geändert: https://github.com/charettes/django/commit/513948735b799239f3ef8c89397592445e1a0cd5

Es verwendet die Funktion self.name_to_path, um die Eingabedaten zu validieren.

Aber nach der Prüfung, ob . im Element enthalten ist, wird es als eine Abfrage mit einem Tabellennamen betrachtet, der Befehl continue wird ausgeführt, was dazu führt, dass die Verwendung der Funktion self.name_to_path zur Überprüfung der Gültigkeit der Daten direkt übersprungen wird.

Der Code, der das Zeichen . in der Funktion get_order_by verarbeitet, ist wie folgt: django/db/models/sql/compiler.py

root@kitploit:~
if  '.'  in  field : 
    table ,  col  =  col . split ( '.' ,  1 ) 
    order_by . append (( 
            OrderBy ( 
                RawSQL ( ' %s . %s '  %  ( 
                self . quote_name_unless_alias ( table ),  col ),  [ ]), 
                descending = descending 
            ),  False )) 
    continue

Die Funktion self.quote_name_unless_alias verarbeitet den Tabellennamen, filtert gültige Tabellennamen und überspringt die Filterung des Spaltennamens, sodass wir eine SQL-Injection-Anweisung einfügen können.

0x32. Patch

In der aktuellen Django-Version 4.0 wurde die Abfrage nach Tabellennamen mit dem Zeichen . entfernt und wird nicht mehr unterstützt; der Patch wurde für die Versionen 3.1 und 3.2 bereitgestellt. Die Versionen 3.2 -> 3.2.4 und 3.1 -> 3.1.12 sind betroffen. 3.2.x Fixed CVE-2021-35042 -- Prevented SQL injection in QuerySet.o…

3.1.x Fixed CVE-2021-35042 -- Prevented SQL injection in QuerySet.o…

Die Änderung ist sehr einfach; die alte ReGex-Datenprüfung wurde wiederhergestellt.

0x33. Behebung

Aktualisieren Sie Django auf eine nicht betroffene Version.

IV. Demo

0x41. Umgebung

Docker & Docker-compose

0x42. Setup

  1. git clone https://github.com/WynSon/CVE-2021-35042.git
  2. Führen Sie ./setup.sh für die Ersteinrichtung aus
  3. sudo docker-compose up --build
  4. sudo docker exec -it cve-2021-35042_web_1 python manage.py makemigrations cve202135042
  5. sudo docker exec -it cve-2021-35042_web_1 python manage.py migrate
  6. Rufen Sie http://localhost:8000/load_example_data auf, um Beispieldaten zu laden:
  7. Pfad mit dem verwundbaren Parameter: http://localhost:8000/wolves/ http://localhost:8000/wolves/?order_by=name

Bildschirm nach Abschluss der Installation

0x43. Ausnutzung

Bedingung: Um die Schwachstelle ausnutzen zu können, müssen wir den Tabellennamen auf irgendeine Weise kennen :))

Beim Injizieren der Anweisung müssen wir den Tabellennamen kennen, um die SQLi-Anweisung ausführen zu können.

Bei Eingabe eines falschen Tabellennamens

Bei Eingabe des korrekten Tabellennamens wird die orderby-Abfrage normal ausgeführt.

Die Anweisung lautet dann SELECT "cve202135042_wolf"."id", "cve202135042_wolf"."name" FROM "cve202135042_wolf" ORDER BY ("cve202135042_wolf"."name") ASC

Zu diesem Zeitpunkt können wir die vorherige order_by-Anweisung beenden und eine SQL-Anweisung zur Ausnutzung einfügen.

SELECT "cve202135042_wolf"."id", "cve202135042_wolf"."name" FROM "cve202135042_wolf" ORDER BY ("cve202135042_wolf"."name"); SELECT * from cve202135042_wolf where id =1; --) ASC

V. Referenzen

https://www.djangoproject.com/weblog/2021/jul/01/security-releases/ https://xz.aliyun.com/t/9834 https://www.bugxss.com/vulnerability-report/3095.html https://blankheart.top/2022/04/07/cve-2021-35042/ https://itcn.blog/p/1648921763575859.html https://github.com/YouGina/CVE-2021-35042

Tool herunterladen