Serveur web mutualisé (4/5) : Problème de sécurité

I. Présentation

Dans nos précédents billets sur ce sujet, nous avons vu ce qu'était un serveur web mutualisé, leurs avantages et leurs limites et nous avons également vu leur architecture et fonctionnement général au niveau technique. En fin de la construction de cette architecture, nous avons été confronté à un problème de droit qui nous a forcé à élargir un peu plus les droits par défaut des répertoires web des clients. A travers ce post je vais montrer en quoi cet ajout de droit pose un problème majeur au sein des serveurs web mutualisés utilisant le couple habituel Apache/PHP, ce qui est le cas de la plupart d'entre-eux !

II. États des lieux

Nous savons donc que pour fonctionner, les utilisateurs uploads leurs fichiers via un service FTP qui leur est dédié est par lequel ils accèdent à leur espace web qui est chrooté. Pour que ces fichiers soient immédiatement lisibles et traités par Apache via HTTP, nous sommes contraints de donner les droits de lecture à Apache sur les dossiers et fichiers en question (logique). On a donc un cas de figure comme celui-ci :

drwxr-xr-x root       root       /storage
drwxrwxrwx www-data   www-data   /storage/web
drwxrwx--- user_blog1 www-data   /storage/web/www-blog1
-rwxrwxr-x user_blog1 user_blog1 /storage/web/www-blog1/index.php
drwxrwx--- user_blog2 www-data   /storage/web/www-blog2
-rwxrwxr-x user_blog2 user_blog2 /storage/web/www-blog2/index.php

Note : J'affiche ici les droits des dossiers et sous dossiers avec les informations qui nous intéressent uniquement. Vous retrouvez l'arborescence complète et la façon dont elle a été construite dans le précédent billet.

On voit donc que www-data possède les droits de lecture et de création sur les dossiers des clients (www-blog1 et 2), ce qui est normal car les services webs sont souvent obligés de créer dossiers/fichiers lors de leur déploiement par exemple (le cas le plus parlant étant WordPress). Les fichiers contenus dans ces dossiers sont, via la configuration de notre serveur FTP, lisibles par tous dans le but qu'apache puisse directement les lire étant donné qu'il n'est ni le groupe ni le propriétaire des fichiers à leur uploads.

En somme, les fichiers appartiennent à leur utilisateurs (user-blog1 par exemple) lorsqu'ils sont uploadés via FTP mais doivent tout de même être lus par apache qui agit avec l'utilisateur www-data. On met donc les droits "other" en read et executable.

III. Droits Apache & PHP

Seulement voilà, quand on récapitule le tout :

  • L'utilisateur upload un script PHP ou une page HTML via son FTP, il utilise ses propres droits.
  • Il demande ensuite via une requête HTTP au serveur web Apache d'aller lire son fichier html ou d'aller exécuter son script PHP
  • Apache utilise donc l'utilisateur "www-data" pour aller exécuter le script PHP de l'utilisateur en question.

Et c'est sur cette dernière étape qu'il y a un soucis de sécurité majeur. Bien que notre utilisateur n'ait pas de droit spécifique hors de son chroot, il demande à www-data (Apache) d'exécuter le script PHP qu'il a lui même écrit puis uploadé sur le serveur. Le script s’exécute donc au niveau du serveur web non pas avec les droits restreints de l'utilisateur, mais avec les droits de www-data qui n'est restreint à aucun chroot et à des limitations beaucoup plus faibles sur le serveur. Par exemple, nous avons vu que tous les répertoires web des clients doivent être lisibles par www-data (Apache), donc si un utilisateur demande à Apache d'exécuter un script qui va lire le contenu des fichiers du voisin puis d'afficher ce contenu sur une page web, il pourra le faire car même si lui ne dispose pas des droits, www-data, qui exécute son script, les possède.

III. Exploitation

Ce n'est peut être pas trés clair. Pour vous montrer la chose je vais vous donner un exemple plus clair. Nous avons pour l'instant un index.php dans le répertoire du blog1. Admettons que le répertoire du blog2 possède également un fichier index.php mais également un fichier "config.php" qui n'est pas destiné à être lu via une requête HTTP web. Notre utilisateur du blog2 étant très prudent, il aura même pris soin de mettre un fichier .htaccess demandant une authentification à l'accès de ce fichier config.php.

Considérons que l'espace web du blog1 a été volé par un pirate mal intentionné, cet utilisateur n'a qu'à utiliser les formidables possibilités de php pour aller voir ce qu'il se passe sur le serveur. On construit par exemple un fichier "shell.php" contenant ces lignes :

<?php
$retour=shell_exec ('pwd');
echo $retour
?>

On va ensuite sur un navigateur pour aller lire ce fichier (le faire exécuter par ww-data plus exactement) via l'URL (en suivant notre arborescence du post précédent) http://www.blog1.fr/shell.php , voila le retour que nous avons :

