La lutte contre les rootkits en environnement Windows 64-bit

Date : 30 Octobre 2012

Introduction

Dans la lutte contre les malwares, les éditeurs antivirus se heurtent principalement à deux difficultés :

  • La « primo-détection » : les vers et autres chevaux de Troie sont de plus en plus nombreux et polymorphiques. Il est donc aujourd’hui illusoire de les détecter à partir d’une base de signatures. Les éditeurs privilégient donc de plus en plus souvent des détections euristiques (étude du comportement dans une sandbox par exemple), mais toutes ces formes de détection sont faillibles.
  • La détection a posteriori : on suppose ici que l’antivirus n’a pas su détecter un malware à temps et qu’il est désormais installé et dissimulé sur le système.

C’est ce second scénario qui nous intéresse dans le présent article. En effet, nous revenons sur un rapport de McAfee qui dresse un état de l’art sur la lutte contre les « rootkits » en environnement Windows, et en particulier sur les systèmes 64-bit.
 

Rappel sur les rootkits

Un grand nombre de codes malveillants un tant soit peu sophistiqués intègrent des fonctionnalités dites de type « rootkit ». Pour rappel, le rootkit est un composant qui est parvenu à s’exécuter avec le plus haut niveau de privilèges (mode noyau ou ring 0) et qui, de part cette position favorable, est en mesure de dissimuler toutes sortes d’activités aux logiciels antivirus qui, eux, s’exécutent en espace utilisateur (ou ring 3). Pour cela, le rootkit va modifier en temps réel (patching) la mémoire du noyau et notamment redéfinir (hooking) des fonctions système de façon à ce qu’elles ne laissent pas apparaître l’empreinte de la présence du malware sur le système (masquage de processus, de fichiers …). A titre d’exemple, il est relativement facile de dissimuler complètement la présence d’un processus en appliquant un « hook » sur la fonction système « NtQuerySystemInformation ».

Les malwares comportant des fonctionnalités de type « rootkit » sont donc bien souvent considérés comme les plus dangereux car ce sont les plus difficiles à détecter et à éradiquer.
 

Un peu d’histoire : de Windows 32-bit à Windows 64-bit

Depuis les origines des versions 32-bit de Windows (Windows 95 fut la première version 32-bit grand public du système), les fonctions bas niveau du noyau permettant notamment d’accéder aux disques et de gérer le trafic réseau ont souvent été incomplètes ou peu documentées. Si bien que beaucoup d’éditeurs tiers de logiciels ont dû effectuer du « reverse engineering » sur le noyau lui-même et avoir recours au patching afin de faire fonctionner correctement certains de leurs logiciels. Sont venus ensuite les malwares et en particuliers les « rootkits » qui ont utilisé ces mêmes techniques pour se dissimuler. Durant toutes ces années, Microsoft n’a jamais été en mesure d’implémenter des protections contre les rootkits dans le noyau de Windows car il était impossible de différencier le patching/hooking légitime de celui employé par les malwares.

Avec le développement des architectures 64-bit, Microsoft a décidé de faire table rase du passé et d’implémenter des protections fortes au niveau du noyau Windows. Il existe deux protections majeures apportées par les éditions 64-bit du système :

  • Protection préventive : Il est impossible sous Windows 64-bit de charger des pilotes dont la signature numérique n’a pas été vérifiée. Nous avons vu ces dernières années que ce type de protection était finalement peu satisfaisant :
    • Certains malwares avancés comme Stuxnet sont parvenus à installer un rootkit via un driver signé par des certificats légitimes (des certificats appartenant à Jmicron et Realtek ont ainsi été utilisés frauduleusement en 2010). Plus récemment en 2012, on a découvert que le malware Shamoon utilisait un pilote commercial, et donc disposant d’une signature numérique valide de la société Eldos, pour effacer des données.
    • Pour des raisons pratiques, cette vérification peut être désactivée via un paramètre du boot loader de Windows. Certains bootkits (il s’agit de rootkits qui s’installent en modifiant le secteur d’amorçage du système) comme celui utilisé dans le botnet TDL-4 sont ainsi capables de désactiver la vérification des signatures de pilotes dans le boot loader puis de se charger au cœur du système.
  • Protection réactive : Le noyau Windows dispose d’un module dont le but est d’empêcher en temps réelle la modification illégale (patch) de certaines zones mémoire critiques. Ce module de protection est généralement appelé PatchGuard, et c’est celui qui nous intéresse ici.
     

