Anti-Forensics : Dissimulation de processus Windows en kernel mode

Olivier Chatail Etude - Recherche, Forensics

Introduction

Cet article est la première itération d’une série d’articles visant à présenter un éventail de techniques utilisées par les logiciels malveillants pour se propager et dissimuler leur présence sur les différentes cibles.

La grande majorité de ces techniques a été découverte et présentée il y a plusieurs années par des chercheurs en sécurité. Le but de l’approche présente est de construire et organiser une base de connaissance sur les aspects systèmes (défensifs et offensifs) et les aspects identification/forensics (réponse à incident) de ces techniques.
En plus de la présentation de ces aspects un code source de type Proof of Concept en C pourra être trouvé sur le Github du CERT.

S’ajouteront à cette base de connaissance les éléments techniques rencontrés sur le terrain par l’équipe de réponse à incident de Devoteam.
Ce premier article présentera la technique nommée DKOM process hiding suivant le plan suivant :

  • Représentation des processus sous Windows
  • Dissimulation par Direct Kernel Object Modification
  • Implémentation
  • Détection en RAM avec Volatility

Le concept, présenté en 2004 à la Black Hat USA a été et est utilisé par de nombreux rookits kernel mode comme le très connu FU-rootkit, développé par Jamie Butler (également auteur de la présentation susmentionnée).

 

Représentation des processus sous Windows

Le kernel Windows représente les processus par des structures EPROCESS.
Ces structures sont opaques : peu documentées par Microsoft et non détaillées par des headers standards.
Référence MSDN: EPROCESS (Windows Driver)

Elles sont malgré tout observables via le debugging kernel, avec KD :

Récupération de pointeur vers EPROCESS avec kd

Listing des champs EPROCESS avec kd

La structure contient 207 champs (dans notre exemple avec Windows 10 64 bits).
Le focus sera mis sur trois champs de cette structure dont :

Champ PID dans KD

Le nom d’exécutable

Structure de type LIST_ENTRY

Cette liste contient deux liens : Flink et Blink.

Ces liens sont intéressants car ils pointent vers deux structures LIST_ENTRY appartenant respectivement au processus précédent (Backlink) et au processus suivant (Forwardlink).

Représentation d’ActiveProcessLinks entre trois processus

Tous les processus d’un système se référencent donc les uns aux autres via des pointeurs dans leur structure ActiveProcessLinks. Ils forment une liste doublement chaînée utilisée par les outils Windows tels que taskmgr.exe (gestionnaire des tâches) ou certains outils de SysInternals comme procexp.exe.

Représentation des liens entre processus

Ces outils parcourent cette liste périodiquement pour mettre à jour l’affichage des processus.

Dissimulation par Direct Kernel Object Modification

La technique DKOM process hiding permet de cacher un processus en déréférençant les ActiveProcessLinks de ce dernier et en reliant le processus « précédent » directement au processus « suivant ».

Représentation graphique d’une attaque DKOM

Sortir notre processus (smss.exe dans l’exemple imagé) de la liste doublement chaînée le rend invisible aux outils parcourant cette dernière pour récupérer tous les processus.
Le fait de déréférencer le processus n’impacte en aucun cas son fonctionnement. En effet, l’ordonnanceur alloue du temps processeur aux threads unitairement, sans considérer la notion de processus.
Les liens Blink et Flink du processus sont modifiés pour pointer vers leur propre structure ActiveProcessLinks afin de ne pas lever d’erreur à la fin de l’exécution du processus. S’ils pointent vers d’anciennes adresses ou des valeurs aléatoires le kernel risque de lever une erreur à la mise à jour des processus « voisins ».

Liens entre processus avec dissimulation du processus de PID 64

 

Implémentation

Commentaires sur le PoC en version 0.1