SRVMUT04et voilà, on vient tout simplement de faire exécuter une commande linux à l'utilisateur www-data via son propre shell en utilisant la fonction "shell_exec" de PHP (cf ce tutoriel sur la fonction shell_exec). Notre pirate réfléchit un peu et pense que si lui se situe dans le répertoire www-blog1, il doit y avoir quelqu'un qui se trouve dans le www-blog2, nous allons tester. On réécrit notre shell.php en y mettant cela :

<?php
$retour=shell_exec ('ls /storage/web/www-blog2');
echo $retour
?>

On exécute à nouveau en nous rendant sur le script via un navigateur :

SRVMUT05On voit donc ici que le répertoire du blog2 contient deux fichiers, un config.php et un index.php. Il ne nous reste plus qu'à aller lire le premier :

<?php
$retour=shell_exec ('cat /storage/web/www-blog2/config.php');
echo $retour
?>

Résultat :

SRVMUT07

Et voilà, on a le contenu du fichier config.php.

Et le .htaccess alors ??

Le .htaccess permet de fixer des barrières à la lecture du fichier si nous l'attaquions par navigateur (autrement dit si nous avions utilisé l'URL http://www.blog2.fr/config.php.) Cependant ce n'est pas ce que nous avons fait ici. Ici nous avons fait exécuter un script PHP à www-data (pour profiter de ses droits sur le serveur) qui lançait donc une commande Linux. Le .htacces n'est donc plus du tout actif dans ce cas de figure.

Ce qui pose problème c'est bien sûr le fait que www-data utilise ses propres droits pour exécuter du code qui a été rédigé par un utilisateur auquel nous en avons donné moins. C'est en quelque sorte une élévation de privilège. L'utilisateur utilise des droits qui ne sont pas les siens pour exécuter du code sur le serveur. Pour ceux qui ont l'esprit rapide, on peut également aller lire le fichier /etc/passwd qui est lisible par tous par défaut sur un système Linux :

<?php
$retour=shell_exec ('cat /etc/passwd');
echo $retour
?>

Résultat :

SRVMUT08Note : Le résultat est plus lisible si on affiche le code source de la page de résutlat.

Et on est ici face à un problème majeur de la configuration d'un serveur web mutualisé via Apache/PHP, c'est le fonctionnement de base du couple qui pose problème ici et qui donne des privilèges et des droits très dangereux aux utilisateurs standards.

Alors oui, on pourrait tout simplement désactiver cette fonction "shell_exec" de PHP pour que les utilisateurs ne puissent pas agir ainsi, mais il existe bon nombre de fonctions qui pourraient faire la même chose, comme fopen qui permet d'ouvrir/de lire des fichiers par exemple. De plus, si vous avez plusieurs centaines de clients sur votre serveur web mutualisé, il y a de bonnes chances pour que quelques uns d'entre eux utilisent et expérimentent des fonctions un peu dangereuses qu'ils vous demanderont d'activer (c'est eux qui payent, on ne va pas leur refuser !). Et c'est là un problème tout aussi important, si on active une fonction dans PHP ou un paramètre un peu dangereux, nous n'avons qu'un seul fichier de configuration PHP qui est valable pour tous. On peut donc activer la fonction pour un client "de confiance" (s'il ne se fait pas pirater encore...) mais elle sera également activée pour tous les autres (y compris ceux qui mettent 123456 en mot de passe de compte FTP et les apprentis sorciers en PHP). Sans compter que si on désactive des fonctions de PHP telles que "fopen", PHP ne pourra plus lire de fichiers, il perd alors grandement de son intérêt pour certaines utilisations "standards"

On ne va donc pas trier nos clients à l'entrée ou les fonctions PHP à activer selon les demandes. Il faudrait pour régler ce problème traiter le fond du problème qui est le fichier de configuration PHP unique pour tous les utilisateurs et l'exécution des scripts PHP rédigés par l'utilisateur par www-data qui dispose de droits bien trop avancés sur le serveur.

Dans un prochain tutoriel, nous essaierons de trouver des pistes de résolution à ces problèmes mais je vous invite vivement à commenter cet article si vous avez des propositions, suggestions ou réflexions à ce sujet.

Les autres articles :

Partagez cet article Partager sur Twitter Partager sur Facebook Partager sur Linkedin Partager sur Google+ Envoyer par mail

Mickael Dorigny

Co-fondateur d'IT-Connect.fr. Auditeur en sécurité des systèmes d'information chez Amossys

    mickael has 484 posts and counting.See all posts by mickael

    2 pensées sur “Serveur web mutualisé (4/5) : Problème de sécurité

    Laisser un commentaire

    Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

     

    Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.