Présentation de PatchGuard

PatchGuard est un composant du noyau 64-bit de Windows qui se charge de vérifier, à intervalles aléatoires, l’intégrité de certaines zones mémoire clés. Lorsqu’il détecte une anomalie dans une de ces zones, il déclenche un écran bleu (Blue Screen Of Death) avec le code « 0x109 » pour signaler que l’intégrité du système a été compromise. PatchGuard est notamment capable de valider :

  • Les modules système (NTOS, NDIS, HAL …).
  • La SSDT (System Service Dispatch Table) : c’est la table qui permet de retrouver en mémoire le code associé aux divers appels systèmes (le hooking de cette table est l’une des techniques les plus utilisées par les rootkits)
  • La GDT (Global Descriptor Table) : c’est la table qui permet la conversion des adresses mémoire virtuelles utilisées par les processus en adresses mémoire physiques.
  • L’IDT (Interrupt Description Table) : C’est la table qui permet la gestion des interruptions matérielles ou logicielles.
  • Les registres de contrôle MSR (Model-Specific Register) : ce sont des registres des processeurs Intel qui facilitent notamment le traçage et le débogage des exécutions, mais qui permettent aussi d’activer/désactiver certaines fonctionnalités du processeur.

Pour éviter que des modules ou pilotes tiers le neutralisent, PatchGuard est un code extrêmement complexe et sophistiqué :

  • Il emploie des techniques d’obscurcissement de code (obfuscation) et de randomisation à tous les niveaux, que ce soit lors de son initialisation ou pendant son fonctionnement,
  • Il vérifie en permanence sa propre intégrité,
  • Le code est auto-déchiffrant en mémoire, il est aussi capable de s’auto-modifier,
  • Plusieurs instances des routines de validation peuvent être exécutées simultanément et placées dans des zones mémoire aléatoires,
  • Le code utilise des procédures système à exécution différée (DPC),
  • Toutes les étapes d’initialisation et de vérification comprennent de nombreuses redirections dans le fil d’exécution, incluant notamment la génération volontaire d’exceptions.
  • PatchGuard est désactivé lorsque l’on passe le noyau en mode de débogage.

PatchGuard est à notre connaissance la seule implémentation d’une protection du noyau d’un système d’exploitation contre les modifications intempestives. En outre, la complexité de son code a fait qu’il existe aujourd’hui très peu de rootkits opérationnels sur les systèmes 64-bit. Mais pour combien de temps ?
 

Les limites de PatchGuard

La principale limite de PatchGuard est qu’il est exécuté avec le même niveau de privilèges (ring 0) que les drivers malveillants ou rootkits qu’il est sensé surveiller. Par conséquent, la situation en mémoire se compare à une course ou un combat d’égal à égal dans lequel le vainqueur sera celui qui arrivera à désactiver l’autre en premier. En particulier, PatchGuard n’étant pas actif en permanence, il peut potentiellement être désactivé dans un intervalle entre deux exécutions.

