Skip to content
KitploitKITPLOIT
StrumentiBlog
Invia
StrumentiBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
CVE-2021-35042 — Vulnerabilità di SQL injection in Django | Kitploit
Strumenti/GitHubGitHub/luuanhduc/cve-2021-35042
Analisi delle VulnerabilitàExploitSfruttamento di Applicazioni WebApprendimento e FormazioneSicurezza dei DatabaseLab e Pratica
GitHubluuanhduc/cve-2021-35042

CVE-2021-35042

Vulnerabilità di SQL injection in Django

Vedi Repository
13 anni faNon ancora revisionato

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi

CVE-2021-35042: Vulnerabilità di SQL injection in Django

I. Panoramica

Django è un Web Application Framework open source, scritto in Python, costruito secondo il modello MVC (Model - View - Controller). Inizialmente è stato creato per gestire i siti web di contenuti di notizie di proprietà del gruppo editoriale Lawrence, software CMS (Content Management System).

Le versioni di Django 3.1.x -> 3.1.13 e 3.2.x -> 3.2.5 presentano una vulnerabilità di SQL injection.

La causa di questa vulnerabilità è che la funzione di filtro dei dati di input controllati dall'utente in QuerySet.order_by() non è sufficiente a prevenire gli attacchi di SQL injection. Questa vulnerabilità può essere sfruttata per consentire a un attaccante di compiere azioni non autorizzate, portando alla divulgazione di dati sensibili.

CVE - IDCVE-2021-35042
Severità9.8 - CRITICA
CWE - IDCWE-89: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
Data di pubblicazione della vulnerabilità1/7/2021
Software interessato3.1.x < 3.1.13, 3.2.x < 3.2.5
Autenticazione richiestaNon richiesta

II. Panoramica x2

0x01. Il modello di Django

In Django, la creazione delle tabelle e la definizione dei campi nel database viene eseguita dichiarando una classe model nel file models.py. In questo esempio, dichiariamo una tabella chiamata Wolf e un campo chiamato name.

0x02. QuerySet e Order_by() in Django

Il framework ORM integrato in Django viene utilizzato per interagire con il database e il risultato della query è un insieme, chiamato QuerySet.

order_by(fields) Per impostazione predefinita, order_by() restituisce un QuerySet ordinato in base all'ordine specificato nell'opzione ordering nel Meta del Model. Possiamo sovrascrivere la condizione order_by in ogni query utilizzando il metodo order_by().

Esempio

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

Il risultato della query precedente verrà ordinato in modo decrescente per il campo name, poi in modo crescente per id. Il segno meno davanti al nome del campo name indica che il risultato è ordinato in modo decrescente.

L'esempio seguente ordina i risultati in base al campo ricevuto dall'utente; se non viene passato alcun valore, ordina per il campo id.

Risultato

Nelle versioni 3.1 e 3.2, Django consente di combinare il metodo di query con il nome della tabella nella query order_by. Questa è anche la causa principale di questa vulnerabilità.

Passare un nome di tabella ci dà lo stesso risultato del passaggio del nome di un campo normalmente

cve202135042_wolf è il nome della tabella

Innanzitutto l'applicazione chiama direttamente la funzione order_by(); il codice che gestisce la funzione order _by() è definito in: django/db/models/query.py

La funzione order_by() esegue 2 operazioni

  1. Rimuove tutti i metodi attualmente chiamati da order_by() e rimuove il parametro predefinito passato quando order_by riceve un valore diverso.
  1. Passa i parametri a order_by. È la funzione add_ordering() a eseguire questa operazione.
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
            

I parametri passati a add_ordering() sono un array.

Esempio: quando vengono passati i seguenti parametri: wolves = Wolf.objects.order_by( 'name' , 'id' ) In tal caso, l'applicazione li convertirà nella seguente query nel database:

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

