Esempio di SQL Injection in PHP (parte 1)

Le SQL Injection sono un genere di attacco informatico molto semplice ma potenzialmente molto dannoso. Si basa su una vulnerabilità del codice ormai nota e nei sistemi software complessi quasi del tutto debellata a patto che lo sviluppatore abbia un pizzico di esperienza sull’argomento.

L’idea è quella di inserire all’interno di testo che viene passato al database attraverso una interfaccia, ad esempio una form html, una stringa di testo con delle porzioni di testo che usano però la sintassi delle query SQL. In questo modo si inganna il db con una query malevola a restituirci un risultato non consono. Vediamo un esempio! Di seguito il codice e le istruzioni su come usarlo. Per test potreste provare ad usare le stesse istruzioni in fondo all’articolo su altri siti. Provatele da prima su qualche sito magari più artigianale, su quelli professionali o che usano CMS come Joomla e WordPress, sicuramente non avrete vita facile poiché hanno criteri e misure di controllo che annullano il rischio di tali vulnerabilità. Nei prossimi articoli vedremo alcuni elementi per scrivere codice resistente alle SQL Injection.

Creiamo una cartella sul nostro server Apache/WAMP gia predisposto ad usare PHP e possibilmente collegato gia con un PHPMyAdmin. Il codice è stato testato su Wamp 2.5 e su Linux Ubuntu 18, su versioni più vecchie potrebbero esserci delle noie con le funzioni del database (vedi msql vs msqli).

Predisponiamo 3 file/script ed una tabella su DBMSMySQL come la seguente. E’ banale e per il nostro test, inseriamo un campo password in chiaro, sapendo che non è una procedura convenzionale.

CREATE TABLE IF NOT EXISTS `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(128) NOT NULL,
  `password` varchar(128) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;

INSERT INTO `users` (`id`, `username`, `password`) VALUES
(1, 'pippo', 'pippo'),
(2, 'pluto', 'pluto'),
(3, 'test', 'test');

Il form.html e style.css con i rispettivi codici:

<!DOCTYPE html>
<html lang="it">
<head>
<title>Form di prova</title>
<meta charset="utf-8">
<link href="style.css" rel="stylesheet" type="text/css">
</head>
<body>

<form method="post" action="sql.php">
<fieldset class="form1">
<legend>Anagrafica cliente</legend>

<label for="username">Nome:</label>
<input type="text" name="username" id="username" required size=30> <br /><br />

<label for="password">Password:</label>
<input type="password" name="password" id="password" required size=30> <br /><br />

<input type="submit" value="Invia"><!-- controlla ed invia-->
<input type="reset" value="Sbianca"> <!-- reset-->
</fieldset>
</form>

</body>
</html>

il foglio di stile in realtà è molto semplice ma ci permette di formattare le caselle di input della form in modo ordinato:

label
{
	width: 100px;
    display: table-cell;
    float: left;
}

e finalmente lo script PHP che viene lanciato dal submit della form inserita nella pagina HTML

<?php
error_reporting(E_ALL);

$mysql_host = 'localhost';
$mysql_user = 'test';
$mysql_pass = 'test';
$mysql_db = 'test';
/* Connessione e selezione del database */
$connessione = mysqli_connect($mysql_host,$mysql_user,$mysql_pass);
if(mysqli_connect_errno())
  die("Connessione non riuscita: " . mysqli_error($connessione));
$db_select= mysqli_select_db($connessione,$mysql_db);
if (!$db_select)
  die("Selezione del database non riuscita");
// recupero username
$u = $_REQUEST["username"];
$p = $_REQUEST["password"];
$sql = "select * from users where username = \"$u\" and password = \"$p\" ";
print "La query usata e': ".$sql ." <br><br>";
$res = mysqli_query($connessione,$sql) or die("Errore in check.php : " . mysqli_error($connessione));
$info_utente = "";
while ($row = mysqli_fetch_array($res, MYSQLI_ASSOC))
{
      $info_utente = $row;
}
if ($info_utente == "")
{
      print "Username o Password errati";
}
else
{
      print "Utente riconosciuto : ";
      print_r($info_utente);
}
?>

Come testiamo il nostro lavoro?

1. Proviamo prima di tutto ad inserire un utente e/o password di fantasia. Lo script ci stampa la combinazione inserita e segnala che l’autenticazione è fallita.

2. Proviamo invece ad inserire uno degli utenti validi. Ad esempio nel nostro db c’è l’utente pluto con password pluto. Lo script ci indica che l’utente è riconosciuto

3. Inseriamo una username valida come “pluto” mentre nella password inseriamo una stringa con una password di fantasia, ad esempio abc ma acui facciamo seguire una stringa SQL malevola con opportune virgolette ->  abc” or “1”=”1

In questo caso cosa stiamo dicendo al database: trovami un utente pluto che abbia password abc oppure che sia valida la condizione 1=1 

Ovviamente la condizione farlocca 1=1 è sempre verificata e quindi inganna il db a trovarci il record dell’utente pluto anche se non abbiamo inserito la password corretta!!!

Ultima modifica 22 Febbraio 2022