pyvmidbg : un débogueur full‐system basé sur l’introspection de machine virtuelle

Posté par  (site web personnel) . Édité par ZeroHeure, Xavier Teyssier, Davy Defaud, Benoît Sibaud et palm123. Modéré par ZeroHeure. Licence CC By‑SA.
36
30
mar.
2019
Virtualisation

Voici un projet qui me (Wenzel) tient à cœur : pyvmidbg.

Le but est assez simple : se donner la capacité de déboguer l’état complet d’un système d’exploitation, tournant dans une machine virtuelle, en utilisant uniquement l’hyperviseur et l’accès au matériel par la machine virtuelle.

L’idée en elle‐même a commencé à germer lorsque je travaillais sur des outils d’analyse de logiciels malveillants (malware) basés sur l’hyperviseur, et, voyant leur efficacité pour l’analyse automatisée, j’ai petit à petit creusé pour transposer ces concepts afin d’aboutir à de puissants débogueurs interactifs.

Intérêt

Problématiques

L’intérêt d’un tel outil ? Au‐delà du besoin évident pour des analystes en sécurité d’analyser furtivement des logiciels malveillants avancés, on peut trouver d’autres problèmes plus généraux liés aux API de débogage des systèmes d’exploitation :

  1. la visibilité (l’effet d’observateur), qui va potentiellement changer l’environnement du programme ; par exemple, certains appels système auront un comportement différent ;
  2. cet effet d’observateur peut parfois être volontaire, dans une tentative de protection de la propriété intellectuelle de certains systèmes d’exploitation ;
  3. les nouvelles fonctionnalités de sécurité des systèmes d’exploitation modernes posent des soucis de compatibilité avec la visibilité et le contrôle total que demandent les débogueurs.

Avantages

Déboguer depuis l’hyperviseur apporte aussi des bénéfices non négligeables :

  1. en virtualisant le démarrage depuis un hyperviseur chargé sur une clef USB, il est possible d’analyser dans une machine virtuelle l’ensemble de la séquence de démarrage d’un système d’exploitation, et ce depuis le micrologiciel BIOS/UEFI ;
  2. les unikernels, images noyau embarquant une seule application, sont dépouillés d’un maximum de fonctionnalités pour être minimaux et rapides ; le stub de débogage est également supprimé, laissant à l’API de l’hyperviseur les seuls moyens d’accès pour un unikernel en production ;
  3. l’unification des outils de débogage : en rebasant nos débogueurs sur l’hyperviseur, il nous sera possible d’utiliser le même outil pour déboguer et suivre des processus, de l’espace utilisateur au noyau, et ce, sur tous les systèmes d’exploitation !

Débogage full‐system

Afin de résoudre ces problématiques et implémenter une solution pérenne, j’aimerais vous présenter la vision que j’ai de nos futurs outils de débogage, travaillant en mode full‐system :

pyvmidbg

  • les multiples stubs de débogage implémentent les protocoles standards pour gérer tous les frontaux ;
  • les stubs possèdent une connaissance du système invité, c’est‐à‐dire qu’ils sont capables de suivre et d’intercepter l’exécution d’un processus cible dans la machine virtuelle ;
  • la LibVMI permet de faire le lien avec les différentes API de VMI (Virtual Machine Introspection) des hyperviseurs cibles.

Démo

Comme une démo vaudra mieux que mille mots, je vous propose cette petite vidéo que j’ai enregistrée pour la conférence Insomni’Hack qui se tenait la semaine dernière à Genève.

Dans celle‐ci, avec une machine virtuelle Windows XP imbriquée, je montre comment :

  1. intercepter l’exécution de cmd.exe ;
  2. se connecter au stub en utilisant radare2 ;
  3. mettre en place deux points d’arrêt, en espace utilisateur sur ntdll!NtOpenFile, puis en espace noyau sur nt!NtOpenFile ;
  4. suivre des événements liés à ces points d’arrêt dans le stub, en ignorant les autres processus pour ne renvoyer de résultat que pour cmd.exe.

Pour aller plus loin, je vous ai également mis le lien vers la présentation.

Quel est votre avis concernant nos outils de débogages actuels ? J’aimerais avoir vos retours !
Je cherche à présent à implémenter la prise en charge de GNU/Linux, et à comprendre comment l’état des fils d’exécution (threads) est sauvé et restauré, et comment l’ordonnanceur passe de l’un à l’autre.

Vous êtes curieux ou souhaitez participer ? Nous avons un Slack !

Dans l’espoir de vous présenter une meilleure version au FOSDEM 2020. :)

Merci à vous !