Le code présent sur le github du CERT est le code d’un driver de test, il part du code d’exemple de driver Windows utilisant le Kernel-Mode Driver Framework.
Lors de son initialisation le driver va chercher, via WDF_DRIVER_CONFIG_INIT(), un processus dont le nom (champ ImageFileName de EPROCESS mentionné précédemment) est virus.exe et va le dissimuler en utilisant la technique décrite auparavant.
Cette implémentation n’est pas un Rootkit fonctionnel et ne sert que d’exemple à titre éducatif.
Le code utilise des offsets mémoire testés sur un Windows 10 64bits mis à jour le 02 Janvier 2017. Ces offsets permettent d’accéder aux différents champs de la structure EPROCESS et ont de grandes chances de ne pas fonctionner sur d’autres versions de Windows.

Offsets mémoires EPROCESS utilisés

Les offsets présentés ci-dessus peuvent être retrouvés dans les captures réalisées avec KD dans la partie Représentation des processus sous Windows.
Le code peut être aisément amélioré pour s’affranchir de la limite liée à la version de Windows et offrir une interface de contrôle user land.

Accès et modification des EPROCESS

L’API de Windows ne fournit pas de structure EPROCESS mais fournit des méthodes permettant de récupérer un pointeur vers ce dernier.
La fonction utilisée dans le cas du PoC est PsGetCurrentProcess(), qui retourne un pointeur vers la structure EPROCESS du processus courant.
Dans le contexte d’exécution de notre driver, elle retourne un pointeur vers la structure EPROCESS du processus System.
Une fois ce pointeur récupéré une fonction de recherche est appelée afin de parcourir la liste des EPROCESS à la recherche de l’ImageFileName virus.exe.

Corps de fonction principal

Si la recherche retourne une structure EPROCESS, alors les ActiveProcessLinks de ce dernier sont modifiés afin de le dissimuler.
Cette opération est réalisée via manipulation directe des structures EPROCESS en mémoire.

Fonction de dissimulation DKOM

Pertinence et protections existantes

Le driver généré par le code du PoC a été soumis à l’analyse des Antivirus fournis par la plateforme https://nodistribute.com/ et n’a levé aucune alerte.

Résultat de l’analyse Antivirus du PoC

Ce résultat est directement lié à la simplicité du code et au faible nombre d’appels systèmes requis pour faire fonctionner la technique.

Cette technique n’est cependant pas stable sur toutes les versions de systèmes d’exploitation Windows.
En effet, une protection intégrée à Windows 64 bits nommée PatchGuard peut détecter les manipulations précédemment décrites.
PatchGuard, aussi appelé Kernel Patch Protection (KPP), a été introduit dans Windows XP 64 bits et Windows Server 2003 SP1 en 2005.

Ce mécanisme, très peu documenté par Microsoft, permet de vérifier la consistance des structures Kernel et éviter les méthodes de patching et hooking par un driver.
KPP effectue des vérifications régulières sur une fréquence aléatoire, il peut se passer des dizaines de minutes sans vérification. Lorsqu’une anomalie a été découverte pendant une de ces vérifications une erreur kernel de type 0x109 – CRITICAL_STRUCTURE_CORRUPTION est levée et entraîne l’arrêt brutal du système.
KPP n’empêche donc pas la bonne exécution de la technique mais arrête le système sans sommation.
Étant donné que cette technique est utilisée principalement pour dissimuler une présence, la génération systématique de « blue screen » de la part de KPP la rend inefficace.
La protection n’étant implémentée que dans les versions 64 bits de Windows, elle laisse les systèmes 32 bits vulnérables. A ce jour la plupart des installations de nouveaux postes sont effectuées en 64 bits, rendant cette menace quasi-obsolète.

La méthode ne doit pas être ignorée pour autant, et ce pour deux raisons :

  • Une réponse à incident sur des systèmes Windows 32 bits peut amener à la rencontrer
  • Des attaques contre PatchGuard existent (et feront l’objet d’une analyse future)

 

Détection en RAM avec Volatility

La détection de la technique est relativement aisée à l’aide d’une capture de RAM, en comparaison à la détection sur un poste infecté.

En effet, une partie des outils de diagnostic live (e.g. suite SysInternals de Microsoft) se base sur la liste doublement chaînée des processus.

