Come è vulnerabile il mio sito web per le iniezioni SQL?

4

Gestisco un piccolo sito web in cui ho pubblicato alcuni articoli. Sono anche molto interessato a temi di sicurezza e ho provato sqlmap sul mio sito web. Ha trovato il nome del database, quindi la mia domanda è come potrebbe trovarlo.

Il sito Web è molto semplice e contiene solo un numero molto limitato di file php e ho appena testato il file index.php:
sqlmap.py -u http://myurl.com/index.php?id=5 --dbs
Nell'index.php ho usato le funzioni php mysql_real_escape_string e stripslashes per pulire la stringa prima di usarla nella domanda SQL e se il visitatore prova a fare confusione con id nell'URL, quindi ricarico solo la index.php:

$id = $_GET['id'];
if (get_magic_quotes_gpc()) {
    $id = stripslashes($id);
}
$id = mysql_real_escape_string($id);

$sql = "SELECT * , COUNT( * ) AS amount
            FROM articles
            WHERE id = $id
            GROUP BY id";
$result = mysql_query($sql) or die(header("Location: index.php"));

Quindi come potrebbe sqlmap.py ottenere il nome del database dalle informazioni di cui sopra?

Potresti spiegare come è possibile e anche fornire un esempio?

    
posta Rox 26.01.2012 - 20:16
fonte

4 risposte

9

Utilizza sempre query parametrizzate, la concatenazione delle stringhe lascia spazio per errori, non devi più lasciare quella stanza (anche queste sembrano molto più belle).

Inoltre, poiché id è un int, non ho bisogno di virgolette per iniettare:

$id = '0; Drop Table myTable;--';

$sql = "SELECT * , COUNT( * ) AS amount
        FROM articles
        WHERE id = 0; Drop Table myTable;--
        GROUP BY id";

Mi piace usare is_numeric per verificare se si tratta di un numero e buttarlo fuori non lo è.

Modifica:

PDO fornisce preparazione di query SQL: link

Quindi ad esempio:

$sql = "SELECT * , COUNT( * ) AS amount
    FROM articles
    WHERE id = :id
    GROUP BY id";
$sth = $dbh->prepare($sql);
$sth->execute(array(':id' => $id));
    
risposta data 26.01.2012 - 21:14
fonte
3

Prima di tutto, stai prendendo i passi giusti non solo assumendo che il tuo codice sia sicuro, ma in realtà testandolo.

In secondo luogo, Sqlmap fornirà alcuni livelli di dettagli su come è arrivato esattamente a un punto SQLi. Prova alcune delle seguenti cose quando lo esegui:

  • sqlmap.py -v 3 --dbs -u link

L'opzione -v 3 causerà la stampa dell'esatto carico utile iniettato. Dovresti essere in grado di vederlo anche nei log degli accessi e degli errori del tuo server web.

In terzo luogo, osservando il tuo snippet di codice: potresti provare:

  • (int) $ _ OTTIENI ['id']

Ma se puoi darci qualche dettaglio in più su ciò che sqlmap sta dicendo che il suo punto di iniezione è, come cronometrato, cieco, unione, booleano, ecc. potremmo entrare in maggiori dettagli.

    
risposta data 26.01.2012 - 20:51
fonte
2

Tutte le risposte sono ok, ma nel tuo caso particolare hai sfuggito il numero come una stringa ( mysql_real_escape_string() ), ma non l'hai racchiuso tra virgolette singole come dovrebbe essere una stringa.

Se, invece di:

$sql = "SELECT * , COUNT( * ) AS amount
        FROM articles
        WHERE id = $id
        GROUP BY id";

hai usato:

$sql = "SELECT * , COUNT( * ) AS amount
        FROM articles
        WHERE id = '$id'
        GROUP BY id";

ci sarebbe nessuna iniezione SQL un rischio ridotto di SQL injection. Ma è sempre meglio:

  • usa le istruzioni preparate
  • usa una convalida dell'input rigorosa - nel tuo caso dovresti fondere id in integer .
risposta data 26.01.2012 - 22:25
fonte
2

La risposta breve in questa particolare situazione, e dato che il $id sarà sempre un numero, è come ha affermato Neil, per filtrare l'input per assicurarsi che sarà sempre un numero intero, non importa quale.

Esempio di concetto:

$id = ( false !== ( int )$_GET[ 'id' ] >= 0 ) ?
        ( int )$_GET[ 'id' ] :
        die( header( "Location: ./index.php" ) );

Qualcosa del genere farebbe in modo che $id possa essere sempre un numero intero e non inferiore a 0 (cioè non -1). Quello che fai con un ID fallito dipende da te, in questo esempio la pagina viene reindirizzata a index.php .

In questo esempio sopra, la seguente richiesta di

id=55+union+select+1,2,3,4,5,6,7,8,9,10,11,12,13

Ne risulterebbe che $sql è:

SELECT * , COUNT( * ) AS amount FROM articles
WHERE id = 55 GROUP BY id

invece di ciò che restituisce il codice corrente che è:

SELECT * , COUNT( * ) AS amount FROM articles
WHERE id = 55 union select 1,2,3,4,5,6,7,8,9,10,11,12,13 GROUP BY id
    
risposta data 29.01.2012 - 10:45
fonte

Leggi altre domande sui tag