- SQL Injection avviene quando l'input utente viene concatenato direttamente nella query - il DB esegue codice che non dovrebbe
- Un apostrofo nel campo username è spesso sufficiente per rilevare la vulnerabilità
- La difesa corretta è la parameterized query - non l'input validation da sola
- Il WAF può rallentare l'attacco ma non sostituisce il fix nel codice
▶ $ history
- curl -s -X POST url -d "username=test&password=test"
- tshark -r capture.pcap -Y "http.request.method == POST"
Mi hanno dato tre ore e un URL. Un'applicazione web interna - gestionale ordini, usato dal reparto commerciale. "Testala. Dimmi cosa non va."
Niente scope limitato. Niente whitelist. Solo: trova.
Apro il browser.
Setup#
┌──────────────────┐ rete isolata ┌──────────────────────┐
│ Kali Linux │◄──────────────────────►│ App web (Ubuntu) │
│ 192.168.64.200 │ │ 192.168.64.10 │
│ │ │ │
│ curl, browser │ │ Apache + PHP + MySQL│
└──────────────────┘ └──────────────────────┘L'applicazione ha un form di login standard. Username, password, pulsante Accedi. Niente di speciale in superficie.
Fase ATTACCO - Reconnaissance#
Il primo test è sempre il più semplice: inserisco un apostrofo nel campo username.
curl -s -X POST http://192.168.64.10/login.php \
-d "username='&password=test"Warning: mysqli_fetch_assoc() expects parameter 1 to be mysqli_result,
boolean given in /var/www/html/login.php on line 47
You have an error in your SQL syntax; check the manual that corresponds
to your MySQL server version for the right syntax to use near ''
# output simulatoL'applicazione mostra l'errore direttamente nella risposta HTTP. Due informazioni preziose in una riga: il server usa MySQL, e il codice non gestisce gli errori. Il percorso del file (/var/www/html/login.php) è un regalo in più.
L'apostrofo ha rotto la query. Questo significa che l'input viene concatenato direttamente nel SQL senza sanitizzazione.
Cosa sta succedendo nel codice#
La query originale del form è probabilmente questa:
// codice vulnerabile nel server
$query = "SELECT * FROM users WHERE username='" . $_POST['username'] . "' AND password='" . $_POST['password'] . "'";Quando inserisco ', la stringa diventa:
SELECT * FROM users WHERE username=''' AND password='test'Tre apostrofi - la sintassi SQL è rotta. Il DB non sa cosa farne e va in errore.
Fase ATTACCO - Exploitation#
Ora che so che è vulnerabile, costruisco un payload per bypassare il login.
curl -s -X POST http://192.168.64.10/login.php \
-d "username=admin'--&password=qualsiasi"La query che arriva al DB diventa:
SELECT * FROM users WHERE username='admin'-- AND password='qualsiasi'-- commenta tutto ciò che segue. La condizione sulla password sparisce. Se esiste un utente admin, sono dentro.
Benvenuto, admin. Ordini in attesa: 847
# output simulatoAccesso ottenuto senza conoscere la password.
Sequenza completa#
sequenceDiagram
participant K as Kali (attaccante)
participant APP as App PHP
participant DB as MySQL
K->>APP: POST username=' (apostrofo)
APP->>DB: SELECT ... WHERE username=''' ...
DB->>APP: Syntax error
APP->>K: Errore SQL visibile (info disclosure)
Note over K: Confermata SQLi + tecnologia
K->>APP: POST username=admin'--
APP->>DB: SELECT ... WHERE username='admin'-- AND password=...
DB->>APP: Record utente admin (password ignorata)
APP->>K: Sessione autenticata come admin
Fase DETECTION - cosa vede il WAF#
Il WAF aziendale (se presente) avrebbe dovuto loggare queste richieste.
Pattern sospetti nel traffico HTTP:
tshark -r capture.pcap \
-Y "http.request.method == POST" \
-T fields -e ip.src -e http.request.uri -e http.file_data \
| grep -i "login"192.168.64.200 /login.php username='&password=test
192.168.64.200 /login.php username=admin'--&password=qualsiasi
# output simulatoSegnali da configurare nel WAF o nel SIEM:
- Apostrofi e virgolette nei campi POST
- Sequenze
--,/*,*/,UNION,SELECTnei parametri - Errori HTTP 500 ripetuti dallo stesso IP in breve tempo
Il WAF può bloccare i payload noti, ma se il codice è vulnerabile e l'attaccante usa encoding o varianti meno comuni, il WAF viene bypassato. La patch nel codice è l'unica soluzione definitiva.
IoC e tecniche#
| Tipo | Valore | Contesto | MITRE ATT&CK |
|---|---|---|---|
| Tecnica | Apostrofo in campo POST | Test iniziale SQLi | T1190 |
| Tecnica | '-- in campo username | Authentication bypass | T1190 |
| Info | Path /var/www/html/login.php in errore | Information disclosure | T1082 |
| Info | Versione MySQL in errore | Version disclosure | T1082 |
Fase RESPONSE - il fix#
La vulnerabilità ha una correzione netta: parameterized query.
// PRIMA - vulnerabile
$query = "SELECT * FROM users WHERE username='" . $_POST['username'] . "'";
// DOPO - sicuro
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = ? AND password = ?");
$stmt->execute([$_POST['username'], $password_hash]);Con la parameterized query, l'input dell'utente viene passato al DB come dato, non come codice. Qualsiasi carattere speciale - apostrofi inclusi - viene trattato letteralmente. La query non può essere modificata dall'input.
Checklist fix completo:
- Convertire tutte le query a parameterized query o prepared statement
- Rimuovere la visualizzazione degli errori SQL in produzione (
display_errors = Off) - Applicare least privilege all'utente DB dell'applicazione - no
DROP, noALTER - Aggiungere logging delle richieste POST anomale
- Configurare WAF con regole per pattern SQLi comuni
- Eseguire SAST sul codice per trovare altri punti di concatenazione SQL
exit 0#
Tre minuti. Un apostrofo. Accesso admin a 847 ordini in sospeso.
La SQLi non è una vulnerabilità sofisticata - esiste da decenni, i tool di rilevamento automatico la trovano in secondi. Eppure continua a comparire in ogni pentest perché il fix richiede di toccare il codice, e toccare il codice richiede tempo che spesso non viene dato.
Input validation è necessaria ma non sufficiente - un attaccante paziente trova sempre una variante che bypassa i filtri. La parameterized query separa il codice dai dati a livello strutturale: non c'è niente da bypassare.