A des fins de démonstration, le PoC a été exécuté sur un système Windows 10 Professionnel en version 14393.

Illustration avec Process Explorer, VMMap, ListDlls et Handle64, exécutés sur le système du PoC

Processus invisible pour Process Explorer

Processus invisible pour VMMap

Références vers dlls et handles absentes

En revanche, le processus existe bien et ses événements peuvent être récupérés avec les bons filtres pour le Process Monitor.

Découverte de l’activité du processus caché avec Process Monitor

En dehors du cas trivial choisi comme exemple, les rootkits peuvent modifier et détourner un grand nombre de fonctionnalités systèmes, il est conseillé d’investiguer hors-ligne, sur un dump de RAM avec un framework adapté comme Volatility.

 

La version de Windows mentionnée précédemment est supportée par Volatility 2.6 avec le profil Win10x64_14393.

Version utilisée pour les tests

La capture mémoire a été réalisée avec l’outil Winpmem, distribué par le projet Rekall de Google.

Capture de mémoire avec Winpmem

Il peut être observé, lors de l’identification des éléments récupérés par winpmem, le driver développé précédemment (son nom est ici 2017_remote_helloworld).

Apparition du driver dans les logs Winpmem

Une fois la capture de mémoire à disposition, l’investigation peut démarrer.

Volatility possède un certain nombre de plugins pour analyser les processus en cours d’exécution sur le dump, une comparaison de ces plugins peut être réalisée de la manière suivante :

Lancement des différents plugins de détection de processus

En analysant les résultats, seuls les plugins psscan et psxview ont trouvé l’existence de notre processus caché.

Détection du processus par psscan et psxview

La documentation de ces plugins permet de comprendre l’apparition ou non du processus caché dans les résultats de ces derniers.

pslist – détection des processus via parcours de la liste doublement chaînée (cible de l’attaque)

pstree – utilise la même technique que pslist, présente simplement les résultats différemment

psscan – scanne la mémoire à la recherche de structures _POOL_HEADER (groupement de pages mémoire) pour identifier les processus qui y sont associés

psxview – combinaison de plusieurs techniques, une par colonne :

  • pslist parcours de la liste doublement chaînée
  • psscan _POOL_HEADER scan
  • thrdproc thread scan, récupère la liste des _KTHREAD utilisée par le scheduler (ne peut être modifiée comme indiqué précédemment) et la parcoure à la recherche des _EPROCESS associés
  • pspcid
  • csrss csrss.exe maintient une liste indépendante des processus qui peut être récupérable en scannant sa mémoire
  • session
  • deskthrd

Psxview est en quelque sorte le plugin le plus rapide et efficace pour la détection des processus cachés, il offre la plus grande couverture parmi les autres modules de Volatility.

Il est maintenant établi que dans cette capture, le processus caché s’appelle virus.exe et a le PID 4952, l’investigation peut continuer.

Le PID ne peut être utilisé directement par les plugins de Volatility dans le cas d’un processus caché de cette manière, la référence à utiliser doit être son offset mémoire.

Tentative de récupération des handles via PID

L’offset mémoire (P pour physique) peut être passé à la quasi totalité des plugins Volatility pour identifier un process, en lieu et place de son PID.

Avec cette information il est par exemple possible de récupérer :

  • les handles ouverts vers des ressources du système d’exploitation (fichier, clé de registre…).

Récupération des handles en utilisant l’offset mémoire du processus

  • La ligne de commande à l’origine du processus

Récupération de la ligne de commande associée au processus

Le driver/rootkit peut également être récupéré dans le dump de mémoire.

 

Références


Direct Kernel Object Manipulation. Jamie Butler, Black Hat 2004.
The Rootkit Arsenal, Escape and Evasion in the dark Corners of the System. Bill Blunden, 2013.
FU rootkit source code, Jamie Butler.
FUTo rootkit source code, Peter Silberman.
Windows Internals, Mark Russinovich, David A. Solomon, Alex Ionescu, 2012.
Microsoft Developer Network, https://msdn.microsoft.com/

 

 

Olivier CHATAIL