Vous êtes sur la page 1sur 10

Les bases des Injections SQL

Ghosts In The Stack http://www.ghostsinthestack.org

TranceFusion

Rsum
Les injections SQL font partie des failles Web redoutables, puisqu'elles s'exploitent ct serveur. Elles touchent les sites qui interagissent de manire non scurise avec une base de donnes, permettant ainsi un attaquant de dtourner les requtes comme il le souhaite. Nous verrons ici les bases de ce type de failles, et quelques techniques d'injections plus pousses, mais sans rentrer dans le dtail des "Blind SQL Injections".

Table des matires


1 Exemple - Principe de base 2 Bypasser un formulaire d'authentication 3 Correction 4 Obtenir des infos - Exemples d'injections plus pousses
4.1 4.2 Obtenir un mot de passe Autres exemples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1 4 5 6
7 7

1 Exemple - Principe de base


Le principe de base qui explique la prsence d'une faille d'injection SQL est trs simple. Observons ce code pour comprendre :

`3EE reherheFphp EEb `htmlb `hedb `titlebns titre`Gtitleb `Ghedb `ody golora4lk4 texta4white4 linka4yellow4 vlinka4fuhsi4b `p ligna4enter4b`strongbeherhe dns les rtiles X`Gstrongb`Gpb `c if @isset@6y4reh4AA {
1

6onnet a mysqlonnet@ryDiDeAY mysqlseletd@feiD6onnetAY 6sql a 4ivig idrtileD titreD ontenu pyw rtiles rii titre vsui 974F 6y4reh4F479 y ontenu vsui 974F6y4reh4F4794Y 6result a dmysqlquery@6sqlA or die @4irreur dns le trtement de l requte X4F6sqlAY 6n a mysqlnumrows@6resultAY if @6n ` IA { eho 4`p ligna9enter9bxous n9vons trouv uun rsultt pour `b4F 6y4reh4F4`GbF4Y cb `p ligna4enter4b ous pouvez relner une reherhe X`Gpb `form nmea4formreh4 methoda4post4 tiona4reherheFphp4b `p ligna4enter4b`input typea4text4 nmea4reh4 sizea4IP4b`Gpb `p ligna4enter4b`input typea4sumit4 nmea4formuttonI4 vluea4eherher4b`Gpb `Gformb `c } else { cb `pbxous vons trouv les rsultts suivnts X`Gpb `c while@6row a mysqlfethrry@6resultAA { cb `tle ellpddinga4H4 ellspinga4H4 widtha4SUQ4 ligna4enter4b `trb `td widtha4STQ4 heighta4PV4 golora45TTHHHH4b `p ligna4enter4b`b`ca6row4titre4cb`Gb`Gpb `Gtdb `Gtrb `trb `td widtha4STQ4 heighta4IV4 golora45HHHHTT4b `pb`ca6row4ontenu4cb`Gpb `Gtdb `Gtrb `Gtleb `c

} } mysqllose@6onnetAY

else { cb `p ligna4enter4b pez e que vous voulez reherher sur le site X`Gpb `form nmea4formreh4 methoda4post4 tiona4reherheFphp4b `p ligna4enter4b`input typea4text4 nmea4reh4 sizea4IP4b`Gpb `p ligna4enter4b`input typea4sumit4 nmea4formuttonI4 `Gformb `c } cb `Godyb `Ghtmlb
Bien qu'un peu long, ce code montre un exemple complet de page. Quel est son rle ? C'est un moteur de recherche dans des articles, tout simplement. La vulnrabilit se situe dans le code en rouge. En eet, la requte eectue est la suivante :

vluea4eherher4b`Gpb

6sql a 4ivig idrtileD titreD ontenu pyw rtiles rii titre vsui 974F6y4reh4F479 y ontenu vsui 974F6y4reh4F4794Y
En vert se trouve le contenu encadr par des guillements simples ; c'est ce que va rechercher le script dans la table des articles, l'aide de l'oprateur chercher du contenu qui "ressemble" ce qui est tap par l'utilisateur, car le % est interprt par LIKE comme "n'importe quelle chane de caractres". C'est un peu comme une expression rgulire ; si vous recherchez "%un%", vous pourrez obtenir n'importe quelle chane de caractre contenant "un", comme "une", "lune", et "brun".

LIKE. En eet, LIKE utilis avec le caractre '%' permet de

Mais cet oprateur ne constitue pas une faille. La vulnrabilit est due au fait que l'entre $_POST["rech"] n'est pas ltre. Car nous pouvons imaginer qu'un utilisateur rentre cette chane : "n'importe quoi". A ce moment l, la requte devient :

6sql a 4ivig idrtileD titreD ontenu pyw rtiles rii titre vsui 97n9importe quoi79 y ontenu vsui 97n9importe quoi794Y
Et l'on remarque trs vite le problme qui va se poser : une erreur de syntaxe due au guillement, que mysql intermprte comme la n de la chane de caractres. La requte ne sera pas excute, et le visiteur obtiendra :

irreur dns le trtement de l requte X ivig idrtileD titreD ontenu pyw rtiles rii titre vsui 97n9importe quoi79 y ontenu vsui 97n9importe quoi79
Maintenant, imaginons un visiteur plus expriment, et qui connat ce type de faille. Il teste une premire fois le script en rentrant "n'importe quoi", le script plante et lui ache la reqte fautive. Ensuite, voici ce qu'il pourrat rentrer dans le formulaire :

9 y 979 a 9

La requte devient donc :

ivig idrtileD titreD ontenu pyw rtiles rii titre vsui 979 y 979 a 979 y ontenu vsui 99 y 979 a 979
Ici, le script ne plantera pas ; il n'y a aucune erreur de syntaxe. Le script ressortira la liste de tous les articles, puisque la condition 'a%' = 'a%' est toujours ralise.

Ceci tait un exemple de dtournement de requte, mais il n'est pas trs utile. Cependant, il est tout fait possible de dtourner le script an d'obtenir des renseignements utiles sur le serveur. C'est ce que nous allons bientt voir.

2 Bypasser un formulaire d'authentication


Laissons cet exemple de ct et penchons-nous plutt sur un deuxime :

`3EE dminFphp EEb `htmlb `hedb `titlebns titre`Gtitleb `Ghedb `ody golora4lk4 texta4white4 linka4yellow4 vlinka4fuhsi4b `p ligna4enter4b`spn stylea4fontEsizeXIRptY4b`bge d9dministrtion `Gb`Gspnb`Gpb `p ligna4enter4b`c if @isset@6y4login4A 88 isset @6y4pss4AA { 6onnet a mysqlonnet@ryDiDeAY mysqlseletd@feiD6onnetAY 6sql a 4ivig loginD pss pyw users rii login a 94F6y4login4F49 exh pss a 94F6y4pss4F494Y 6result a dmysqlquery@6sqlA or die @4irreur lors du tritement de l requte 4F6sqlAY if @mysqlnumrows@6resultA ` IA die @4voginGss inorret 3`r Gb ` href a 9dminFphp9betour`Gb4AY cb `p ligna4enter4bfienvenue 3 ous vez dsormis s toutes les fontions d9dministrtion du site 3 `Gpb `p ligna4enter4bb gonsulter l fhh`Gpb `p ligna4enter4bb qrer les rtiles`Gpb `p ligna4enter4bb FFF`Gpb `c } else { cb
4

`p ligna4left4bgette pge est rserve ux dministrteurs 3 i vous tes n9en tes ps unD liquez ` hrefa4indexFphp4bii`Gb 3`Gpb `p ligna4left4b `Gpb `form nmea4formlogin4 methoda4post4 tiona4dminFphp4b `p ligna4enter4bintrez votre login G pss X`Gpb `p ligna4enter4b `input typea4text4 nmea4login4 vluea4login4b`Gpb `p ligna4enter4b`input typea4pssword4 nmea4pss4 vluea4pss4b`Gpb `p ligna4enter4b`input typea4sumit4 nmea4ok4 vluea4yu4b`Gpb `Gformb `c } cb `Godyb `Ghtmlb
Ceci est un exemple trs basique de formulaire de zone admin. Et non scuris... Mis part qu'il soit vulnrable une XSS, il l'est galement pour les injections SQL. En eet, si nous rentrons ceci :

9 y 99a9
La requte en rouge devient

6sql a 4ivig loginD pss pyw users rii login a 99 y 99a99 exh pss a 99 or 99a994Y
Ainsi, on peut se loguer sans connatre l'utilsiateur et le mot de passe, puisque la consition 'a'='a' est toujours vrie.

On se rend donc compte que les injections SQL peuvent devenir trs dangereuses si l'administrateur a une politique de scurit ngligente, ou s'il n'en a pas du tout...

3 Correction
Si vous tes webmaster, cela vous intressera srement de savoir comment corriger ce type de failles. En ralit, c'est trs simple, encore faut-il prendre le temps de se documenter ce sujet...

Le premier rexe que l'on peut avoir est de se dire "les guillements sont proscrire, ce sont eux les causes de ce type de failles", et donc de coder un script qui enlve tous les guillements ou qui les chappe en rajouttant un antishash devant. On peut donc utiliser la fonction addslashes() ou bien utiliser les options magic_quotes_gpc et magic_quotes_runtime qui le font en parmanence pour nous. Ainsi, ce code est scuris :

funtion seure@6texteA{ return mysqlrelespestring@6texteAY } GB FFF


5

BG 6sql a 4ivig idrtileD titreD ontenu pyw rtiles rii titre vsui 974Fseure@6y4reh4AF479 y ontenu vsui 974Fseure@6y4reh4AF4794Y
La fonction que nous avons cod, secure(), ajouttera des antislashes si ncessaire devant tous les ', ce qui les rendra interprts par mysql non en tant que n de chane mais comme des simples caractres. Elle utilise la fonction mysql_real_escape_string(), conue spcialement pour viter ce type de failles.

Mais le problme de ce genre de solution apparat trs clairement lorsque nous voulons eectuer des requtes faisant intervenir des nombres :

6sql a 4ivig idrtileD titreD ontenu pyw rtiles rii idrtile a 4F6y4idrtile4F44Y
En eet, ici, il sera toujours possible de faire des injections SQL car il n'y a pas de guillemets encadrant le nombre (ici, $_POST["idarticle"]). On peut trs bien taper "0 OR 1=1" an de lister tous les articles. Mme si c'est inutile, cela permet quand mme de prouver l'existence de la faille.

On en conclut que mme si une fonction de scurisation des guillements est prsente, qu'elle soit automatique ou non (magic_quotes), il y a toujours un risque. Pour l'liminer dnitivement, il faut donc faire :

6sql a 4ivig idrtileD titreD ontenu pyw rtiles rii idrtile a 94Fseure@6y4idrtile4AF494Y
On a rajout des guillements simples encadrant le nombre, ce qui ne gne en rien Mysql. Et cela rend le script scuris...

Pour rsumer, la solution pour se protger des injections SQL est simple : il ne faut jamais faire conance l'utilisateur. Ne jamais le sous-estimer et penser qu'il n'est pas inform. Il faut alors ltrer tout ce que peut rentrer l'utilisateur avant de faire quoi que ce soit.

De plus, vous ne devez jamais laisser paratre les erreurs SQL sur votre site, car une personne malveillante peut faire planter le script volontairement an de recueuillir des informations sur le nom des champs et des tables du serveur. C'est pour cela qu'il vaut mieux retourner un code d'erreur si une fonction choue, plutt que d'aacher la requte. D'ailleurs, ici, cet achage provoque une vulnrabilit de type XSS, car l'utilisateur malin qui injectera du javascript dans le champ fera d'une part chouer l'interaction avec la base, et d'autre part acher son code...

4 Obtenir des infos - Exemples d'injections plus pousses


Maintenant, nous allons introduire l'exploitation de ces failles de manire avance travers quelques exemples. Ne perdez pas de vue le fait que ces exemples ne sont pas des cas rels ; ici, nous voulons juste montrer l'tendue de ces failles. Dans un autre articles, les "Blind Injections SQL", nous verrons concrtement comment l'on se dbrouille en ralit. Je vous conseille donc de vous repporter cet article pour obtenir des cas plus concrets.

4.1

Obtenir un mot de passe

Tout d'abord, reprenons le premier exemple, le moteur de recherche. Ce script trs mal conu ache la requte lorsqu'il plante, donc nous allons tirer parti de cet achage pour noter le nom des tables et des champs. Pour le deuxime exemple, nous pouvons aussi faire planter le script en mettant un guillement, ce qui nous rvle le nom de la table "membres", et des deux champs "login" et "pass", assez explicites. A prsent, essayons de rcuprer le login et le pass de l'admin. Nous voulons faut donc trouver un script sur le site vulnrable qui en ache. Par exemple, le moteur de recherche ache les articles. A l'attaque ! Voici ce que nous pouvons rentrer dans le champ :

acher

ces informations. Il nous

9 union ll selet idrtileD pss s titreD login s ontenu from usersDrtiles 5


Notez que UNION n'est disponible que depuis MySQL 4. La requte devient :

6sql a 4ivig idrtileD titreD ontenu pyw rtiles rii titre vsui 979 xsyx selet idrtileD pss s titreD login e ontenu pyw usersDrtiles 579 y ontenu vsui 979 xsyx ivig idrtileD e e titreD login e ontenu pyw usersDrtiles 5794Y
Le # reprsente pour MySQL un commentaire ! Remarquez que l'on peut aussi utiliser '/*'. Par consquent, tout ce qui est aprs sera ignor. La requte slectionne donc tous les articles et ajoute (rle du mot cl UNION) tous ces rsultats la liste des administrateurs et leur mot de passe. Notez l'astuce consistant renomer l'aide de AS les champs an de russir l'UNION. De plus, si vous croisez une table A de n champs avec une table B, B devra forcment avoir elle aussi n champs, que l'on slectionne trois champs dans chaque partie de la requte. Cela peut donc produire cet achage :

qui devront avoir le mme type

. C'est pour cela

toyeux xol te vous souhite un joyeux xol est une trs onne nne 3 ersion QFVFP t S ve site vient d9tre mis jour 3 hes nouveuts font leur ppritions 3 IPQRST dmin pssP dminP
On a donc les mots de passe des deux admins, et le comble c'est qu'ils sont cods en clair !

4.2

Autres exemples

Imaginons maintenant que nous disposons du nom d'une table et d'un champ dans cette table. Nous voulons obtenir le nom d'un champ et d'une autre table o l'on pourrait trouver des informations utiles. La mthode utiliser est de la divination pure et dure ;-). On peut essayer ainsi les tables "articles", "membres", "admin", "users", etc. et les champs corespondants "login", "password", "pass", etc. Mais comment tester justement ces champs et ces noms de tables ? Nous allons utiliser par exemple cette requte :

Deviner le nom d'une table


ivig idrtileDtitreDontenu pyw rtiles rii titre vsui 979 xsyx ivig idrtileD titreD ontenu pyw rtilesDmemres 579 y ontenu vsui 97FFF79
7

En blanc, la requte initiale, en vert, ce que l'on rentre et en bleu le commentaire. On remarque que l'on n'a fait que dupliquer la requte en ajoutant juste ",membres" dans le nom des tables interroger. La requte va donc planter si jamais "membres" n'est pas le nom d'une table existante, et acher des articles dans le cas contraire. Il faut donc remplacer "membres" par le nom de la table tester.

Encore une fois, je le rappelle, tous ces exemples ne sont pas ceux que l'on utiliserait dans la ralit puisqu'ils necessitent de connatre pas mal de renseignements sur la base. Repportez-vous aux Blind SQL Injections .

Deviner le nom d'un champ dans une table connue


Nous connaissons le nom de la table (membres), nous voulons savoir le nom des champ. Nous testons :

ivig idrtileDtitreDontenu pyw rtiles rii titre vsui 979 xsyx ivig idrtileD titreD hmptester pyw rtilesDmemres 59
"champatester" est le champ dont nous voulons vrier la prsence. Si la requte russit, il existe, sinon, il n'existe pas.

Deviner un mot de passe


Dans certains cas il arrive que le contenu d'un champ soit accesible mais non ach. C'est le cas par exemple de notre formulaire de zone admin : on ne peut pas directement acher le mot de passe. Il faut donc procder par essais successifs :

ivig B pyw memres rii login a 9dmin9 exh pss vsui 979
A croiser bien sr avec une injection SQL. Si la session d'admin s'ouvre, c'est que son mot de passe commence par un 'a'. Sinon, on essaye avec 'b', puis ainsi de suite. On remonte les caractres jusqu' trouver le mot de passe complet.

Si l'on veut connatre le nombre de caractres du mot de passe, on peut utiliser l'oprateur LENGTH() comme ceci :

ivig B pyw memres rii logina9dmin9 exh vixqr@pssAaR5 FFF9


Les mthodes que nous venons de voir se font par bruteforcing, puisqu'elles ne nous permettent pas d'obtenir les informations de manire directe, mais simplement de savoir si l'on a bon ou faux. L'oprateur AS est trs pratiques dans ces situations puisqu'il permet de renomer un champ temporairement pour la requte, donc de croiser deux champs dirents.

SHOW et GRANT : obtenir tout ce que l'on veut ( ?)


Les deux oprateurs ultimes dont nous aurions besoin sont GRANT et SHOW. Ils permettent de lister la structure complte de la base, des tables, lister les utilisateurs, leurs privilges et leur mot de passe. Le seul problme majeur est qu'il est impossible de les utiliser en les croisant avec SELECT. Impossible donc d'y avoir accs dans les exemples que nous venons de voir.

1 http://www.ghostsinthestack.org/gitv2-temp-f4ejz/article-11-blind-sql-injections.html

Les petits malins auront envie d'utiliser le point virgule an d'eectuer deux requtes l'une aprs l'autre, mais un autre problme nous en empche : mysql_query(). Cette fonction interagit entre PHP et MySQL mais ne peut permettre que d'eectuer UNE SEULE requte la fois. Le point virgule est donc bannir. Et GRANT/SHOW par la mme occasion... sauf si c'est une autre fonction qui est utilse, et qui permet ce genre de choses !

Ainsi, vous sere peut-tre du mais il est impossible d'utiliser un oprateur tel que UPDATE, DROP, ou INSERT si la requte commence par SELECT. A moins, comme nous l'avons dit, que la fonction utilise le permette.

Obtenir la version du serveur


Nous pouvons utiliser les variables spciques chaque serveur SQL. Pour MYSQL, la variable

@@version

contient le nom de la version du serveur. Ainsi, SELECT @@version ache cette version. Il faut bien entendu exploiter une injection an de pouvoir utiliser cette commande. Pour les autres serveurs, c'est une autre variable. Il sut de chercher un peu dans les documentations pour les trouver.

Crer un chier
La directive

INTO OUTFILE [nom_chier] croise avec SELECT permet de crer un chier contenant

les informations de SELECT demandes. On peut donc imaginer un scnario o vous exploitez tout d'abord une injection SQL se situant dans une requte INSERT ce qui vous permet d'crire du code dans la base, puis vous exploitez une deuxime injection dans SELECT an de crer un chier contenant le code que vous avez crit dans la base. Si c'tait du code PHP, une backdoor par exemple, ou un simple script d'une ligne contenant une faille Include, vous obtiendrez un accs supplmentaire sur le serveur.

Cependant, il faut dja obtenir l'url vers laquelle crire le chier, car si vous crivez la racine du serveur, cela peut d'une part sembler louche, d'autre part ne pas tre accessible sur le serveur... En eet, si votre chier crit se trouve avant le rpertoire "www" d'Apache, c'est chu...

Utiliser un chier pour eectuer des oprations


Il est possible d'utiliser

LOAD DATA INFILE [nom_chier]

pour lire un chier et eectuer les

oprations SQL dcries l'intrieur. C'est le complment de INTO OUTFILE. Le seul problme, c'est que LOAD n'est pas compatible avec SELECT, donc inutilisable dans la grande majorit des cas.

Conclusion
Vous l'aurez compris, les injections SQL dpassent compltement le cas d'cole avec ' or ='. Il y en a des tonnes, plus ou moins adaptes ce que l'on veut faire. Les seuls limites sont celles du langage SQL, qui nous empche parfois de croiser des requtes pourtant bien pratiques... Dans un second article scripts vulnrables des informations cruciales. SQL dites "blind", ou " l'aveuglette", nous exploiterons fond le langage SQL an de faire rvler aux

2 sur les injections

Le but de cet article n'tait bien entendu pas d'inciter les gens exploiter des failles sur des sites existants, mais surtout de comprendre le fonctionnement de ce type de failles, an de mieux savoir s'en protger, par exemple.

2 http://www.ghostsinthestack.org/gitv2-temp-f4ejz/article-11-blind-sql-injections.html

Rfrences
Cet article a t crit en grande partie l'aide de mes connaissances, mais voici quelques liens qui vous permettront d'approfondir le sujet :   The Hackademy - Injections SQL

3 4

Manuel de rfrence PHP - Trs utile pour la scurisation des scripts

3 http://www.thehackademy.net/article.php?story_id=95\&section_id=57 4 http://www.php.net/

10

Vous aimerez peut-être aussi