Skip to content
KitploitKITPLOIT
FerramentasBlog
Enviar
FerramentasBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

··Feeds·Contato·Privacidade·© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
Ferramentas/GitHubGitHub/luuanhduc/cve-2021-35042
Análise de VulnerabilidadesExploraçãoExploração de Aplicações WebAprendizado e EducaçãoSegurança de Banco de DadosLabs e Prática
GitHubluuanhduc/cve-2021-35042

CVE-2021-35042

Vulnerabilidade de injeção SQL no Django

Ver Repositório
15há 3 anosAinda não revisado

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar

CVE-2021-35042: Vulnerabilidade de injeção SQL no Django

I. Visão geral

O Django é um framework de aplicação web de código aberto, escrito em Python, construído com base no modelo MVC (Model-View-Controller). Foi originalmente desenvolvido para gerenciar sites de conteúdo de notícias pertencentes ao grupo editorial Lawrence, como um sistema de gerenciamento de conteúdo (CMS).

As versões 3.1.x a 3.1.13 e 3.2.x a 3.2.5 do Django possuem uma vulnerabilidade de injeção SQL.

A causa dessa vulnerabilidade é que a função de filtragem dos dados de entrada controlados pelo usuário no QuerySet.order_by() não é suficiente para prevenir ataques de injeção SQL. Essa vulnerabilidade pode ser explorada para permitir que um atacante realize ações não autorizadas, levando ao vazamento de dados sensíveis.

Baixar ferramenta
CVE-IDCVE-2021-35042
Severidade9.8 - CRÍTICA
CWE-IDCWE-89: Neutralização incorreta de elementos especiais usados em um comando SQL ('Injeção SQL')
Data de publicação da vulnerabilidade01/07/2021
Software afetado3.1.x < 3.1.13, 3.2.x < 3.2.5
Requer autenticaçãoNão é necessária

II. Visão geral x2

0x01. Modelo do Django

No Django, a criação de tabelas e definição de campos no banco de dados é feita declarando uma classe de modelo no arquivo models.py. Neste exemplo, declaramos uma tabela chamada Wolf e um campo chamado name.

0x02. QuerySet e Order_by() no Django

O framework ORM integrado ao Django é usado para manipular o banco de dados, e o resultado de uma consulta é um conjunto, chamado de QuerySet.

order_by(campos) Por padrão, order_by() retorna um QuerySet ordenado de acordo com a ordem especificada na opção ordering do Meta do Model. Podemos sobrescrever a condição order_by em cada consulta usando o método order_by().

Exemplo

wolves = Wolf.objects.order_by('-name', 'id')

O resultado da consulta acima será ordenado de forma decrescente pelo campo name e depois de forma crescente pelo id. O sinal negativo antes do nome do campo name indica uma ordenação decrescente.

O exemplo a seguir ordena o resultado retornado pelo campo recebido do usuário; se nenhum valor for passado, ordena pelo campo id.

Resultado

Nas versões 3.1 e 3.2, o Django permite combinar o método de consulta com o nome da tabela na consulta order_by. Essa é a principal causa dessa vulnerabilidade.

Passar um nome de tabela nos dá o mesmo resultado que passar um nome de campo normalmente.

cve202135042_wolf é o nome da tabela

Primeiro, a aplicação chama diretamente a função order_by(). O código que processa a função order_by() está definido em: django/db/models/query.py

A função order_by() realiza duas ações:

  1. Remove todas as ordenações atuais que estão sendo chamadas por order_by() e remove o parâmetro padrão passado quando order_by recebe um valor diferente.
  2. Passa os parâmetros para order_by. A função add_ordering() realiza essa etapa.
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
            

O parâmetro passado para add_ordering() é um array.

Exemplo: quando o parâmetro é passado da seguinte forma: wolves = Wolf.objects.order_by( 'name' , 'id' ) A aplicação converte isso em uma consulta SQL no banco de dados:

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

