ADNKRONOS

Tecnologia

Amazon Books

WallPapers

Driver Image Banner 728 x 90

Indice articoli

 

 

SQL injection

Molti sviluppatori web non sono consapevoli di come sia possibile infiltrarsi in una query SQL, ed assumono che i comandi SQL siano sicuri.

Questo significa che le query SQL possono essere utilizzate per eludere i controlli standard di accesso ed autenticazione. Qualche volta le query SQL possono addirittura consentire l'accesso alla shell dell' host che ospita il server database.

La tecnica denominata "Direct SQL Command injection" è una tecnica dove un attaccante crea o altera un comando SQL esistente per mostrare dati riservati , per sovrascrivere dati importanti o per eseguire pericolosi comandi di sistema sull 'host del database. Questa tecnica sfrutta l'applicazione per combinare l'input dello user con le parti statiche usate per costruire la query .

 

Gli esempi che seguono sono veri (sfortunatamente).

La mancanza di controlli di autorizzazione per il superuser nella connessione tra l'input e il database, o dell'user che può essere sfruttato da un'utente, l'attaccante può generare un superuser nella vostra base di dati.

Esempio 6. Dividere il risultato della query in più pagine ... e diventare

superuser(PostgreSQL and MySQL)

$offset = argv[0]; // beware, no input validation!

$query = "SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET

$offset;";// with PostgreSQL

$result = pg_exec($conn, $query);

// with MySQL

$result = mysql_query($query);

 

Gli utenti normali cliccano sopra 'next e 'prev' che collegano a dove la variabile $offset è messa nel URL. Lo script prevede che la variabile $offset ricevuta sia numero decimale. Tuttavia, qualcuno prova a rompere il funzionamento del codice aggiungendo quanto segue nella URL

//nel caso di PostgreSQL

0;

insert into pg_shadow(usename,usesysid,usesuper,usecatupd,passwd)

select 'crack', usesysid, 't','t','crack'

from pg_shadow where usename='postgres';

--

 

// nel caso di MySQL

0;

UPDATE user SET Password=PASSWORD('crack') WHERE user='root';

FLUSH PRIVILEGES;

Se questo succede, lo script consentirà un accesso a superuser. Nota che 0 serve per dare un valore valido per la variabile $offset alla query originale e terminarla.

Nota: E' una tecnica comune quella di forzare il parser SQL ad ignorare il resto della query scritta dallo sviluppatore con -- che è il commento in SQL.

Un modo possibile per acquisire le password è quello di eludere le pagine risultanti della vostra ricerca. Quello di cui ha bisogno l'attaccante è solo di cercare se c'è una variabile sottomessa usata nella query SQL e non gestita in modo appropriato.

Questi filtri possono essere impostati di solito in una form precedente per personalizzare le opzioni WHERE, ORDERBY, LIMIT e OFFSET in uno statement SELECT .

Se il vostro database supporta il costrutto UNION l'attacco può consistere nell'appendere un intera query all'originale per fare il list delle password da una tabella qualsiasi. Usare campi criptati per le password è una buona cosa.

Esempio 7. elencare articoli e password (qualsiasi server database )

$query = "SELECT id, name, inserted, size FROM products

WHERE size = '$size'

ORDER BY $order LIMIT $limit, $offset;";

$result = odbc_exec($conn, $query);

 

La parte statica della query può essere combinata con un altra istruzione di SELECT che mostra tutte le password:

'union select '1', concat(uname||'-'||passwd) as name, '1971-01-01', '0' from

usertable;

--

Se questa query (giocando con and e --) viene assegnata ad una delle variabili usate in $query, il gioco è fatto.

Anche gli UPDATE SQL sono soggetti per attaccare il vostro database. Queste query sono anche minacciate dall'utilizzo di alcuni loro pezzi per aggiungere una query completamente nuova.

Ma l'attaccante può ingannarvi con l'opzione SET. In questo caso occorre avere qualche informazione sullo schema del database per poter manipolare la query con successo. Queste informazioni si possono acquisire osservando i nomi delle variabili nella form, o semplicemente forzando brutalmente (in senso informatico). Non ci sono poi cosi tante convenzioni per chiamare i campi che memorizzano password e username.

Esempio 8. Resettare una password per guadagnare i privilegi dello user (qualsiasi database)

$query = "UPDATE usertable SET pwd='$pwd' WHERE uid='$uid';";

ma un utente malizioso sottomette il valore ' or uid like'%admin%'; --

