Sei sulla pagina 1di 7

ASP.

NET SQL Injection Attack by Luca Regnicoli and Roberto Brunetti

versione stampabile

In questo brevissimo articolo volevo condividere con voi una riflessione profonda: ma proprio vero che non con gli strumenti moderni (Es. Visual Studio.NET) e con le tecnologie moderne (ES. ASP.NET) chiunque in grado di scrivere unapplicazione funzionante ? Probabilmente la risposta si: con i 30.000 wizard e le autocreazioni di form diventato veramente semplice scrivere unapplicazione. Spesso per, utilizzando in modo approssimato tali strumenti e/o tecnologie si ottengono risultati mediocri, sia in termini di performance, che di scalabilit, che di protezione delle informazioni. Sappiamo tutti che, utilizzando un database server serio come SQL Server, bene utilizzare le stored procedure per accedere in lettura/scrittura alle informazioni. E assolutamente vero che perdiamo un po di tempo nella scrittura dellapplicazione rispetto a scrivere gli statement SQL direttamente nel codice delle pagine, ma altrettanto vero che i benifici che ne derivano sono molteplici: velocit di esecuzione, riutilizzo di SP da pi applicazioni, migliore tipizzazione delle informazioni in entrata, migliore leggibilit dei parametri solo per citarne alcuni. Fin qu non credo di avervi detto niente di nuovo. Volevo porre allattenzione un problema, gi conosiciuto da chi sviluppa/sviluppava nelle precedenti versioni di ASP e in generale da coloro che sviluppa per il web. Unapplicazione Web soggetta ad attacchi di vario tipo: si parte dallaccesso ai servizi, per passare allaccesso alle informazioin fino ai vari tipi di Denial of Service. Anche se il nostro sistema hw e sw a prova di bomba (si fa per dire, non esiste un sistema veramente veramente sicuro) probabile che proprio noi sviluppatori apriamo delle brecce insospettabili per lammistratore del sistema e per il sistema stesso J Mi riferisco ad esempio ai controlli sui dati che un utente pu inserire nelle nostre Web Forms ed in particolare a quanto vedremo in questo articolo, che vuole essere semplicemente una riflessione.

SQL Injection significa iniettare del codice SQL in una applicazione. Questa tecnica di attacco solitamente praticabile solo quando lo sviluppatore si dimenticato di effettuare alcuni controlli sulle pagine che accedono ai dati e quando lo sviluppatore accede ai dati in modo non molto ortodosso.

Partiamo come sempre da un esempio semplice per poi complicare lo scenario.

Ad esempio, ho visto molte pagine ASP.NET (ma anche ASP 3.0) con il seguente codice:

Dim strSQL as String = SELECT * FROM Customers WHERE CustomerID = & txtClient.Text &

Probabilmente la pagina ASP.NET chiede allutente (supponiamo per adesso) il codice del cliente allinterno di un campo Textbox della Web Form.

Il codice della pagina ASPX il seguente FILE: SIMPLE.ASPX

... <form id="Form1" method="post" runat="server"> <p>Codice Cliente <asp:TextBox ID="txtCliente" Runat="server"></asp:TextBox> <asp:Button ID="btnCerca" Runat="server" Text="Cerca" /> <asp:DataGrid AutoGenerateColumns="True" ID="dgCustomer" Runat="server" /> </form> ...

Mentre il codice del CodeBehind il seguente

FILE: SIMPLE.ASPX.CS

private void btnCerca_Click(object sender, System.EventArgs e) { string sConn = Server=XXX; uid=... SqlConnection oConn = new SqlConnection(sConn); string strSQL = "SELECT * FROM Customers WHERE CustomerID = '" + txtCliente.Text + "'"; SqlCommand oCmd = new SqlCommand(strSQL, oConn); oConn.Open(); SqlDataReader oReader = oCmd.ExecuteReader(CommandBehavior.CloseConnection); dgCustomer.DataSource = oReader; Page.DataBind(); oReader.Close(); oConn.Close(); }

Quando lutente preme il pulsante Ricerca la pagina estrae il record corrispondente con lo statement sopra indicato e ritorna i dati in una data list.

E senza grosse formattazioni la pagina si presenta cos:

Lutente potrebbe prova a digitare il simbolo percentuale % per cercare di estrarre tutti i record della tabella Customer. Fortunatamente il nostro super codice non contiene nessuna clausola LIKE, quindi lutente non otterrebbe nessun record in risposta.

Se per lutente, invece di inserire un ID di cliente (ANTON nel nostro esempio), inserisce questa simpatica stringa

ANTON' OR CustomerID LIKE '%

Vi immaginate cosa accade nella nostra pagina ?

Il risultato della stringa SQL che la nostra pagina invia a SQL Server sarebbe

SELECT * FROM Customers WHERE CustomerID = ANTON' OR CustomerID LIKE '%

Loutput della pagina ovvio J

E vero che lutente maligno deve conoscere il nome del campo della nostra tabella per impostare la corretta clausola LIKE, ma altrettanto vero che il cosiddetto Lazy Programmer (letteralmente Programmatore Stanco...o scarpone J) costruisce la tabella SQL con un nome di campo facile da ricordare che probabilmente corrisponde al nome della colonna della tabella da presentare allutente.