Quando recebido, a função add_ordering verifica cada elemento do array; se for uma string, ela é verificada em 5 casos:

  1. if '.' in item: Verifica se é uma consulta com um nome de coluna e se essa coluna tem um nome de tabela especificado na instrução SQL. Se sim, emite um aviso e continue.
  2. if item == '?': Se o valor do elemento for '?', o resultado da saída será ordenado aleatoriamente, continue.
  3. if item.startswith('-'): Se o item começar com '-', o resultado da consulta será ordenado DESC (decrescente).
  4. if item in self.annotations: Verifica se contém um comentário; se sim, continue.
  5. if self.extra and item in self.extra: Verifica se há uma cláusula extra; se sim, continue.

Após as 5 verificações, o parâmetro é passado para a função self.names_to_path(item.split(LOOKUP_SEP), self.model._meta) para verificar se é um nome de coluna válido. Depois, se for válido, é adicionado ao self.ordering da classe Query para processamento.

III. Análise da vulnerabilidade de injeção SQL no Django

0x31. Causa

O ORM do Django realiza a filtragem dos dados inseridos nas consultas de maneira muito rigorosa, mas a mudança no código que levou a essa injeção SQL ocorreu porque o autor assumiu que, se o nome da coluna fosse um UUID (Identificador Único Universal), a consulta order_by não poderia ser executada.

Ou seja, se os dados de entrada estivessem no formato xxx-xxx-xxx-xxx (formato UUID), a consulta não poderia ser executada.

Código antes da alteração

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

Pelo código acima, podemos ver que se o parâmetro corresponder a ? ou começar com - seguido de caracteres comuns ou ponto final, a consulta é executada.

Portanto, quando o nome da coluna é um UUID, ele se torna um valor inválido e não pode ser usado em order_by. A alteração do código de tratamento foi aceita e ficou assim: https://github.com/charettes/django/commit/513948735b799239f3ef8c89397592445e1a0cd5

Ele passou a usar a função self.name_to_path para validar a entrada.

Mas, após verificar se há . no item, ele considera que é uma consulta com nome de tabela; o comando continue é executado, ignorando diretamente o uso da função self.name_to_path para verificar a validade dos dados.

O código que trata o ponto na função get_order_by é: 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

A função self.quote_name_unless_alias trata o nome da tabela, filtra nomes de tabela válidos e ignora a filtragem do nome da coluna; portanto, podemos inserir um comando de injeção SQL.

0x32. Correção

Na versão atual do Django 4.0, a consulta por nome de tabela usando . foi removida e não é mais suportada. A correção foi aplicada nas versões 3.1 e 3.2. As versões 3.2.x a 3.2.4 e 3.1.x a 3.1.12 são afetadas. 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…

A modificação é simples: a verificação dos dados via Regex antiga foi reintroduzida.

0x33. Mitigação

Atualizar o Django para uma versão não afetada.

IV. Demonstração

0x41. Ambiente

Docker & Docker-compose

0x42. Configuração

  1. git clone https://github.com/LUUANHDUC/CVE-2021-35042.git
  2. Execute ./setup.sh para a configuração inicial
  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. Acesse http://localhost:8000/load_example_data para carregar dados de exemplo:
  7. Caminho com o parâmetro vulnerável: http://localhost:8000/wolves/ http://localhost:8000/wolves/?order_by=name

Tela após a instalação

0x43. Exploração

Condição: Para explorar, precisamos saber o nome da tabela de alguma forma :))

Ao injetar um comando, precisamos saber o nome da tabela para conseguir executar o SQLi.

Quando o nome da tabela está errado

Quando o nome da tabela está correto, a consulta orderby é executada normalmente.

A instrução neste momento se torna SELECT "cve202135042_wolf"."id", "cve202135042_wolf"."name" FROM "cve202135042_wolf" ORDER BY ("cve202135042_wolf"."name") ASC

Neste ponto, podemos encerrar a instrução order_by anterior e inserir um comando SQL para exploração.

SELECT "cve202135042_wolf"."id", "cve202135042_wolf"."name" FROM "cve202135042_wolf" ORDER BY ("cve202135042_wolf"."name"); SELECT * from cve202135042_wolf where id =1; --) ASC

V. Referências

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