Dans son rapport, McAfee rappelle quelques attaques théoriques sur PatchGuard déjà illustrées par des chercheurs et qui ont depuis été corrigées avec les différents Service Packs de Windows Vista et Windows 7 :

  • Hooking des fonctions (handler) prenant en charge les exceptions : la fonction de vérification de PatchGuard se déclenche souvent au travers d’exceptions générées par les procédures à exécution différée (DPC). Un rootkit peut mettre un hook sur ces gestionnaires d’exceptions pour prendre le contrôle du fil d’exécution et empêcher les vérifications de PatchGuard.
  • Hooking de la routine « KeBugCheckEx » (0x109) : Il s’agit de la fonction qui arrête le système en cas de corruption et qui affiche l’écran bleu. Aujourd’hui, PatchGuard fait sa propre copie de cette fonction et efface la pile d’exécution pour empêcher le hooking.
  • La manipulation des registres de débogage des processeurs Intel x86_64 (DR0 à DR7) : ces registres permettent de mettre des points d’arrêts d’exécution lorsque certaines adresses mémoire sont lues/écrites. Un rootkit peut définir des points d’arrêt sur des adresses mémoire qu’il contrôle afin de modifier le fil d’exécution des vérifications de PatchGuard et ainsi empêcher que les modifications illégales du noyau soient détectées.
  • Modifier le gestionnaire qui traite les procédures DPC du noyau. Un rootkit peut assez facilement détecter l’emplacement de ce gestionnaire, le modifier, et ensuite décider d’exécuter ou non les appels des procédures DPC, selon si elles correspondent à une exécution de PatchGuard ou aux autres tâches de fonctionnement du noyau.
  • Etc.

Dans son rapport, McAfee explique enfin avoir développé sa propre technique d’attaque contre PatchGuard. Elle est davantage générique puisqu’elle a consisté à observer la façon dont le code de PatchGuard s’auto-déchiffre. Lors de son initialisation, PatchGuard déchiffre une première partie de son code, code qui sert à déchiffrer le reste des instructions. Il suffit de parcourir la mémoire du noyau à la recherche de toutes les occurrences de ce code (similaire à une recherche de signature) et d’y concaténer une représentation chiffrée d’instructions de retour (return). Cela permet, d’après l’éditeur, de désactiver efficacement PatchGuard une fois pour toute sur toutes les éditions de Windows incluant Windows 8.
 

Conclusion : vers un nouveau niveau de sécurité

McAfee conclue sur le concept somme toute assez basique selon lequel il est impossible de protéger un système d’une attaque qui s’exécute avec le même niveau de privilèges que la fonctionnalité de sécurité qui est sensée le protéger. En effet, les deux codes (dans notre cas le rootkit et PatchGuard) ont le droit de faire les mêmes opérations sur le processeur et ne disposent d’aucune restriction sur les accès en mémoire. PatchGuard n’est donc qu’un moyen de rendre plus difficiles les attaques par rootkit mais reste une solution vulnérable par nature. Autrement dit, un code qui a atteint le « ring 0 » ne peut plus être contré efficacement au sein d’un système d’exploitation.

La solution proposée par McAfee et son partenaire Intel est de faire reposer cette protection sur le matériel, le processeur en l’occurrence. La solution présentée, appelée DeepSAFE, utilise les fonctionnalités de virtualisation des derniers processeurs Intel 64-bit, pour exécuter une couche sécurisée de code à un nouveau niveau de privilèges maximum (il est appelé « VMX root » mais on pourrait tout aussi bien l’appeler « ring -1 »). Le noyau du système d’exploitation, lui, reste exécuté à son niveau de privilèges habituel (ring 0). Dans ce nouveau modèle, c’est la couche de code sécurisée qui configure les zones mémoire critiques ou les registres processeur à surveiller. Si un composant du noyau effectue une modification non autorisée sur l’une des zones clés surveillées, le matériel déclenche une exception qui rend le contrôle de l’exécution à la couche de code sécurisée de DeepSAFE, qui décidera si oui ou non la modification peut être faite.

Pour conclure, nous sommes parfaitement conscients que le rapport de McAfee que nous avons étudié constitue avant tout une bonne publicité pour leur collaboration avec Intel et les dernières technologies qu’ils ont développées ensemble. DeepSAFE n’est sûrement pas une solution miracle et les chercheurs en sécurité ne tarderont pas à trouver des failles dans son implémentation. Cependant, nous avons trouvé que le rapport avait le mérite de proposer une solution élégante à la problématique déjà bien ancienne des rootkits.

Références

Précedent Précedent Suivant Suivant Imprimer Imprimer