Perché questo particolare input funziona per l'iniezione SQL?

3

Sto studiando infosec, iniziando a farmi strada attraverso alcuni dei giochi di guerra online là fuori. Recentemente abbiamo lavorato su Natas di OverTheWire ( link ) ed è stato molto divertente finora. La mia domanda è legata a una delle sfide del gioco.

** SPOILERS PER IL SEGUITO DEL GIOCO **

Su uno dei livelli, mi viene dato il mio primo incontro con mysql. Il codice di backend appare come questo (il gioco ti permette di vedere il codice php per ogni funzione, almeno all'inizio):

<?
if(array_key_exists("username", $_REQUEST)) {
$link = mysql_connect('localhost', 'natas14', '<censored>');
mysql_select_db('natas14', $link);

$query = "SELECT * from users where username=\"".$_REQUEST["username"]."\" and password=\"".$_REQUEST["password"]."\"";
if(array_key_exists("debug", $_GET)) {
    echo "Executing query: $query<br>";
}

if(mysql_num_rows(mysql_query($query, $link)) > 0) {
        echo "Successful login! The password for natas15 is <censored><br>";
} else {
        echo "Access denied!<br>";
}

mysql_close($link);
} else {
?>

<form action="index.php" method="POST">
Username: <input name="username"><br>
Password: <input name="password"><br>
<input type="submit" value="Login" />
</form>
<? } ?> 

Ho iniziato a cercare in SQL injection e ho provato alcune cose di base come foo OR 1=1 come input, ma non ho ottenuto nulla. Ho guardato il codice e ho provato a inserire citazioni con il mio input, il che mi avrebbe causato errori quando avevo un numero dispari di citazioni nell'input, ma non sapevo dove andare da lì.

Alla fine ho iniziato a lavorare sulla pagina di OWASP per il test di SQL injection e durante il test dei loro esempi mi sono imbattuto in qualcosa che diceva di provare:

$username = 1' or '1' = '1
$password = 1' or '1' = '1

Questo non ha funzionato, ma per qualche ragione, la mia intuizione ha detto di cambiare il primo ' in " nell'input $ username e l'ultimo ' in " nell'input $ password. Così è diventato

$username = 1" or '1' = '1 
$password = 1' or '1' = "1'

E ... ha funzionato. soddisfatto la condizione per questo blocco

if(mysql_num_rows(mysql_query($query, $link)) > 0) {
    echo "Successful login! The password for natas15 is <censored><br>";
} else {
    echo "Access denied!<br>";
}

e mi ha dato la password per il livello successivo.

La mia domanda è ... PERCHE '? Non ne so abbastanza di SQL injection, perché ovviamente sono un noob, ma non capisco esattamente cosa stia succedendo sul server SQL con quel particolare input.

Per reiterare, la query appare come questa (ho usato la funzione di debug nel codice sopra per farla stampare la query):

Executing query: SELECT * from users where username="1" or '1' = '1" and password="1' or '1' = "1"'

Qual è il comportamento di questa query, e in che modo sql la valuta per darmi un risultato TRUE su entrambi gli input (almeno presumo che sia ciò che sta facendo ...)? Ogni volta che cambio il " in ' in qualsiasi altra configurazione all'interno della query, fallisce. E il fatto che ci sia un numero dispari di " e ' all'interno della query mi sta facendo impazzire.

Qualsiasi consiglio o spiegazione sarebbe molto apprezzato. Mi sento come se non avrei davvero superato questo livello fino a quando non capisco cosa sta succedendo!

    
posta winter 04.02.2018 - 04:39
fonte

2 risposte

4

Whenever I change the " to ' in any other configuration within the query, it fails.

Sarebbe:

SELECT * from users where
    username = "1' or '1' = '1"
and
    password = "1' or '1' = '1"

Questo fallisce perché stai letteralmente interrogando un utente chiamato 1' or '1' = '1 con una password 1' or '1' = '1 . Se vuoi sfuggire alle doppie virgolette, devi usare le virgolette doppie - come hai fatto tu. Questa è la tua query di successo riformattata:

SELECT * from users where
    username = "1"
or
    '1' = '1" and password="1'
or
    '1' = "1"

Poiché '1' == "1" , questo valore è true.

And the fact that there are an odd number of " and ' within the query is driving me crazy.

In realtà non esiste uno squilibrio tra virgolette. In particolare, '1" and password="1' è una stringa a virgolette singole che capita di avere spazi e virgolette all'interno.

    
risposta data 04.02.2018 - 14:23
fonte
1

Nella tua query:

SELECT * from users where username="1" or '1' = '1" and password="1' or '1' = "1"

username="1" restituisce false

'1' = '1" and password="1' viene valutato come falso, poiché non viene confuso da virgolette doppie, queste vengono trattate come stringa normale perché sono racchiuse tra virgolette singole

'1' = "1" restituisce true, perché puoi usare virgolette singole e doppie virgolette e su entrambi i lati hai la stessa stringa "1"

Dato che hai OR tra queste affermazioni, è sufficiente che solo una di esse venga valutata su true, per abbinare effettivamente tutte le righe. In questo modo, la query estrae tutte le righe dalla tabella, perché 1 = 1 è true per tutte le righe e lo script valuta la prima riga, che in realtà è ciò che è interessante.

    
risposta data 04.02.2018 - 14:25
fonte

Leggi altre domande sui tag