Vulnerabilità fantastiche e dove trovarle (parte 1) - Scripting cross-site con errori del modulo Django

Vulnerabilità di scripting XSS

Perché Cross-Site Scripting (XSS) è ancora la vulnerabilità Web più comune? La teoria dell'identificazione di XSS è piuttosto semplice, ci sono molti strumenti di analisi statica creati per rilevarlo e tuttavia ci sono così tante vulnerabilità da scoprire. Quindi, cosa dà?

Bene, uno dei motivi è che i metodi tradizionali di analisi del programma spesso non riescono a identificare l'intento di un determinato codice. Ad esempio, uno strumento potrebbe avere difficoltà a capire quali oggetti nel programma potrebbero contenere l'input dell'utente.

Nel mio precedente post ho descritto come abbiamo affrontato questo problema costruendo un sistema che apprende le specifiche di sicurezza da migliaia di progetti Open Source e li utilizza per trovare vulnerabilità reali. Ho anche promesso di condividere alcuni esempi interessanti di ciò che ha appreso.

Ho deciso di iniziare con una fonte interessante e piuttosto inaspettata di possibili problemi nei progetti che utilizzano Django. Questo post è una guida per identificare e sfruttare le vulnerabilità XSS utilizzando errori di convalida nei moduli Django. Ecco un vero esempio: https://github.com/mozilla/pontoon/pull/1175.

Facciamo un salto diretto e iniziamo con un piccolo test. Quante volte hai scritto / visto codice simile al seguente frammento?

Che dire di questo?

O questo?

Tutti sono esempi diffusi di come di solito fai sapere all'utente che l'input fornito non è valido, giusto? L'input viene preso dai parametri della richiesta HTTP e chiaramente smascherato in un oggetto MyForm. Se uno dei campi contiene input non validi (ad es. Qualcuno ha inserito la stringa "foobar" in un campo numerico), viene restituita una pagina di 400 richieste errate con una descrizione dell'errore. La differenza tra i frammenti è il formato dell'errore restituito: un elenco HTML, testo semplice o JSON.

Ora una domanda da un milione di dollari: quale di questi frammenti renderà XSSable la tua app Web?

Per rispondere, esaminiamo l'API dei moduli Django da due punti di vista:

  1. L'aggressore è in grado di inserire input dannosi nella pagina web visualizzata nel browser dell'utente?
  2. Questo input dannoso verrà sempre salvato correttamente prima che venga restituito all'utente?

Secondo la documentazione di Django, il modo per creare messaggi di errore dinamici per errori di convalida sul campo è quello di sollevare un'eccezione django.core.exceptions.ValidationError con il messaggio corrispondente. Tale eccezione generata da una qualsiasi delle funzioni di convalida del modulo (ad esempio i metodi clean () e clean_ () della classe django.forms.BaseForm) causerà la memorizzazione del messaggio nel dizionario degli errori del modulo (django .forms.utils.ErrorDict) e in seguito eventualmente mostrato all'utente.

Un modo per sfruttare tale eccezione è utilizzare alcuni dei campi modulo incorporati che riflettono convenientemente l'input errato nel messaggio di eccezione. Ho provato tutti i tipi di campi del modulo Django elencati qui e ho ottenuto il seguente elenco: ChoiceField, TypedChoiceField, MultipleChoiceField, FilePathField. Ognuno di questi genera un messaggio di errore del tipo "Seleziona una scelta valida.% (Valore) s non è una delle scelte disponibili.", Dove valore è l'input errato. per la vittoria .

La seconda opzione è sfruttare campi personalizzati e / o procedure di validazione. Ad esempio, considera il seguente frammento (preso da un progetto reale e modificato per brevità):

Qui un buon payload sarebbe qualcosa di simile a foo. .

Sì, hai ragione, le eccezioni ValidationError da sole non ci concederanno un XSS. Per una corretta vulnerabilità abbiamo bisogno di un altro ingrediente: la possibilità di iniettare messaggi di errore nella pagina HTML finale che viene restituita all'utente.

La suddetta classe ErrorDict ha i seguenti metodi per estrarre i messaggi di errore:

  1. as_data () - nessuna sanificazione
  2. get_json_data (escape_html = False) - nessuna sanificazione se escape_html == False (impostazione predefinita)
  3. as_json (escape_html = False) nessuna sanificazione se escape_html == False (impostazione predefinita)
  4. as_ul () - sicuro
  5. as_text () - nessuna sanificazione
  6. __str __ () (chiama as_ul ()) - sicuro

Ora torniamo al nostro piccolo quiz. È facile vedere che lo snippet 1 è sicuro, perché utilizza il metodo __str __ (), che sfugge all'input. Gli snippet 2 e 3, tuttavia, sono pericolosi e possono causare XSS.

Ci sono due messaggi principali da asporto qui. Quello per gli sviluppatori è il mantra "disinfetta sempre input non attendibili". Quello per i ricercatori di sicurezza è: un semplice grep -R "ValidationError" potrebbe ampliare la superficie di attacco per te.

A proposito, hai il mio rispetto se hai superato correttamente il quiz senza leggere l'intero post.

Costruire un'app Web o mobile?

Crowdbotics è il modo più veloce per creare, avviare e ridimensionare un'applicazione.

Sviluppatore? Prova Crowdbotics App Builder per impilare e distribuire rapidamente app con una varietà di framework popolari.

Occupato o non tecnico? Unisciti a centinaia di team felici che creano software con PM di Crowdbotics e sviluppatori esperti. Scorri i tempi e i costi con Crowdbotics Managed App Development gratuitamente.