a $uid per cambiare la password di admin, or semplicemente imposta $pwd a

"hehehe', admin='yes', trusted=100 " (con uno spazio davanti) per guadagnare più

privilegi

. così la query viene trasformata in questa:

// $uid == ' or uid like'%admin%';--$query = "UPDATE usertable SET pwd='...' WHERE uid='' or uid like '%admin%';--";

// $pwd == "hehehe', admin='yes', trusted=100 "

$query = "UPDATE usertable SET pwd='hehehe', admin='yes', trusted=100 WHERE ...;"

ed ora un esempio terrificante di come sia possibile accedere alla shell del sistema operativo su alcuni host di database.

Esempio 9. Attacco al sistema operativo dell' host del database (MSSQL Server)

$query = "SELECT * FROM products WHERE id LIKE '%$prod%'";

$result = mssql_query($query);

Se l'attaccante imposta la variabile $prod a% ' exec master..xp_cmdshell 'net user test testpass /ADD' -- , allora $query diventa :

$query = "SELECT * FROM products WHERE id LIKE '%a%' exec master..xp_cmdshell 'net user test testpass /ADD'--";

$result = mssql_query($query);

Il server MSSQL esegue gli statement SQL in batch includendo un comando per aggiungere un nuovo user tra gli account locali del database. Se questa applicazione viene eseguita in questo modo ed è attivo MSSQLSERVER, con sufficienti privilegi, l'attaccante ora ha un account con cui accedere alla macchina.

Nota: Alcuni degli esempi visti sono specifici di un certo database server, questo non significa che altri non possano essere attaccati nella stessa maniera o che possano avere altre vulnerabilità.

Evitare le tecniche di attacco

Potete obiettare che l'attaccante deve possedere informazioni sullo schema del database nella maggior parte dei esempi.

Avete ragione, ma voi non potete sapere quando questo può accadere e come possa accadere, se accade il vostro database è esposto . Se voi state usando un package di gestione database open source o di dominio pubblico, come può essere un sistema di gestione contenuti (CMS) od un forum, gli attaccanti possono avere un pezzo del vostro codice in maniera semplice. Può essere un rischio se non è stato progettato adeguatamente.

La maggior parte di questi attacchi sono basati sullo sfruttamento di codice scritto senza la sicurezza in mente.

Mai fidarsi di nessun tipo di input, in special modo se proviene dal lato client, anche se viene da un box di selezione, da un campo di input nascosto o da un cookie. Il primo esempio ci mostra come una incolpevole query possa provocare disastri.

Mai connettersi ad un database come superuser o come proprietari del database. Utilizzare sempre user con privilegi molto limitati.

Controllare se l'input dato si aspetta un determinato tipo di dato. Il PHP ha un vasto raggio di funzioni di validazione, dalle più semplici che si possono trovare nelle funzioni per variabili e nelle funzioni per il tipo carattere (per esempio is_numeric(), ctype_digit()) fino al supporto per le espressioni regolari compatibili con il Perl.

Se l'applicazione si aspetta un input numerico, considerate di verificare i dati con is_numeric() o cambiare il tipo dato usando settype(), o utilizzate la sua rappresentazione numerica con sprintf().

 

Esempio 10. un modo più sicuro di comporre una query per paginare

settype($offset, 'integer');

$query = "SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET $offset;";

 

// please note %d in the format string, using %s would be meaningless

$query = sprintf("SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET %d;",

$offset);

Quotate ciascun input non numerico che passate al database con addslashes() o con addcslashes().

Guardate il primo esempio.

Come ci mostra l'esempio, le virgolette inserite nella parte statica della query non la rendono abbastanza sicura e sono facilmente attaccabili.

Giusto o sbagliato che sia non mostrate nessuna informazione specifica sul database, specialmente sullo schema. Guardate anche le funzioni di Error reporting, error handling e di logging.

Potete usare le stored procedures e cursori definiti in precedenza per astrarre l'accesso dei dati, in modo da non far accedere gli utenti direttamente alle tabelle o alle viste, ma queste soluzioni hanno un altro impatto.

Oltre a questo, potete beneficiare del loggare le query sia dai vostri script che direttamente dallo stesso database, se questo lo supporta. Ovviamente, non è che fare il log delle query previene da qualsiasi tentativo di intrusione, ma è un valido aiuto per circoscrivere quale applicazione è stata attaccata.

il log non è utile di per se, ma per le informazioni che ne possiamo ricavare. Quindi più dettagliato è e meglio è.

Error Reporting

