Forensics : analyse firmware d’un routeur Alcatel

Forensics : analyse firmware d’un routeur Alcatel

Bonjour à tous!

Ayant récemment réalisé une investigation sur un routeur Alcatel, je viens résumer notre travail ici. Tout le projet est évidemment publique, n’espérez pas avoir de détails croustillants sur cette page! Un simple retour d’expérience 🙂

Contexte

Quand tu débarques et que tu comprends rien…

Commençons: voici notre point de départ, un dossier ayant l’arborescence suivante, disponible en téléchargement:

TiMOS-SR-13.0.R10/
├── boot.ldr
├── both.tim
├── cpm.tim
├── iom.tim
├── isa-aa.tim
├── isa-tms.tim
└── support.tim

Et… c’est tout! Qu’est-ce que l’on cherche? Aucune idée, probablement une compromission du routeur. D’ailleurs, on ne savait même pas que l’on travaillait sur du matériel réseau au tout début. Bien sûr, des recherches Google Qwant s’imposent et nous renseignent sur l’origine du nom étrange “TiMOS-SR-XXX”: un système d’exploitation base UNIX à destination des routeurs Alcatel Lucent, anciennement appelé TiMOS et renommé en SR-OS (quelque chose comme Service Router Operating System). De nouvelles recherches nous permettent de récupérer un tas de documentation et ainsi de cibler le modèle en question: un 7750 voir éventuellement un 7705 (car le seul selon la doc à pouvoir supporter un fichier “support.tim”).

Doc sur les fichiers firmware Alcatel

Analyse statique

En analysant les fichiers, les commandes de base type “strings” ou “file” ne donnent rien du tout. On imagine bien une extraction de fichiers vu que cela provient d’un firmware, donc certainement dans un format propriétaire venu de l’espace. C’est en fouillant internet que nous sommes tombés sur un outil permettant d’extraire des binaires et des data d’un firmware TiMOS. Ce qui nous permet de réaliser bon nombre d’extractions. Chouette, on avance!

Extraction de données depuis un firmware TiMOS

On réessaye une analyse manuelle des chaînes de caractères, on récupère beaucoup de choses comme tout ou partie des fichiers de configuration. Cependant, rien ne semble malveillant, et beaucoup de paramètres sont restés par défaut.

Extrait des confs

Par la suite on essaye de récupérer des infos sur la machine, dont le type de processeur. On se documente beaucoup mais on peine à trouver un fil rouge.

Informations sur les potentiels processeurs
Type d’architecture des procs

A ce stade là, nous avons l’impression d’avoir fait un peu le tour selon nos connaissances sur l’analyse statique. Si maintenant vous vous dites “mais qu’ils sont cons ils ont zappés le plus important!” alors c’est normal, on y reviendra plus tard…

Analyse dynamique

Evidemment, sur ce type d’investigation, un double click sur le fichier ne va pas nous emmener très loin… On a donc pensé à virtualiser notre routeur. Il s’avère un peu tricky de créer une VM à partir du firmware, alors on récupère une VM dispo sur internet et on suit la méthode suivante:

  1. Installation de KVM / Qemu (pour proc x86)
  2. Lancement de la VM avec l’image non modifiée, ce qui permet également de faire joujou en ligne de commande (lancement de la VM d’un côté, connexion telnet de l’autre):
    bash-4.4$ sudo qemu-system-x86_64 -m 1024M -enable-kvm original-sros-vm.qcow2 -serial telnet:localhost:3366,server,nowait -smp 2

    Lancement de la VM originale non modifiée
  3. On commence à corser les choses: si on essayait de décompresser l’image au format qcow2 de la VM, de trouver les fichiers firmware et de les remplacer par les notres? Pour cela, on utilise la commande “guestmount” qui permet de “deviner” les partitions et systèmes de fichiers (ici “/dev/asdfas” correspond à un truc au hasard, pour provoquer une erreur puis la recherche de partitions):

    Monter une image .qcow2 pour modifier les fichiers embarqués
  4. Ok on a monté notre image, et par chance on a un dossier “timos” qui contient les même type de fichiers firmwares que l’on possède! Est-ce que cela suffit? On a repéré un fichier boot, mais l’extension n’est pas la même. On check rapidement si les header sont identiques, ce qui permettrait de changer celui d’origine par le notre. Malheureusement, ils sont très différents.
    Check des headers des fichiers boot

    On tente alors de remplacer tous les fichiers firmware, puis on démarre! J’arrête le suspens de suite, ça ne fonctionne pas. Au démarrage, l’OS commence bien mais nous indique rapidement une erreur d’architecture de processeur. Après quelques recherches, la VM est faite pour tourner avec un processeur virtuel x86, tandis que notre firmware est fait pour une archi MIPS comme vu précédemment. Et bien on se retrousse les manches et on continue! On télécharge la bonne version de Qemu pour supporter les procs type MIPS, et on relance! Dommage, encore une fois ça ne fonctionne pas: il faut ajouter un kernel MIPS qui n’est pas présent par défaut… Rahhhh!! Il faut donc trouver un kernel MIPS Linux, le compiler avec les bons arguments, les bonnes options etc… et…

  5. Ca me soule, de toute façon ça fonctionnera pas
  6. Tu prends un café puis tu jettes ton laptop par la fenêtre. Ou l’inverse, au choix.

Analyse statique, encore…

