Blog ENI : Toute la veille numérique !
🐠 -25€ dès 75€ 
+ 7 jours d'accès à la Bibliothèque Numérique ENI. Cliquez ici
Accès illimité 24h/24 à tous nos livres & vidéos ! 
Découvrez la Bibliothèque Numérique ENI. Cliquez ici

Malwares : étude des codes malveillants

Introduction

Il est illusoire de penser qu’un chapitre suffirait pour couvrir l’étude de codes malveillants. 

La multiplicité des langages de programmation, des systèmes d’exploitation, des architectures de processeurs, l’utilisation de programmes légitimes de façon détournée, la très grande variété de vulnérabilités font qu’il existe une quasi-infinité de combinaisons qui rendent une approche systématique peu efficace, voire impossible.

De plus, il est courant de penser, à tort, qu’un antivirus est une solution de protection.

En effet, un antivirus n’est pas un bouclier qui vous empêche toute contamination, il remplit plutôt une fonction de vaccin : il vous empêche d’exécuter des malwares connus.

L’année 2020 fut une brillante démonstration de la limite de la vaccination : aucun vaccin ne protégeait de la Covid-19, malgré l’existence de nombreux vaccins, et être vacciné contre le tétanos ne vous protégeant pas d’une infection par un coronavirus.

Deux questions se posent donc :

« Dans quel cas est-il impossible d’élaborer un vaccin efficace ? » et « À quoi suis-je toujours vulnérable ? »

Pour répondre, il faut comprendre les limites des techniques de détection de malwares et savoir qu’en moyenne un antivirus ne vous protège que d’environ un tiers des codes malveillants.

L’analogie du vaccin fonctionne parfaitement pour les codes malveillants et puisque vous n’êtes jamais protégé contre 100 % des menaces, le plus simple reste de ne pas s’y exposer.

Ainsi, la détection d’un malware dans votre système d’information n’est...

Qu’est-ce qu’un malware ?

Un code malveillant, en anglais malicious software, souvent abrégé en malware, est un programme réalisant des actions malveillantes.

Une définition qui n’aide pas vraiment à avancer.

Le contenu et le comportement d’un malware dépendent grandement du but de son auteur.

L’ensemble des outils, programmes, processus, techniques, tactiques d’un attaquant ou groupe d’attaquants est abrégé TTP (en anglais : Tactics, Techniques, and Procedures).

Il est possible de classer les codes malveillants selon des méthodes différentes. Dans notre langage quotidien, nous nous référons à plusieurs d’entre elles.

Il n’est pas rare d’entendre parler de vers (imageant la propagation d’une machine à une autre), ce qui correspond à l’approche épidémiologique ; de credential stealers (programmes de vol d’identifiants), une approche centrée sur le but de l’attaquant ; ou encore de backdoors (portes dérobées), ce qui correspond à la description technique de la modification apportée au système pour en garder le contrôle.

La meilleure classification

C’est une question complexe et la réponse, à défaut d’être 42, est « celle qui vous convient » ou, pour les plus créatifs, « la vôtre ».

Cependant, les classifications existantes ont bien entendu toutes leur intérêt.

Une approche épidémiologique prend en compte les facteurs favorisant la propagation d’une infection et met en scène l’agent pathogène, l’hôte, le milieu, les vecteurs de transmission, etc.

On peut ainsi réaliser un classement, une taxonomie pour les puristes. On retrouve d’ailleurs dans notre quotidien les appellations virus, vers, vecteurs de propagation, pour parler de la menace informatique.

L’avantage de cette approche, c’est qu’elle permet d’anticiper la façon de contenir la menace en prenant en compte l’éventuelle progression de la menace dans le parc informatique. 

Des approches techniques du genre MITRE Att&ck ou la CKC (Cyber Kill Chain) de Lockheed Martin permettent de classer les malwares selon les traces qu’ils laissent sur le système et les combinent avec la phase de l’attaque en cours.

Ces étapes sont les mêmes que celle régissant un pentest : reconnaissance, énumération, exploitation, installation, mouvements latéraux, etc.

La CKC reste à un niveau macro, la matrice Att&ck zoomant jusqu’à l’artefact système. 

Les malwares sont donc classés, par exemple, selon l’utilisation de program startup, des liens symboliques ou encore de l’accès au clipboard (presse-papiers en français, ce dernier contenant les informations lors des copier-coller).

Note sur la matrice MITRE Att&ck : cette dernière est très orientée système...

La détection par base de connaissance

Spoiler : cela ne fonctionne pas.

Une des approches les plus simples est de maintenir une liste contenant tous les codes malveillants passés, présents et futurs.

Grâce à une fonction dite de somme de contrôle (ou hash en anglais), il est possible de vérifier l’intégrité d’un fichier. Une telle fonction, par exemple SHA256, respecte un cahier des charges strict en trois points :

  • Deux fichiers différents ne peuvent pas avoir la même somme de contrôle.

  • Un fichier ne peut avoir qu’une unique somme de contrôle.

  • On ne peut pas, à partir de la somme de contrôle, retrouver le contenu du fichier d’origine.

