AttilaPHP ********* Informations : °°°°°°°°°°°°°° Langage : PHP Website : http://www.attila-php.net Version : 3.0 Problème : - Accès aux comptes users/admins Developpement : °°°°°°°°°°°°°°° AttilaPHP est un CMS avec des zones privées réservées aux utilisateurs, une partie admin, un forum,... A son installation, deux utilisateurs avec un rang spécial sont créés. Le premier, ayant l'id 1, est l'administrateur, il a tout les droits, bien sûr accès à la partie admin,... : INSERT INTO CE_visiteurs VALUES( '1', 'pouet@pouet.com', 'attila', 'attila', '1', 'YYYYYYYYYYYYYXXXXX'); Le deuxième, qui a comme id 14, est l'utilisateur qui n'est pas utilisateur. C'est l'utilisateur par défaut qui sera attribué aux visiteurs non-enregistrés, non-membres. D'ailleurs son nom est "Visiteur" : INSERT INTO CE_visiteurs VALUES( '14', '', 'Visiteur', 'xxxx', '0', 'YYYNYYNYNNNNXXX'); *Note : Ces requêtes sont tirées du fichier gosql.* Voyons maintenant, dans le fichier www/global.php3, la fonction qui sera executée pour authentifié les admins commes les utilisateurs, la fonctions get_identity() : --------------------------------------------------------------------------------------------------------------------------- function get_identity() { global $cook_id, $TABLE_CURRENT_VISITS,$base; $table=$TABLE_CURRENT_VISITS; connect_db(); if (!$cook_id) { /** no cookie set? Visitor! **/ add_log("visit",14); $query="SELECT * FROM $table Where visiteur=14"; $resu2=mysql_db_query($base,$query); if (mysql_fetch_row($resu2)==0) { $query="INSERT INTO $table (id,visiteur) VALUES ('0','14')"; /** If no entry for visitor, insert one **/ $resu=mysql_db_query($base,$query); } $query="SELECT * FROM $table Where visiteur=14"; $resu=mysql_db_query($base,$query); $row=mysql_fetch_array($resu); $valid=$row["ID"]; setcookie("cook_id",$valid); return(14); exit; } $query="SELECT * FROM $table Where ID=$cook_id"; $resu=mysql_db_query($base,$query); $row=mysql_fetch_array($resu); $visiteur=$row["visiteur"]; return($visiteur); } --------------------------------------------------------------------------------------------------------------------------- On voit d'abord que si la variable $cook_id (au nom, ça serait bien un cookie...) est vide, et donc qu'on est pas loggé, on est considéré comme le "Visiteur", et la fonction retourne "14" (l'id d'un visiteur), puis se stoppe. On voit que dans la table sql utilisée ici, le champ contenant l'id a comme nom "visiteur". Si la variable $cook_id est bien là, qu'on est donc loggé, la fonction exécute la requête sql : [SELECT * FROM $table Where ID=$cook_id] , en extrait le champ "visiteur" (l'id), et le retourne. Voyons maintenant comment cette fonction est utilisée dans les deux fichiers réservés aux utilisateurs (www/user.php3, www/user_action.php3) : ------------------------------------------------------------------------- $identite=get_identity(); if ($identite==14) {header("Location: http://$weburl/index.php3"); exit;} ------------------------------------------------------------------------- Tant que ce que la fonction get_identity() retourne (l'id, donc) n'est pas 14, l'id du visiteur, alors on est considéré comme membre, et on est pas redirigé vers l'index. Maintenant voyons son utilisation dans les fichiers réservés à l'admin (www/god_action.php3,www/god.php3) : -------------------------------------------------------------- $identite=get_identity(); if ($identite!=1) {header("Location: http://$weburl"); exit; } -------------------------------------------------------------- Tant que l'id est différent de 1 (l'id admin), on n'est pas considéré comme admin, et on est redirigé vers la page principale. Résumons : - Pour être membre, il faut avoir un autre id que 14 - Pour être admin, il faut avoir l'id 1 Forcemment, si on est admin, on est aussi membre. Revenons à la ligne de la fonction get_identity() qui va chercher les renseignements sur l'utilisateur : ------------------------------------------------ $query="SELECT * FROM $table Where ID=$cook_id"; ------------------------------------------------ La variable $cook_id ne subit aucun filtre, et n'est pas délimitée par des ' ou des ". C'est donc une cible parfaite pour de l'injection SQL. Comme on sait que l'id le plus avantageux, qui est le champ "visiteur" de cette table, est 1, il suffit d'envoyer sur le site, sur n'importe quelle page, un cookie avec comme nom "cook_id" et comme valeur "0 OR visiteur=1" pour avoir accès à la partie membre et admin. En effet, la requête deviendra alors : --------------------------------------------- SELECT * FROM $table Where ID=0 OR visiteur=1 --------------------------------------------- et l'id envoyé par get_identity() sera forcemment "1". Solution : °°°°°°°°°° Un patch est disponible sur http://www.phpsecure.info. Il faut remplacer la ligne : ------------------------------------------------ $query="SELECT * FROM $table Where ID=$cook_id"; ------------------------------------------------ de la fonction get_identity() dans le fichier www/global.php3 par : -------------------------------------------------- $cook_id = addslashes($cook_id); $query="SELECT * FROM $table Where ID='$cook_id'"; -------------------------------------------------- Credits : °°°°°°°°° Auteur : frog-m@n E-mail : leseulfrog@hotmail.com Website : http://www.phpsecure.info Date : 20/08/2003