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 — Django SQL injection vulnerability | Kitploit
Tools/GitHubGitHub/luuanhduc/cve-2021-35042
Vulnerability AnalysisExploitationWeb Application ExploitationLearning & EducationDatabase SecurityLabs & Practice
GitHubluuanhduc/cve-2021-35042

CVE-2021-35042

Django SQL injection vulnerability

Repository anzeigen
1vor 3 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-Sicherheitslücke

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 zur Verwaltung von Nachrichten-Webseiten entwickelt, die dem Verlagskonzern Lawrence gehören, als Content-Management-System (CMS).

Django-Versionen 3.1.x bis 3.1.13 und 3.2.x bis 3.2.5 weisen eine SQL-Injection-Sicherheitslücke auf.

Die Ursache dieser Sicherheitslücke ist, dass die Filterfunktion für vom Benutzer kontrollierte Eingabedaten in QuerySet.order_by() nicht ausreicht, um SQL-Injection-Angriffe zu verhindern. Diese Sicherheitslücke kann ausgenutzt werden, um unbefugte Aktionen durchzuführen, die zur Offenlegung sensibler Daten führen.

CVE - IDCVE-2021-35042
Severity9.8 - KRITISCH
CWE - IDCWE-89: Unzureichende Neutralisierung von speziellen Elementen in einem SQL-Befehl ('SQL-Injection')
Vulnerability Publication Date1.7.2021
Affected Software3.1.x < 3.1.13, 3.2.x < 3.2.5
Require AuthenticationNicht erforderlich

II. Übersicht x2

0x01. Djangos Modell

In Django werden das Erstellen von Tabellen und das Definieren von Feldern in der Datenbank durch Deklarieren einer Modellklasse in der Datei models.py durchgeführt. 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 für Datenbankoperationen verwendet, und das Ergebnis einer Abfrage ist eine Sammlung, die als QuerySet bezeichnet wird.

order_by(fields) Standardmäßig gibt order_by() ein QuerySet zurück, das nach der im ordering-Attribut des Meta-Modells festgelegten Reihenfolge sortiert 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 das Kombinieren von Abfragemethoden mit Tabellennamen in der order_by-Abfrage. Dies ist auch die Hauptursache für diese Sicherheitslücke.

Die Übergabe eines Tabellennamens liefert das gleiche Ergebnis wie die Übergabe eines Feldnamens.

cve202135042_wolf ist der Tabellenname

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

Die Funktion order_by() führt zwei Aufgaben aus:

  1. Löscht alle aktuellen Methoden, die durch order_by() aufgerufen werden, und entfernt den übergebenen Standardparameter, wenn order_by einen anderen Wert erhält.
  2. Übergibt den Parameter an order_by. Die Funktion add_ordering() führt dies aus.
root@kitploit:~
def add_ordering(self, *ordering):
        """
        Add items from the 'ordering' sequence to the query's "order by"
        clause. These items are either field names (not column names) --
        possibly with a direction prefix ('-' or '?') -- or OrderBy
        expressions.

        If 'ordering' is empty, clear all ordering from the query.
        """
        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() validates the lookup. A descriptive
                # FieldError will be raise if it's not.
                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 wird die Anwendung dies in die folgende Datenbankabfrage umwandeln:

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

Wenn die Funktion add_ordering aufgerufen wird, überprüft sie jedes Element im Array; wenn es sich um einen String handelt, wird es auf die folgenden 5 Fälle geprüft:

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

Nach diesen fünf Prüfungen wird der Parameter 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 gültig, werden sie zur self.ordering der Query-Klasse hinzugefügt, um weiterverarbeitet zu werden.

III. Analyse der SQL-Injection-Sicherheitslücke in Django

0x31. Ursache

Djangos ORM filtert die in die Abfrage eingegebenen Daten sehr streng, aber die diesmalige Codeänderung führte zu SQL-Injection, weil die Autoren die Annahme trafen, dass wenn der Spaltenname eine UUID (Universal Unique Identifier) -Spalte ist, die order_by-Abfrage nicht ausgeführt werden kann.

Das heißt, wenn die eingegebenen Daten xxx-xxx-xxx-xxx (UUID-Format) sind, kann die Abfrage nicht ausgeführt werden.

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 ist ersichtlich, dass die Abfrage nur dann ausgeführt wird, wenn der Parameter mit ? übereinstimmt oder mit - beginnt und von normalen Zeichen oder einem Punkt . gefolgt wird.

Daher ist ein UUID-Spaltenname ein ungültiger Wert und kann nicht in order_by verwendet werden.

Die Änderung dieses Verarbeitungscodes wurde akzeptiert; sie wurde wie folgt geändert: https://github.com/charettes/django/commit/513948735b799239f3ef8c89397592445e1a0cd5

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

Aber nach der Prüfung, ob ein Punkt . im Element vorhanden ist, wird es als eine Abfrage mit Tabellennamen betrachtet, und der Befehl continue wird ausgeführt, was dazu führt, dass die Verwendung der Funktion self.name_to_path zur Validierung der Daten übersprungen wird.

Der Code, der den Punkt 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 Tabellennamen, filtert gültige Tabellennamen und überspringt die Filterung von Spaltennamen, sodass wir eine SQL-Injection-Anweisung einfügen können.

0x32. Patch

In der aktuellen Django-Version 4.0 wurde die Abfrage mit Tabellennamen durch einen Punkt entfernt und wird nicht mehr unterstützt. Der Patch wurde für die Versionen 3.1 und 3.2 veröffentlicht. Die Versionen 3.2 bis 3.2.4 und 3.1 bis 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 Korrektur war sehr einfach; die alte Regex-Datenprüfung wurde wieder eingeführt.

0x33. Abhilfe

Aktualisieren Sie Django auf eine nicht betroffene Version.

IV. Demo

0x41. Umgebung

Docker & Docker-compose

0x42. Einrichtung

  1. git clone https://github.com/LUUANHDUC/CVE-2021-35042.git
  2. Führen Sie ./setup.sh für die erste Einrichtung 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. Der Pfad mit dem verwundbaren Parameter: http://localhost:8000/wolves/ http://localhost:8000/wolves/?order_by=name

Bildschirm nach der Installation:

0x43. Ausnutzung

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

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

Bei falschem Tabellennamen

Bei korrektem Tabellennamen wird die order_by-Abfrage normal ausgeführt.

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

An diesem Punkt 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