Per prima cosa
Sei autorizzato e autorizzato a testare e scherzare? Potresti aver bisogno di una prova scritta per il tuo bene, nel caso in cui diventi cattivo. Assicurati di non eseguire questo live su un server di produzione, utilizza invece un server di prova.
Torna alle basi
Un modo classico per dimostrare le iniezioni SQL:
$id = isset($_GET['id']) ? $id : -1; // Set default value if id isn't set
$stmt = $db->query('SELECT * FROM articles WHERE id=' . $id);
$results = $stmt->fetchAll();
fancy_display($results);
Per ottenere tutte le righe, potremmo usare 0 OR 1=1
. La query finale sarà simile a SELECT * FROM articles WHERE id=0 OR 1=1
. Poiché 1=1
è sempre true, restituirà tutte le righe dagli articoli.
Questo di solito non è ciò che vogliamo a meno che non vogliamo sottolineare il server in qualche modo. Pertanto tendiamo a utilizzare UNION
per raggiungere altre tabelle: 1 UNION SELECT ALL 1, 2, username, hash from users
.
Che dire di inserire un INSERT dopo SELECT?
L'SQL injection riguarda davvero la modifica della query SQL originale in modi involontari. La query deve essere valida per avere successo. Seguendo il nostro precedente esempio, non puoi semplicemente mescolare un INSERT con un SELECT in una query:
SELECT * FROM articles WHERE id=1 ALSO INSERT INTO articles (title, content) VALUES ("foo", "bar")
Si noti che ALSO è solo una parola chiave immaginaria, anche perché non è supportata. Un altro tentativo potrebbe essere quello di utilizzare per separare le query separandole con ;
:
SELECT * FROM articles WHERE id=1; INSERT INTO articles (title, content) VALUES ("foo", "bar")
La maggior parte delle volte questo non funzionerà. La seconda query viene ignorata, poiché il codice sottostante deve specificare che sta utilizzando "più query", anche note come "query impilate". Ad esempio, in PHP, è necessario utilizzare mysqli::multi_query
anziché mysqli::query
. La maggior parte delle applicazioni utilizza l'equivalente successivo. Potresti voler leggere una mia precedente risposta .
Iniezione di un'istruzione INSERT
Quindi l'altro modo valido è provare e trovare un codice vulnerabile che utilizza INSERT
:
// Registration page
// Got credentials via $_POST
$username = 'foo';
$password = 'bar'; // not hashed, so bad
$db->query('INSERT INTO users (username, password, admin) VALUES ("' . $username . '", "' . $password . '", 0)');
La query finale sarà simile a:
INSERT INTO users (username, password, admin) VALUES ("foo", "bar", 0)
Cambiamo il flusso utilizzando una password diversa: bar", 0), ("haxors_admin", "easy", 1)--
. La query finale sarà simile a questa:
INSERT INTO users (username, password, admin) VALUES ("foo", "bar", 0), ("haxors_admin", "easy", 1)--", 0)
Tutto dopo --
viene commentato e quindi effettivamente ignorato. Abbiamo appena aggiunto un utente amministratore. Nota che questo scenario è molto semplice per dimostrare l'attacco.
sqlmap si unisce al divertimento
sqlmap è uno strumento di automazione per trovare le vulnerabilità SQL e sfruttarle. Oltre all'estrazione dei dati, ha anche opzioni per l'acquisizione del SO come --os-shell
o --os-cmd
.
Sotto il cofano, controllerà se le query impilate sono supportate. Se lo è, utilizzerà sys_exec
o sys_eval
per eseguire quei comandi. In caso contrario, tenterà di utilizzare una backdoor Web (ad esempio una backdoor di PHP) per eseguire tali comandi. La backdoor viene creata iniettando INTO OUTFILE
: ingannare la query per scrivere in una cartella scrivibile . Ora se MySQL non ha i diritti per scrivere in quella cartella, non verrà creato. Quindi l'attacco fallisce. Questo vettore di attacco è spiegato meglio nella wiki di utilizzo di sqlmap . Maggiori informazioni su questo in Iniezione SQL avanzata per il controllo completo del sistema operativo (white paper) .
Conclusione
Nel tuo caso, le query impilate non sono supportate e MySQL non ha abbastanza diritti. Questo spiega perché l'attacco è fallito. A parte gli scopi di apprendimento, consiglierei di non disturbare ulteriormente e iniziare a correggere le vulnerabilità.