Se il programmatore ha usato nomi tipo AS/400 il problema non si presenta J Probabilmente il campo CodiceCliente si chiamerebbe ACCC01A... anche vero per che esistono delle convenzioni, di conseguenza protrebbe addirittura essere pi semplice scoprirli J

Vediamo come risolvere il problema di scoprire come si chiamano i campi della tabella sorgente

Provate la seguente stringa

ANTON OR 1=1 --

Il risultato perfetto, e senza conoscere i nomi dei campi.

N.B. i due trattini (--) sono la sintassi per definire un commento in T-SQL. Nel caso di Oracle basta usare un ; (punto e virgola) e per MySQL sufficente un # (cancelletto, o sharp come va di moda adesso)

Ma, lattacco SQL Injection, consente allhacker di provare a scoprire qualcosa in pi sul nostro database server.

La prima tecnica si chiama SQL Union Attack e consiste nel cercare di estrarre dal db informazioni di altre tabelle (il nome Union deriva proprio dalla omonima clausola SQL).

Proviamo subito a digitare nella textbox CodiceCliente la seguente stringa

ANTON UNION SELECT @@SERVERNAME

La stringa SQL inviata al database sar quindi

SELECT * FROM Customers WHERE CustomerID = ANTON' UNION SELECT @@SERVERNAME--

Vediamo come appare la nostra Web Form di esempio, anzi risparmiatevelo perch in questo caso viene generato un errore, ma il motivo non quello che si pensa e cio non si potr chiedere il nome del server a SQL. Lerrore deriva semplicemente dal fatto che la seconda select non ritorna un numero uguale di colonne rispetto alla prima. Non per difficile scoprire il numero delle colonne: basta contare il numero delle colonne presentate a video e ripetere n volte @@servername nel campo textbox. Anche andare a tentativi non poi cos difficile.

Scrivendo nel nostro caso 11 volte @@servername, il risultato il seguente

Provate anche con @@ServiceName e con @@Version... divertente. Con @@Version ad esempio il buon databse ritorna la sua versione, la piattaforma con la relativa versione e build. Ad esempio Microsoft SQL Server 2000 - 8.00.534 (Intel X86) Nov 19 2001 13:23:50 Copyright (c) 1988-2000 Microsoft Corporation Developer Edition on Windows NT 5.1 (Build 2600: )

Cos sapete come si chiama la macchina con cui abbiamo scritto questo articolo, nonch la versione del nostro SQL Server e il nostro sistema operative (NT 5.1 Windows XP)

La soluzione al problema non esiste in un wizard o un automatismo tecnologico e quindi implica la scrittura di qualche riga di codice. In fondo il nostro lavoro ed spesso quello che differenzia unapplicazione che crasha o da problemi da unapplicazione seria e con bassa manutenzione.

Un semplice metodo e come tale non cos efficace pu essere semplicemente impostare la lunghezza massima della TextBox. Mettiamo quindi la maxlength HTML nel campo textbox, ma invece di provare a vedere se funziona, ricordiamoci che una controllo client-side pu essere eluso facilmente da un utente medio. Anche inserendo script lato client nessuno impedisce allutente di salvare la pagina sul suo disco, rimuovere tutti i controlli, ricarica la pagina dal suo disco e farci una POST Http con le informazioni che vuole. Anche senza questo giro, pu simulare una POST con un client diverso dal browser.

Abbiamo capito che il controllo delle informazioni va fatto sempre anche server-side, unico meccanismo per evitare le tecniche di spoofing pi comuni.

Non esistendo un Validator Control in ASP.NET che controlli la lunghezza di un campo, dobbiamo procedere a mano controllando, dove possibile, la lunghezza della stringa di input.

E assolutamente ovvio che questo controllo lasci un po il tempo che trova, visto che gi un campo lungo 11 caratteri consente allutente di scrivere A OR 1=1 nella input box.

Di conseguenza la soluzione controllare che non siano presenti caratteri speciali (!,;,@,#,-, etc etc) oppure clausole SQL (UNION, AND, OR, etc etc).

In questo caso esiste un Validator Control che ci pu dare una mano per il controllo dei caratteri digitati in un campo input: RegularExpressionValidator. Ricordiamo che tutti i Validator Control effettuano anche i controlli server-side.

Scrivere le regular expression non cos banale come scrivere un po di if nel codice, ma sicuramente ne guadagnamo in pulizia ed eleganza di codice. Scrivere 39 if nel click di un pulsante non rende il nostro codice cos leggibile.

Ecco un esempio di Regular Expression

[^/=%-]*

che consente di controllare che non esistano i seguenti caratteri in una stringa:

/ = % -

(Slash, Uguale, Percento, Meno)

(N.B. Ricordatevi di mettere il come ultimo carattere essendo un carattere speciale)

Applicando questa espressione alla proprit ValidationExpression del controllo RegularExpressionValidator abbiamo risolto il problema, almeno per adesso....

Nel prossimo articolo infatti vedremo qualche altro tipo di SQL Injection e speriamo....la soluzione ad essi.