Quando vengono passati, la funzione add_ordering controlla ogni elemento dell'array; se si tratta di una string, vengono verificati i seguenti 5 casi:

  1. if '.' in item: Controlla se si tratta di una query con un nome di colonna e se quella colonna ha un nome di tabella specificato nell'istruzione SQL. Se presente, viene emesso un avviso e continue.
  2. if item == '?': Se il valore dell'elemento è il carattere '?', il risultato dell'output viene ordinato casualmente, continue.
  3. if item.startswith('-'): Se l'item inizia con il carattere '-', il risultato della query viene ordinato in modo DESC (decrescente).
  4. if item in self.annotations: Controlla se contiene un commento; se sì, continue.
  5. if self.extra and item in self.extra: Determina se sono presenti extra e, se sì, continue.

Dopo i 5 controlli, il parametro viene passato alla funzione self.names_to_path(item.split(LOOKUP_SEP), self.model._meta) per verificare ulteriormente se si tratta di un nome di colonna valido; se valido, viene aggiunto a self.ordering della classe Query per l'elaborazione successiva.

III. Analisi della vulnerabilità di SQL injection in Django

0x31. Causa

L'ORM di Django filtra i dati inseriti nella query in modo molto rigoroso, ma la modifica del codice sorgente che ha portato alla SQL injection è dovuta al fatto che l'autore ha ipotizzato che se il nome di una colonna è un UUID (Universal Unique Identifer), la query order_by non potrebbe essere eseguita.

Ciò significa che se i dati inseriti sono xxx-xxx-xxx-xxx (formato UUID), la query non può essere eseguita.

Codice prima della modifica

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

Dalla porzione di codice sopra, possiamo vedere che se il parametro corrisponde a ? oppure inizia con - ed è seguito da caratteri normali o dal punto ., la query viene eseguita.

Pertanto, quando il nome di una colonna è un UUID, esso è un valore non valido e non può essere inserito in order_by. La modifica del codice di questa parte è stata accettata; è stata modificata come segue: https://github.com/charettes/django/commit/513948735b799239f3ef8c89397592445e1a0cd5

È stata utilizzata la funzione self.name_to_path per validare i dati di input.

Ma dopo il controllo, se nell'item è presente ., viene considerata una query con nome di tabella; l'istruzione continue viene eseguita, portando a saltare direttamente l'uso della funzione self.name_to_path per verificare la validità dei dati.

Il codice che gestisce il punto . nella funzione get_order_by è il seguente 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

La funzione self.quote_name_unless_alias gestisce il nome della tabella, filtra i nomi di tabella validi e salta il filtraggio del nome della colonna, quindi possiamo inserire un'istruzione SQL injection.

0x32. Patch

Nella versione attuale Django 4.0, la query per nome di tabella tramite il punto . è stata rimossa e non è più supportata; la patch è stata rilasciata per le versioni 3.1 e 3.2. Le versioni 3.2 -> 3.2.4 e 3.1 -> 3.1.12 sono interessate. 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…

La modifica è molto semplice: il controllo dei dati tramite la vecchia ReGex è stato ripristinato

0x33. Rimedio

Aggiornare Django a una versione non vulnerabile.

IV. Demo

0x41. Ambiente

Docker & Docker-compose

0x42. Setup

  1. git clone https://github.com/LUUANHDUC/CVE-2021-35042.git
  2. Eseguire ./setup.sh per la configurazione iniziale
  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. Accedere a http://localhost:8000/load_example_data per caricare i dati di esempio:
  7. Il percorso contenente il parametro vulnerabile: http://localhost:8000/wolves/ http://localhost:8000/wolves/?order_by=name

Schermata al termine dell'installazione

0x43. Sfruttamento

Condizione: Per poter sfruttare la vulnerabilità, dobbiamo assolutamente conoscere il nome della tabella in qualche modo :))

Quando si inietta l'istruzione, dobbiamo conoscere il nome della tabella per poter eseguire l'istruzione SQLi.

Quando si inserisce un nome di tabella errato

Quando si inserisce il nome di tabella corretto, la query orderby viene eseguita normalmente.

L'istruzione ora sarà: SELECT "cve202135042_wolf"."id", "cve202135042_wolf"."name" FROM "cve202135042_wolf" ORDER BY ("cve202135042_wolf"."name") ASC

Ora possiamo terminare l'istruzione order_by precedente e inserire un'istruzione SQL per sfruttare la vulnerabilità.

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

V. Riferimenti

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

Scarica lo strumento