Il y a de ça quelques lignes, je vous précisais que l’on avait sauté une étape importante. En effet, ni l’un ni l’autre n’avons pensé à scanner les binaires et les data extraits! Etant sur un routeur, j’avais laissé de côté les Manalyzer, VirusTotal et companie car ces outils ne sont pas prévus pour ces cas d’usage. Seulement, dans le scan, il n’y a pas que ça! Il existe par exemple Yara et ses millions de règles!!!! Alors on installe le tout avec le dépôt github des règles offiiels basiques, et on lance un scan:

bash-4.4$ find ./ -type f -exec yara -m ../Yara-rules/index.yar {} \; 2>/dev/null
PlugXStrings [description="PlugX Identifying Strings",author="Seth Hardy",last_modified="2014-06-12"] ./both-extract/both.tim_image_xsrbootrom.bin_data
PlugXStrings [description="PlugX Identifying Strings",author="Seth Hardy",last_modified="2014-06-12"] ./both-extract/both.tim_image_bootrom.bin_data
PlugXStrings [description="PlugX Identifying Strings",author="Seth Hardy",last_modified="2014-06-12"] ./cpm-extract/cpm.tim_image_bootrom.bin_data
PlugXStrings [description="PlugX Identifying Strings",author="Seth Hardy",last_modified="2014-06-12"] ./cpm-extract/cpm.tim_image_xsrbootrom.bin_data
maldoc_getEIP_method_1 [author="Didier Stevens (https://DidierStevens.com)"] ./cpm-extract/cpm.tim_image_mongo.bit
spyeye [author="Jean-Philippe Teissier / @Jipe_",description="SpyEye X.Y memory",date="2012-05-23",version="1.0",filetype="memory"] ./isa-aa-extract/isa-aa.tim_text.bin
RooterStrings [description="Rooter Identifying Strings",author="Seth Hardy",last_modified="2014-07-10"] ./isa-aa-extract/isa-aa.tim_text.bin
Rooter [description="Rooter",author="Seth Hardy",last_modified="2014-07-10"] ./isa-aa-extract/isa-aa.tim_text.bin
vmdetect [author="nex",description="Possibly employs anti-virtualization techniques"] ./isa-aa-extract/isa-aa.tim_text.bin
Big_Numbers1 [author="_pusher_",description="Looks for big numbers 32:sized",date="2016-07"] ./isa-aa-extract/isa-aa.tim_data.bin
RijnDael_AES_CHAR [author="_pusher_",description="RijnDael AES (check2) [char]",date="2016-06"] ./isa-aa-extract/isa-aa.tim_data.bin
RijnDael_AES_LONG [author="_pusher_",description="RijnDael AES",date="2016-06"] ./isa-aa-extract/isa-aa.tim_data.bin
vmdetect [author="nex",description="Possibly employs anti-virtualization techniques"] ./isa-aa-extract/isa-aa.tim_protocols.bin
spyeye [author="Jean-Philippe Teissier / @Jipe_",description="SpyEye X.Y memory",date="2012-05-23",version="1.0",filetype="memory"] ./isa-aa-extract/isa-aa.tim_text2.bin
RooterStrings [description="Rooter Identifying Strings",author="Seth Hardy",last_modified="2014-07-10"] ./isa-aa-extract/isa-aa.tim_text2.bin
Rooter [description="Rooter",author="Seth Hardy",last_modified="2014-07-10"] ./isa-aa-extract/isa-aa.tim_text2.bin
vmdetect [author="nex",description="Possibly employs anti-virtualization techniques"] ./isa-aa-extract/isa-aa.tim_text2.bin
Big_Numbers1 [author="_pusher_",description="Looks for big numbers 32:sized",date="2016-07"] ./isa-aa-extract/isa-aa.tim_data2.bin
CRC32c_poly_Constant [author="_pusher_",description="Look for CRC32c (Castagnoli) [poly]",date="2016-08"] ./isa-aa-extract/isa-aa.tim_data2.bin
RijnDael_AES_CHAR [author="_pusher_",description="RijnDael AES (check2) [char]",date="2016-06"] ./isa-aa-extract/isa-aa.tim_data2.bin
RijnDael_AES_LONG [author="_pusher_",description="RijnDael AES",date="2016-06"] ./isa-aa-extract/isa-aa.tim_data2.bin
maldoc_indirect_function_call_3 [author="Didier Stevens (https://DidierStevens.com)"] ./isa-aa-extract/isa-aa.tim_data2.bin
maldoc_getEIP_method_1 [author="Didier Stevens (https://DidierStevens.com)"] ./support-extract/support.tim_image_lisboa_atm.bit
maldoc_getEIP_method_1 [author="Didier Stevens (https://DidierStevens.com)"] ./support-extract/support.tim_image_lisboa_oc12.bit
maldoc_getEIP_method_1 [author="Didier Stevens (https://DidierStevens.com)"] ./support-extract/support.tim_image_xmacsync4x10g_one.bit

Et là miracle, on a plein de résultats! Bon on n’a pas encore fini, il faut enlever les faux positifs, vérifier que ceux qui restent sont réellement problématiques, et surtout trouver des listes de règles plus adaptées aux routeurs. Mais ça, je vous laisse faire, car je n’ai plus le temps pour avancer maintenant 😉 Si jamais je fais des recherches plus approfondies sur les types de malwares qui touchent le routeur en question, je ferai un petit rajout ici même =)

Sur ce, bons hacks les amis!

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

*

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.