Sì, sei completamente aperto all'iniezione SQL, ad esempio tramite validUsername' injectionPayload %23
, che ti darebbe questa query (il #
(codificato come %23
tagli del restante '
):
SELECT * FROM users WHERE name='validUsername' injectionPayload #'
Into Outfile
in base ai diritti dell'utente, è possibile scrivere contenuto in un file con questo carico utile:
-1' UNION ALL SELECT 'injected string' INTO OUTFILE '/path/to/file.php' #
Iniezione cieca (con credenziali utente valide)
Con il tuo codice attuale, è difficile ottenere tutti i dati direttamente dal database. Utilizzi solo la password e il nome, ed entrambi devono essere corretti, altrimenti il tuo codice non funzionerà.
Ma questo è uno script di accesso, quindi creerà un risultato diverso per le credenziali utente valide e per quelle non valide, corretto?
In questo caso, è possibile utilizzare l'iniezione SQL standard cieca (se si dispone di credenziali utente valide). I payload avrebbero un aspetto simile a questo:
// mysql 4 or 5?
validUsername' AND substring(version(), 1, 1)='5
validUsername' AND substring(version(), 1, 1)='4
// is first char of database hash smaller than ascii 100?
validUsername' AND ascii(substring((SELECT password FROM mysql.user LIMIT 0,1),1,1))<100 #
[...]
E così via. Quello che succede è che combini la query con una domanda booleana. Ad esempio does the database version start with a 5?
. Se la risposta è true
, allora tutto funziona normalmente ed è stato effettuato l'accesso. Se la risposta è false
, non si effettuerà l'accesso poiché la query non restituirà dati e quindi $numrows == 1
è false.
Crea molte richieste (specialmente per uno script di accesso), ma è possibile estrarre i dati.
Ignora accesso
Dovrebbe anche essere possibile ignorare la pagina di accesso (accedi come qualsiasi utente se conosci il nome utente ma non la password):
-1' UNION ALL SELECT name, md5('password') FROM users WHERE name='attackedUser' #
Non l'ho verificato, ma cosa dovrebbe succedere: il -1
rimuove i risultati legittimi della query, union
aggiunge i risultati della query inserita e la query iniettata ottiene il nome di un utente attaccato e imposta la password su password
per questa richiesta (e invii password
come valore POST per la password).
Iniezione cieca (senza credenziali utente valide)
Come abbiamo visto nella sezione precedente, possiamo effettivamente impostare la password, quindi non abbiamo bisogno di credenziali valide per un'iniezione cieca. Potresti combinare il primo e il secondo attaccante descritti, oppure potrei immaginare qualcosa del genere:
-1' UNION ALL SELECT 1,md5(user) FROM mysql.user LIMIT 0,1 #
Questa è solo una stringa semplificata per mostrare l'idea: di nuovo, si rimuovono i dati validi con -1
, si aggiunge la query e si seleziona come password i dati da estrarre (hash MD5, come fornito la password verrà sottoposta a hash). Quindi, come la password che invii tramite POST, inserisci il valore che indovini (es. root
). Questi due valori verranno quindi confrontati tramite $password == $dbpass
. Se hai effettuato l'accesso, la tua ipotesi è corretta, in caso contrario, allora è sbagliato. Per indovinare gli hash delle password, puoi utilizzare l'approccio della sottostringa dall'alto.
Conclusione
Anche se pensi che l'iniezione SQL che hai non divulga alcuna informazione, dovresti comunque usare le dichiarazioni preparate, in quanto potrebbe esserci un modo per divulgare le informazioni. E anche se non è in questo momento, il tuo codice potrebbe cambiare in futuro.