Ce qui est vérifiable empiriquement avec le test ci-dessous :

$ cat fichier1 
Le contenu du fichier 1. 
 
# sans majuscule au debut 
$ cat fichier1.bis  
le contenu du fichier 1. 
 
# avec aussi une majuscule à Fichier ; après tout, pourquoi pas 
$cat fichier1.ter 
Le contenu du Fichier 1. 
 
# autre chose rien à voir 
$ cat fichier2 
Le contenu du fichier 2, c'est à peu près la même soupe. 
A 2kPi près, dira-t-on. 
 
$ sha256sum fichier* 
a464400a766b072fb122c6d950b605442b375a18458b6be23c9b1c89c80f4a27  fichier1 
27d978894819ae58cd33d556157766773ab53933c84b161aec5d4486fbb09895  fichier1.bis 
6afbbdaacb44d8f6d4eb7cee343d00791498d820e9b6273cb370921046becdaa  fichier1.ter 
a07b45f1ed19abf55c09206d2cf640b69f044700c830732e3ecc3da8bfc01bef  fichier2 

On constate que chaque somme de contrôle est complètement différente. La moindre modification du contenu, même l’ajout d’un espace, provoque un changement radical dans le résultat.

La première approche, vous l’aurez compris...

Correspondances partielles

La faiblesse principale des fonctions de hachage dans leur utilisation en base de connaissance réside dans le fait qu’une modification du fichier modifie tout le hash. C’est parfait pour en garantir l’intégrité, mais ce n’est pas pratique pour ce qu’on voudrait faire : savoir si deux fichiers sont partiellement ou totalement similaires.

De tels algorithmes existent et sont notamment utilisés dans les correcteurs orthographiques pour applications de messagerie ou autres traitements de texte, le plus connu étant la distance de Levenshtein : https://en.wikipedia.org/wiki/Levenshtein_distance#Computing_Levenshtein_distance

Les regex (Regular Expressions) peuvent également permettre d’identifier une correspondance partielle.

De tels algorithmes peuvent s’appliquer au calcul des hashs, on parle alors de fuzzy-hashing.

L’algorithme le plus répandu consiste à calculer les context-triggered piecewise hashes, son implémentation la plus connue est SSDeep : https://ssdeep-project.github.io/ssdeep/index.html

Explication complète, présentation et "Paper" en anglais sont disponibles ici : https://dfrws.org/presentation/identifying-almost-identical-files-using-context-triggered-piecewise-hashing/

En simple, ou si vous n’avez pas lu le "Paper", SSDeep calcule des hashs sur des "tranches" du fichier ; vous allez voir, c’est très parlant.

L’affichage du résultat est sous forme blocksize:hash:hash,filename.

Comparons nos fichiers basic_malware_mutated.sh et basic_malware.sh écrits dans la section précédente et constatons que des parties du hash sont similaires.

$ssdeep basic_malware_mutated.sh basic_malware.sh 
 ...

Structure d’un PE et imphash

Pour introduire le prochain concept nommé imphash, il faut étudier le format des binaires exécutables Windows.

Nul besoin d’entrer dans les détails, la version simplifiée du schéma ci-dessous devrait suffire :

images/12EP03.png

Vous trouverez la documentation complète ici : https://docs.microsoft.com/en-us/windows/win32/debug/pe-format?redirectedfrom=MSDN

Un binaire PE commence par l’en-tête PE, à savoir les lettres "MZ". PE (Portable Executable) est le format propriétaire Windows pour les fichiers exécutables, bibliothèques de développement et autres objets exécutables liés. On le reconnaît facilement via l’extension de fichier .exe ou .dll ou par les deux premiers octets du fichier brut "MZ".

Le binaire est découpé en sections où sont rangés les différents contenus. La section .text est la section principale, la section .data contient les variables, .rdata contient les contenus annexes (en readonly), et la section .rsrc les ressources additionnelles (par exemple, les images).

Si vous avez déjà fait du C, du PHP, du Java ou du Python, vous savez certainement que la première chose à faire dans votre code est d’importer les librairies nécessaires au programme, ce afin que le compilateur prépare les dépendances entre votre code et les librairies de votre ordinateur.

Un binaire doit déclarer les fonctions qu’il compte utiliser.

Ces imports sont stockés dans une table d’imports (généralement dans .rdata), un pointeur du data directory y conduit.

La table d’imports permet d’avoir une idée générale du comportement d’un exécutable. Dans notre cas :

"CloseHandle","CopyFileA","CopyFileW","CreateDirectoryW"...

Entropie et packing

Puisqu’il est difficile d’échapper aux méthodes combinées de impfuzzy + fuzzy hash, un attaquant désirant ne pas être détecté devra modifier le binaire dans son intégralité pour atteindre son but.

Une approche est de réaliser un second binaire appelé wrapper. Ce dernier n’a qu’une mission : servir de caisse de transport opaque pour notre binaire. Un binaire dans un binaire ? Binaire-ception ! On peut traduire les verbes « to pack » et « to wrap » par « emballer », on vient recouvrir le binaire de notre « papier cadeau spécial » : un autre binaire.

