By-passare un login che si appoggia su un database SQL

7/01/2013 10:12:00 AM -Luigi23- 2 Comments


Questa guida è a solo scopo informativo non mi assumo le responsabilità di ciò che ne farete. 

Molte persone fino ad oggi si sono chieste come eseguire un login senza avere le credenziali per l'accesso(cioè né utente né password).
Oggi vi spiegherò come fanno gli hacker a farlo.
Per iniziare vi dico che queste persone usano una tecnica dell'hacking, chiamata SQL injection, che mira a colpire le applicazioni web che si appoggiano su un database di tipo SQL. Questo exploit sfrutta l'inefficienza dei controlli sui dati ricevuti in input ed inserisce codice maligno all'interno di una query SQL. Le conseguenze prodotte sono imprevedibili per il programmatore: l'Sql Injection permette al malintezionato di autenticarsi con ampi privilegi in aree protette del sito (ovviamente, anche senza essere in possesso delle credenziali d'accesso) e di visualizzare e/o alterare dati sensibili.



Applicazione pratica

Per un esempio pratico ricorreremo ad uno script in PHP (fate riferimento alla documentazione ufficiale di PHP) che si appoggia ad un database MySQL. La tecnica che è alla base dell'Sql Injection è comunque identica anche per altri tipi di namedatabase o di linguaggio (come l'ASP). Lo script utilizzato come esempio si occupa di autenticare un utente ed è diviso in due file: il primo è form.html (un semplice form per il login in html), il secondo login.php (che controllerà i dati e stabilirà, se consentito, il login. É in PHP). L'utente visualizza form.html e compila i dati, che verranno automaticamente inviati a login.php, che li memorizza sottoforma di variabile globale $_POST.

form.html

<form action='login.php' method='post'>Username: <input type='text' name='user'>Password: <input type='password' name='pwd'>

Il form è molto semplice: ha solo due campi, uno per l'username e uno per la password. I dati immessi verranno poi passati (come detto) a login.php, nelle variabili rispettive $_POST['user'] e $_POST['pwd']. Una volta ricevuti questi dati, PHP effettua una query e li cerca all'interno del database. Se verranno trovati procederà all'utenticazione dell'utente.

login.php

//Prepara la query, in una variabile$query = "SELECT * FROM users WHERE user='".$_POST['user']."' AND pwd='".$_POST['pwd']."'";
//Esegue la query (supponiamo che sia già aperta una connessione valida al database)$sql = mysql_query($query);
//Conta il numero di righe trovate (se questo numero è maggiore di 0 i dati immessi sono corretti)if(mysql_affected_rows($sql)&gt;0){//Esegue la convalidazione dell'autenticazione e permette l'accesso a pagine protette}
?&gt;

Fin quando ci si limita a inserire quei dati per cui l'applicazione è stata originariamente pensata, non si avranno problemi. Tuttavia questo script non esegue alcun controllo sui dati ricevuti ma, anzi, li immette direttamente nella query (il programmatore, ingenuamente, suppone che gli input forniti siano sempre un nome utente e una password). Questa possibilità permette a un qualsiasi cracker di inserire dei dati che vanno ad alterare il funzionamento previsto della query.

Infatti, se, ad esempio, passassimo come username il nome dell'amministratore del servizio (utilizzeremo il nome root) e come password

123' OR '1'='1

la query diventerebbe:
SELECT * FROM users WHERE user='root' AND pwd='123' OR '1'='1'
Cioè è sempre vera, perché è necessario o che la password sia uguale a 123 oppure che 1 sia uguale a 1 (ovvero sempre!). In questo modo la query restituisce una riga e il cracker viene autenticato come l'amministratore del servizio (avrà quindi a disposizione tutte le operazioni permesse per quel livello).

Tutto questo accade perché nel valore della password sono stati inseriti degli apici (notate che quelli a inizio e a fine della password verranno aggiunti dalla query, quindi non devono essere passati come input) che diventano parte della sintassi della query stessa (SQL utilizza gli apici per contenere una stringa).

Proteggersi dalla SQL injection

L'unica possibilità di protezione è un controllo sui dati ricevuti da parte del programmatore, durante lo sviluppo del programma. Bisogna cioè assicurarsi che l'input ricevuto rispetti le regole necessarie, e questo può essere fatto in diversi modi:
  • controllare il tipo dei dati ricevuti (se ad esempio ci si aspetta un valore numerico, controllare che l'input sia un valore numerico);
  • forzare il tipo dei dati ricevuti (se ad esempio ci si aspetta un valore numerico, si può forzare l'input affinché diventi comunque un valore numerico);
  • filtrare i dati ricevuti attraverso le espressioni regolari (regex);
  • sostituire i caratteri pericolosi con equivalenti caratteri innocui (ad esempio in entità html);
  • effettuare l'escape dei dati ricevuti (ogni linguaggio, solitamente, mette a disposizione particolari funzioni per questo scopo).
Ovviamente, questi metodi possono essere applicati anche insieme sullo stesso dato in input. La scelta varia proprio a seconda delle tipologie di questi dati. Occorre, quindi, prestare particolare attenzione a tutte le varianti di un input, tenendo conto di ogni possibile (oppure improbabile) ipotesi.

Se questo post ti è stato utile condividilo con gli amici e continua a seguirmi.
Un Saluto e un Abbraccio dal vostro -Luigi23-.

Ti è piaciuto l'articolo?

2 commenti:

  1. Interessante... Ma funziona solo in alcuni casi... Tipo quando un sito non è ben protetto!

    RispondiElimina
  2. Sbagliato. Dal momento che in una query SQL immetti un OR dividi la condizione, perciò potrei mettere qualsiasi valore nel primo campo perché la condizione dopo l'OR è sempre verificata, bypassando la prima in ogni caso.
    Le condizioni sono sempre verificate assieme quando c'è un AND, è logica.
    http://www.digitanto.it/FotoArticoli/Appunti18/Ap18_0003.jpg

    RispondiElimina

Grazie per il tuo feedback!