Aller plus loin

  • # Accès au Slack

    Posté par  (site web personnel) . Évalué à 4.

    J'oubliais de préciser que Slack ne fonctionne que sur invitation, je n'ai pas trouvé comment en faire un chat public.

    Envoyez-moi un mail à mathieu.tarral@protonmail.com

  • # Prometteur

    Posté par  . Évalué à 3.

    Ce projet a l'air très intéressant (et très pointu techniquement).

    Comme un hyperviseur joue déjà avec l'horloge des VM (puisque ces dernières sont parfois suspendues), on peut effectivement imaginer un déboggeur s'interfaçant au niveau de l'hyperviseur et plus transparent pour les applications que les déboggeurs classiques.

    Pour la question à propos des threads, sous Linux ils sont gérés (ordonnancés) par le noyau.
    Les structures de l'ordonnanceur dépendent des versions du noyau. On peut probablement écrire des fonctions pour les parcourir (avec tous les problèmes classiques de cohérence des infos si on regarde au moment où un thread est inséré/retiré). Pour influer sur l'ordonnanceur (et choisir à quel thread on donne la main), ça me semble vraiment difficile sans ajouter un support spécifique dans le noyau. Or, l'ordonnanceur est une pièce compliquée, très optimisée, donc très difficile à modifier…

    • [^] # Re: Prometteur

      Posté par  (site web personnel) . Évalué à 1.

      On peut probablement écrire des fonctions pour les parcourir (avec tous les problèmes classiques de cohérence des infos si on regarde au moment où un thread est inséré/retiré).

      il y a effectivement le cas ou l'ordonnanceur va mettre à jour l'état des processus et des threads, et il faut éviter de lire les structures task_struct pour Linux lorsque l'ordonnanceur tourne.

      Avec des symboles et une connaissance du guest, c'est tout à fait faisable.

      Pour influer sur l'ordonnanceur (et choisir à quel thread on donne la main), ça me semble vraiment difficile sans ajouter un support spécifique dans le noyau.

      Il ne s'agit pas de forcer l'ordonnanceur à suivre un certain comportement.

      L'objectif est de suivre son fonctionnement, et d'intercepter les appels à certaines fonctionnes cruciales,

      comme switch_to (Linux) ou KiSwapThread (Windows), qui vont scheduler un nouveau thread pour execution, et reprendre la main à ce moment là.

      Encore une fois, c'est la connaissance du guest via Rekall qui nous fournit l'emplacement de ces symboles, ainsi que les offsets des structures en mémoire.

      Donc possible et pas (si) impossible que ça en à l'air au premier abord :)

  • # Ambitieux (trop ?)

    Posté par  (site web personnel) . Évalué à 2.

    Joli projet et très intéressant pour le domaine du RE.

    Mais si je m'en réfère à ton schéma d'architecture, cela me parait très ambitieux : vouloir supporter plusieurs hyperviseurs, des stubs KD et GDB (donc OS Windows et Linux comme guest) et le tout en passant uniquement par VMI, de ce que j'en connais ce sera difficilement atteignable.
    Viser un seul hyperviseur cible parait être plus réaliste. Et tant qu'à faire en en choisissant un dont les sources sont modifiables afin de pouvoir y ajouter des fonctions de debug avancées si nécessaires; donc à priori KVM/qemu, Xen ou VirtualBox.

    Dans le même ordre d'idée, le projet Sandbagility est un framework d'introspection de VM Windows utilisé aussi pour faire du RE (dev open-source par des malware analystes de Orange Cyberdefense). C'est développé en Python et repose sur des ajouts à VirtualBox pour avoir un protocole de debug avancé (Fast Debugging Protocol). Voir par exemple la présentation qui en a été fait à la conf. SSTIC en 2018 https://www.sstic.org/2018/presentation/sandbagility/

    • [^] # Re: Ambitieux (trop ?)

      Posté par  (site web personnel) . Évalué à 2.

      Bonjour, et merci pour le feedback.

      Mais si je m'en réfère à ton schéma d'architecture, cela me parait très ambitieux

      C'est vrai que c'est un projet avec une échéance sur plusieurs années, au vu de la complexité des hyperviseurs, et de la difficulté à rationaliser leurs APIs dans une bibliothèque d'abstraction.

      Néanmoins je maintiens qu'il s'agit de la route à suivre, car les interfaces de VMI se ressemblement, et les hyperviseurs finiront par offrir une API de VMI complète.

      Le fait de pouvoir construire des applications (comme des stubs) sans se soucier de la couche en dessous est un vrai plus à mon sens.

      Dans le même ordre d'idée, le projet Sandbagility est un framework d'introspection de VM Windows utilisé aussi pour faire du RE

      Je connais ce framework, et l'ai évoqué dans mes slides :)
      J'ai hâte de suivre ses prochaines évolutions.

      Pour l'heure il ne répondait pas à mon problème, mais il apporte des briques de solutions !

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.