Per la sicurezza del PHP ci sono due facce del reporting di errori.

Una è benefica, nell' incrementare la sicurezza, l'altra la diminuisce.

Una tattica di attacco standard consiste nell'analizzare le risposte di un sistema inviandogli dati impropri, e verificando quali errori vengono restituiti in risposta a dati differenti per tipo e contenuti.

Questo consente all'attaccante di ottenere informazioni sul server per poterne scoprire eventuali debolezze.

Per esempio, se un attaccante ha analizzato le informazioni riguardanti una pagina basata sulla sottomissione di un form in precedenza, può cercare di sovrapporre i propri dati a quelli previsti oppure di modificarli.

 

Esempio 11.Attacco con le variabili su una pagina HTML personalizzata

 

<form method="post" action="attacktarget?username=badfoo&password=badfoo">

<input type="hidden" name="username" value="badfoo">

<input type="hidden" name="password" value="badfoo">

</form>

Gli errori PHP che di solito sono restituiti, sono di grande aiuto agli sviluppatori nel debug di uno script, indicano che cosa del file o della funzione hanno sbagliato e a che numero di linea è successo.

Queste sono tutte informazioni che possono essere sfruttate. Non è inusuale per uno sviluppatore PHP usare show_source(), highlight(), hilight_string(), oppure highlight_file() come misura per il debug, ma in un sito online, questo può esporre le vostre variabili nascoste, il vostro codice non testato ed altre informazioni pericolose. E' pericoloso in modo particolare eseguire codice conosciuto con gestori di debug incorporati, oppure che usa tecniche di debug molto comuni. Se un attaccante può determinare quale tecnica state usando, può provare a forzare una pagina mandando diverse stringhe di debug molto comuni.

Esempio 12. Esposizione di variabili di debug molto comuni

<form method="post" action="attacktarget?errors=Y&amp;showerrors=1"&debug=1">

<input type="hidden" name="errors" value="Y">

<input type="hidden" name="showerrors" value="1">

<input type="hidden" name="debug" value="1">

</form>

 

A prescindere dal modo di gestire gli errori, la possibilità di generare errori in un sistema porta l'attaccante ad acquisire informazioni.

Per esempio, lo stile di un errore generico del PHP indica che il sistema utilizza il PHP, se l'attaccante sta guardando una pagina HTML e vuole verificare quale è il back-end (per guardare eventuali debolezze del sistema), inserendo dati errati, può essere possibile determinare che il sistema è costruito in PHP.

Un errore di funzione può indicare che tipo di server database si sta usando, o dare suggerimenti su come una pagina web è stata programmata o progettata.

Questo consente una analisi più profonda nelle porte aperte dal database, o a cercare per bug o debolezze specifiche della pagina web.

Inserendo diversi pezzi di dati errati, per esempio, un attaccante può determinare l'ordine di un controllo di autenticazione in uno script,(dal numero di linea dell'errore) così come può tentare degli attacchi che possono essere sfruttati in differenti punti dello script.

Un errore di filesystem o un generico errore PHP può indicare quali sono i permessi del web server, così come sono strutturati i files sul web server.

I codici di errore scritti dagli sviluppatori possono aggravare questo problema portando ad un semplice sfruttamento di informazioni che dovrebbero rimanere nascoste.

Tre sono le principali soluzioni a questo problema. Il primo è controllare tutte le funzioni e cercare di incapsulare la maggior parte degli errori.

La seconda è di disabilitare il report degli errori dal codice in esecuzione.

La terza è utilizzare le funzioni PHP per creare il vostro gestore di errori .

In accordo con la vostra politica di sicurezza potete adottare anche tutte e tre le soluzioni.

Un modo di prevenire questi problemi è quello di usare l'error_reporting() proprio del PHP, per aiutarvi a rendere sicuro il vostro codice ed individuare l'utilizzo di variabili potenzialmente pericolose.

Testando il vostro codice prima della distribuzione con E_ALL, voi potete trovare rapidamente le zone in cui le variabili dello script possono essere utilizzate o modificate in modo malevolo. Una volta pronti per la distribuzione, usando E_NONE, voi isolate il codice da ogni tentativo di debug intrusivo e malevolo.

Esempio 13. cercare le variabili pericolose con E_ALL

<?php

if ($username) { // Not initialized or checked before usage

$good_login = 1;

}

if ($good_login == 1) { // If above test fails, not initialized or checked before usage

fpassthru ("/highly/sensitive/data/index.html");

}

?>