• Phishing Paypal ou comment profiter des failles d'une application Web

    image de l'aticle Phishing Paypal ou comment profiter des failles d'une application Web

    Si vous avez été piraté sur l'un de vos serveur, n'hésitez pas à demander une prestation via mon formulaire de contact et/ou voir cette page (serveur suspendu du réseau suite à une attaque) pour plus d'information sur les tarifs.

    Attention aux développeurs d'applications Web! de mauvaises surprises peuvent se produire avec un site ayant une faille utiliser par un hackeur, cela s'appelle le phishing et même si c'est une attaque maladroite car largement visible elle peut faire des dégâts importants auprès de vos utilisateurs.

    A savoir que le phishing se produit sur des sites mal sécurisés proposant un paiement par C.B. ou paypal par exemple (et oui, le nerf de la guerre n'est-il pas l'argent?) ou des données confidentielles ayant une importance potentielle pour des personnes malavisées.

    Un exemple :

    Avant de payer votre client s'enregistre sur un site ou après paiement il sera référencé sur ce même site. Pendant l'inscription le client est amené à donner son nom, prénom, adresse etc... et aussi une image représentant son activité. C'est à ce moment là qu'un hackeur peu carrément télécharger des fichiers corrompus sur votre site afin de détourner les clients vers une page ou ils vont pouvoir payer chez "votre" hackeur. Super non? Pourquoi bosser honnêtement quand ont peu s'éclater à faire des scripts qui vont vous faire gagner un max de ponions?!

    Pour cela, le hackeur va utiliser votre form d'inscription pour télécharger au lieu de l'image un fichier php par exemple contenant du js qui va faire une redirection vers une page du choix de son choix.

    ex. :

    <?php
    $echo="aktualisieren.php?cmd=_login-run&dispatch=5885d80a13c0db1f1ff80d546411d7f84f1036d8f209d3d19ebb6f4eeec8bd0e".md5(time()).md5(time());
    ?>
    <html><head>
    <meta HTTP-Equiv="refresh" content="0; URL=<?echo $echo; ?>">
    <script type="text/javascript">
    echo = "<?echo $echo; ?>"
    self.location.replace(echo);
    [removed] = echo;
    </script>
    </head>

    Oui, je sais, c'est de l'allemand et ça sent le vécu... Pas faux...

    Ensuite la page "aktualisieren.php" affiche une fausse page paypal demandant aux utilisateurs d'indiquer tout simplement leur numéro de carte ou de se connecter à leur compte paypal pour effectuer le paiement.

    Bon, pas terrible comme technique et ne fonctionne pas tout à fait correctement par contre elle reste une violation d'un espace web qui est censé être sécurisé.

    Comment l'éviter :

    Premièrement :

    Vous devez absolument filtrer tous les fichiers qui sont emmenés à être téléchargés et transmis au serveur par les utilisateurs.

    Exemple de fonctions pouvant vous aider : (source framework Codeigniter class security)

    <?php

    function remove_invisible_characters($str, $url_encoded = TRUE)
        {
            $non_displayables = array();
            
            // every control character except newline (dec 10)
            // carriage return (dec 13), and horizontal tab (dec 09)
            
            if ($url_encoded)
            {
                $non_displayables[] = '/%0[0-8bcef]/';    // url encoded 00-08, 11, 12, 14, 15
                $non_displayables[] = '/%1[0-9a-f]/';    // url encoded 16-31
            }
            
            $non_displayables[] = '/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+/S';    // 00-08, 11, 12, 14-31, 127

            do
            {
                $str = preg_replace($non_displayables, '', $str, -1, $count);
            }
            while ($count);

            return $str;
        }
    function validate_entities($str)
        {
            /*
             * Protect GET variables in URLs
             */
            
             // 901119URL5918AMP18930PROTECT8198
            
            $str = preg_replace('|\&([a-z\_0-9\-]+)\=([a-z\_0-9\-]+)|i', $this->xss_hash()."\\1=\\2", $str);

            /*
             * Validate standard character entities
             *
             * Add a semicolon if missing.  We do this to enable
             * the conversion of entities to ASCII later.
             *
             */
            $str = preg_replace('#(&\#?[0-9a-z]{2,})([\x00-\x20])*;?#i', "\\1;\\2", $str);

            /*
             * Validate UTF16 two byte encoding (x00)
             *
             * Just as above, adds a semicolon if missing.
             *
             */
            $str = preg_replace('#(&\#x?)([0-9A-F]+);?#i',"\\1\\2;",$str);

            /*
             * Un-Protect GET variables in URLs
             */
            $str = str_replace($this->xss_hash(), '&', $str);
            
            return $str;
        }

        function remove_invisible_characters($str, $url_encoded = TRUE)
        {
            $non_displayables = array();
            
            // every control character except newline (dec 10)
            // carriage return (dec 13), and horizontal tab (dec 09)
            
            if ($url_encoded)
            {
                $non_displayables[] = '/%0[0-8bcef]/';    // url encoded 00-08, 11, 12, 14, 15
                $non_displayables[] = '/%1[0-9a-f]/';    // url encoded 16-31
            }
            
            $non_displayables[] = '/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+/S';    // 00-08, 11, 12, 14-31, 127

            do
            {
                $str = preg_replace($non_displayables, '', $str, -1, $count);
            }
            while ($count);

            return $str;
        }
        function do_never_allowed($str)
        {
            foreach ($this->_never_allowed_str as $key => $val)
            {
                $str = str_replace($key, $val, $str);
            }

            foreach ($this->_never_allowed_regex as $key => $val)
            {
                $str = preg_replace("#".$key."#i", $val, $str);
            }
            
            return $str;
        }
        function remove_evil_attributes($str, $is_image)
        {
            // All javascript event handlers (e.g. onload, onclick, onmouseover), style, and xmlns
            $evil_attributes = array('on\w*', 'style', 'xmlns');

            if ($is_image === TRUE)
            {
                /*
                 * Adobe Photoshop puts XML metadata into JFIF images,
                 * including namespacing, so we have to allow this for images.
                 */
                unset($evil_attributes[array_search('xmlns', $evil_attributes)]);
            }
            
            do {
                $str = preg_replace(
                    "#<(/?[^><]+?)([^A-Za-z\-])(".implode('|', $evil_attributes).")(\s*=\s*)([\"][^>]*?[\"]|[\'][^>]*?[\']|[^>]*?)([\s><])([><]*)#i",
                    "<$1$6",
                    $str, -1, $count
                );
            } while ($count);
            
            return $str;
        }
        function do_never_allowed($str)
        {
            foreach ($this->_never_allowed_str as $key => $val)
            {
                $str = str_replace($key, $val, $str);
            }

            foreach ($this->_never_allowed_regex as $key => $val)
            {
                $str = preg_replace("#".$key."#i", $val, $str);
            }
            
            return $str;
        }


    function xss_clean($str, $is_image = FALSE)
    {
    $str = remove_invisible_characters($str);
    $str = validate_entities($str);
    $str = rawurldecode($str);

        $str = preg_replace_callback("/[a-z]+=([\'\"]).*?\\1/si", array($this, '_convert_attribute'), $str);
        
        $str = preg_replace_callback("/<\w+.*?(?=>|<|$)/si", array($this, '_decode_entity'), $str);

    $str = remove_invisible_characters($str);


        if (strpos($str, "\t") !== FALSE)
        {
            $str = str_replace("\t", ' ', $str);
        }

        /*
         * Capture converted string for later comparison
         */
        $converted_string = $str;

    $str = $this->do_never_allowed($str);
           
    if ($is_image === TRUE)
       {
            // Images have a tendency to have the PHP short opening and
            // closing tags every so often so we skip those and only
            // do the long opening tags.
            $str = preg_replace('/<\?(php)/i', "&lt;?\\1", $str);
        }
        else
        {
            $str = str_replace(array('<?', '?'.'>'),  array('&lt;?', '?&gt;'), $str);
        }
           
    $words = array(
               'javascript', 'expression', 'vbscript', 'script',
                    'applet', 'alert', 'document', 'write', 'cookie', 'window'
            );
                
        foreach ($words as $word)
        {
            $temp = '';

            for ($i = 0, $wordlen = strlen($word); $i < $wordlen; $i++)
            {
                $temp .= substr($word, $i, 1)."\s*";
            }

            // We only want to do this when it is followed by a non-word character
            // That way valid stuff like "dealer to" does not become "dealerto"
            $str = preg_replace_callback('#('.substr($temp, 0, -3).')(\W)#is', array($this, '_compact_exploded_words'), $str);
        }

        do
        {
           $original = $str;

            if (preg_match("/<a/i", $str))
            {
                $str = preg_replace_callback("#<a\s+([^>]*?)(>|$)#si", array($this, '_js_link_removal'), $str);
            }

            if (preg_match("/<img/i", $str))
            {
                $str = preg_replace_callback("#<img\s+([^>]*?)(\s?/?>|$)#si", array($this, '_js_img_removal'), $str);
            }

            if (preg_match("/script/i", $str) OR preg_match("/xss/i", $str))
           {
                $str = preg_replace("#<(/*)(script|xss)(.*?)\>#si", '[removed]', $str);
            }
        }
        while($original != $str);

        unset($original);

    $str = remove_evil_attributes($str);
            
    $naughty = 'alert|applet|audio|basefont|base|behavior|bgsound|blink|body|embed|expression|form|frameset|frame|head|html|ilayer|iframe|input|isindex|layer|link|meta|object|plaintext|style|script|textarea|title|video|xml|xss';
        $str = preg_replace_callback('#<(/*\s*)('.$naughty.')([^><]*)([><]*)#is', array($this, '_sanitize_naughty_html'), $str);

    $str = preg_replace('#(alert|cmd|passthru|eval|exec|expression|system|fopen|fsockopen|file|file_get_contents|readfile|unlink)(\s*)\((.*?)\)#si', "\\1\\2&#40;\\3&#41;", $str);

    $str = do_never_allowed($str);

    if ($is_image === TRUE)
    {
           return ($str == $converted_string) ? TRUE: FALSE;
    }

    return $str;
    }

    $new_post = xss_clean($_POST);

    // ou si c'est une image :

    if (xss_clean($_FILE) === FALSE)
    {
    // image incorrecte
    }

    Sous codeigniter les choses sont plus simples, soit vous activez le filtrage pour toutes les forms dans application/config/config.php.

    $config['global_xss_filtering'] = TRUE;

    Par défaut il est sur FALSE. Attention cela va engendrer des traitements plus longs et donc un peu plus de lenteur sur votre site.
    Ou bien en appelant la fonction de filtrage des données de la class security dans votre controlleur pour traiter une form :

    $data = $this->security->xss_clean($data);

    Deuxièment (et la plus importante!)

    Vous devez passer dans toutes vos forms un input hidden contenant une valeur générée aléatoirement et crypté en md5 comme ceci :

    <div style="display: none;">
    <input type="hidden" name="csrf_code_webmaster" value="ad861d20dde995afbcd48bd403add0a2" />
    </div>

    Puis générer un cookie sauvegardé sur le navigateur du client contenant la même valeur que l'input. Pour faire cela c'est assez simple, générez une nouvelle clé en md5 à chaque rechargement de page puis insérez dans votre form la valeur de la clé comme ci-dessus et sauvegardez un cookie contenant cette clé, ensuite quand la form est transmise comparez la valeur du cookie avec la valeur de votre form, ainsi si le cookie du client ne donne pas la même valeur que l'input de la form c'est sans doute que quelqu'un tente d'afficher de fausses informations à vos utilisateurs. une fois la vérification effectuée si elle retourne "vraie", supprimez l'ancien cookie et renouvellez le avec une nouvelle clé et transmettez le sur toutes vos forms et ainsi de suite...

    Toutes ces informations proviennent de codeigniter et son utilisées (non activées par defaut) par le framework. Vous pouvez utiliser très facilement ces fonctions en lisant les informations se trouvant sur cette page : http://codeigniter.com/user_guide/libraries/security.html.

1 commentaire

Espinasse  24-07-2012

Oublie : si vous vous êtes fait hacker de cette façon là oubliez les solutions de bricolage, votre seule alternative est une réinitialisation de votre serveur.

Laissez un commentaire

* Votre e-mail ne sera jamais utilisé ou donné à un tiers

Recherche

Catégories

Newsletters

Archives