PHP: sono libero da SQL Injection? [duplicare]

3

Consentitemi di prefigurare ciò dicendo che questo è il mio primo tentativo di capire l'igiene dei fattori di produzione, e al momento sono ancora un principiante di PHP. Ho creato un registro rapido / accesso al sito Web per testare alcune cose e ho problemi a romperlo. Sto cercando di sfruttare il mio sito web in modo da poter capire (da solo, si spera) come risolvere questo problema.

Ho fatto un bel po 'di ricerche, ma non importa quante cose diverse provo, semplicemente non posso influenzare il mio sito. Quello che sto cercando di fare è di fare qualcosa, dal far cadere le tabelle per ottenere informazioni sugli utenti - tutto ciò che potrebbe rappresentare un rischio. Di seguito è riportato il mio codice ridotto. Sono abbastanza sicuro che ci sia spazio per l'iniezione, ma sinceramente non riesco a trovarlo. Inoltre, non importa al mio uso di MD5. So che ci sono cose migliori là fuori!

Supponi che $user e $password provengano da un modulo senza che nulla sia stato eseguito.

$password = md5($password);

$query = mysqli_query($con,"SELECT * FROM users WHERE name='$user'");
$numrows = mysqli_num_rows($query);

if ($numrows == 1){

    $row = mysqli_fetch_assoc($query);
    $dbpass = $row['password'];
    $dbuser = $row['name'];

    if ($password == $dbpass){  
        $_SESSION['name'] = $dbuser;
    }
}

Quello che sto cercando è qualsiasi exploit che posso usare per imparare da. Se hai suggerimenti su come proteggerlo, sarebbe apprezzato anche.

Saluti.

    
posta 07.04.2015 - 21:41
fonte

2 risposte

4

Hai provato a includere le virgolette per rompere questo? Da quello che vedo qui, in realtà dovrebbe causare un errore orribile se viene passata una citazione. A volte devi gironzolare un po 'prima che accada l'incidente.

$query = mysqli_query($con,"SELECT * FROM users WHERE name='$user'");

Ecco il mio tentativo di rompere questo:

'OR 1=1--

Sembra che tu non abbia usato le query parametrizzate, lasciando quindi il tuo codice aperto all'iniezione. Nota quanto sopra è solo una dimostrazione di concetto: con il tuo codice attuale non ti consente di fare molto che puoi vedere.

Il tuo codice convalida i risultati della query dopo che viene eseguita, il che è molto pericoloso. Sei aperto agli attacchi temporali SQL per lo meno.

Le istruzioni per l'implementazione delle query parametrizzate sono le seguenti: link link

Inoltre:

1) Come principiante, stai molto meglio usando un ORM pre-creato.

2) La sanitizzazione dell'ingresso è la chiave. Fai sempre questo prima che i dati entrino in una query.

3) Se stai facendo questo per imparare la sicurezza, prova un gioco di guerra pre-fatto simile, potrebbe darti una guida migliore per imparare a sfruttare il bug.

Avviso: Non conosco troppo bene questa particolare API PHP, quindi se si eseguono query parametrizzate per impostazione predefinita, non potrei dirlo o non ne ero a conoscenza.

    
risposta data 07.04.2015 - 22:09
fonte
3

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.

    
risposta data 07.04.2015 - 22:18
fonte

Leggi altre domande sui tag