À ce stade, il nous faut parler d’entropie, un concept mathématique et physique.

Pour la formule qui nous intéresse en informatique, l’entropie de Shannon, il s’agit d’un score entre 0 et 8.

En simplifiant, le score représente le nombre de bits qu’il faut pour pouvoir écrire toutes les valeurs contenues dans un fichier.

Par exemple, la phrase « Portez ce vieux whisky au juge blond qui fume » utilise toutes les lettres de l’alphabet ainsi que le caractère espace.

Il faut donc 27 caractères pour écrire ce message. Si on leur donne à chacun un numéro entre 0 et 26, on peut écrire le message au format binaire.

On n’a pas besoin des 8 bits pour coder les valeurs de 0 à 27, seuls 5 sont nécessaires :

0000 0000 = 0

0001 1011 = 27

Si on utilise 4 bits, on ne peut écrire que 16 valeurs (1111 = 15), 5 bits permettent d’écrire 32 valeurs (11111 = 31).

Le calcul mathématique de l’entropie est log2(27) = 4.754887502163469.

L’entropie ici est donc...

Analyses et outillage

Chaque type de fichier demande un outillage spécifique, sauf chez quelques spécimens qui font tout avec hexdump et leurs scripts C ou Python.

Il existe des distributions Linux dédiées telles que REMNux (la distribution orientée reverse engineering, disponible sur https://remnux.org/) ou Tsurugi (la distribution orientée DFIR - Digital Forensic and Incident Response, https://tsurugi-linux.org/).

Mais une bonne vieille Debian fonctionne tout aussi bien, si vous prenez le temps de la configurer et d’y ajouter quelques packets.

La plupart sont disponibles dans les dépôts Debian (apt) ou dans les dépôts pip, voici un extrait de notre sélection personnelle :

bless

https://github.com/afrantzis/bless

Éditeur hexadécimal avec interface graphique

ssdeep

https://github.com/ssdeep-project/ssdeep

Fuzzy-hashing de fichiers

EVi

https://github.com/twpZero/EVi

Visualisation graphique d’entropie

impfuzzy

https://github.com/JPCERTCC/impfuzzy

Fuzzy-hashing des tables d’import PE

Gdb + peda

https://github.com/longld/peda

Débugueur + extention utile

pdfid

https://github.com/Rafiot/pdfid

Étude des PDF

radare2

https://github.com/radareorg/radare2

Étude des shellcodes

oletools

https://github.com/decalage2/oletools

Étude des documents Office

OfficeMalScanner

http://www.reconstructer.org/code/OfficeMalScanner.zip

Étude auto des documents Office

peframe

https://github.com/guelfoweb/peframe

Étude des PE

pefile

https://github.com/erocarrera/pefile

Étude des PE

yara

https://github.com/VirusTotal/yara

Comme un grep en hexa

vt-cli

https://github.com/VirusTotal/vt-cli

Le client pour VirusTotal

CAPE

https://github.com/kevoreilly/CAPEv2

Extraction des fichiers de config et des payloads

Cuckoo

https://github.com/cuckoosandbox/cuckoo

Sandbox, (nous utilisons VirtualBox)

VirtualBox

apt-get install virtualbox

Pour...

Simulations et profilage

Une fois l’analyse de notre malware terminée, la phase de classification commence. Pour déterminer la malveillance d’un code, il est possible de corréler son activité avec les étapes d’une attaque.

La réalisation d’une attaque, que ce soit dans le cadre d’un audit de sécurité ou d’une attaque réelle, se fait par étapes. Par exemple :

  • Reconnaissance

  • Énumération

  • Exploitation

  • Post-exploitation

  • Élévation de Privilège

  • Persistance  

  • C2 : Control and Command (Canal de communication pour piloter les machines infectées)

  • Action sur objectif

Ces étapes peuvent varier légèrement selon les modèles, mais l’idée reste généralement la même. Il existe donc des points communs entre le PTES, l’OSSTMM, la CKC et la MITRE Att&ck.

La CKC est plutôt générique et s’applique très bien de façon agnostique et sur tout type de menace : Mac, Linux, Windows, réseau, OT, IoT, mobile…

https://www.lockheedmartin.com/en-us/capabilities/cyber/cyber-kill-chain.html

Le niveau de détail peut cependant varier. Ainsi, pour la matrice MITRE Att&ck, le nombre d’étapes augmente et chacune est détaillée.

Cependant, cette spécialisation se fait à un prix, car pour être exhaustif sur les techniques d’attaques il faut choisir une technologie sur laquelle elles s’appliquent. Ainsi, MITRE Att&ck choisit sans surprise Windows, perdant au passage la possibilité de modéliser avec précision les attaques réseau (ARP, IP spoofing, buffer overflow, memory leaks…).

Pour la persistance sous Windows, il existe des variantes pour arriver à des résultats "similaires" : clés...