Mouvement latéral sans fichier avec des objets COM piégés

Gros plan sur les mains d'un homme tapant sur un ordinateur portable et tenant une tablette dans un bureau sombre et éclairé en bleu

Le modèle d'objet composant (COM) est une pierre angulaire du développement de Microsoft Windows depuis le début des années 1990 et il est encore très répandu dans les systèmes d'exploitation et applications Windows modernes. La dépendance aux composants COM et le développement intensif de fonctionnalités au fil des ans ont créé une surface d'attaque importante. En février 2025, James Forshaw (@tiraniddo) de Google Project Zero a publié un article de blog détaillant une nouvelle approche pour exploiter la technologie de communication à distance Distributed COM (DCOM), dans laquelle des objets COM piégés peuvent être utilisés pour exécuter du code géré .NET dans le contexte d'un processus DCOM côté serveur. M. Forshaw met en évidence plusieurs cas d'utilisation pour l'escalade des privilèges et le contournement du Protected Process Light (PPL).

Sur la base des recherches de M. Forshaw, Mohamed Fakroud (@T3nb3w) a publié une implémentation de la technique permettant de contourner les protections PPL début mars 2025. Jimmy Bayne (@bohops) et moi-même avons mené des recherches similaires en février 2025, ce qui nous a conduits à développer une technique de mouvement latéral sans fichier en abusant d’objets COM piégés.

Contexte

COM est une norme d'interface binaire et une couche de services middleware qui permet l'exposition de composants distincts et modulaires afin qu'ils interagissent entre eux et avec des applications, quel que soit le langage de programmation sous-jacent. Par exemple, les objets COM développés en C++ peuvent facilement s'interfacer avec une application .NET, ce qui permet aux développeurs d'intégrer efficacement divers modules logiciels. DCOM est une technologie de communication à distance qui permet aux clients COM de communiquer avec les serveurs COM via la communication inter-processus (IPC) ou les appels de procédure à distance (RPC). De nombreux services Windows implémentent des composants DCOM accessibles localement ou à distance.

Les classes COM sont généralement enregistrées et contenues dans le registre Windows. Un programme client interagit avec un serveur COM en créant une instance de la classe COM, appelée objet COM. Cet objet fournit un pointeur vers une interface standardisée. Le client utilise ce pointeur pour accéder aux méthodes et propriétés de l'objet, facilitant ainsi la communication et les fonctionnalités entre le client et le serveur.

Les objets COM sont fréquemment étudiés afin d'évaluer l'exposition aux vulnérabilités et de découvrir les fonctionnalités susceptibles d'être exploitées. Un objet COM piégé est une classe de bogues dans laquelle un client COM instancie une classe COM dans un serveur DCOM hors processus, où le client contrôle l'objet COM via un pointeur d'objet marshalé par référence. Selon la condition, ce vecteur de contrôle peut présenter des failles logiques liées à la sécurité.

Le blog de M. Forshaw décrit un cas d’utilisation de contournement PPL où l’interface IDispatch, telle qu’exposée dans la classe COM WaaSRemediation, est manipulée pour permettre l'utilisation abusive d'objets COM piégés et l'exécution de code .NET. WaaSRemediation est implémenté dans le service WaaSMedicSvc, qui s'exécute en tant que processus protégé svchost.exe dans le contexte NT AUTHORITY\SYSTEM. L’excellente présentation de M. Forshaw a servi de base à nos recherches appliquées et au développement d’une technique de mouvement latéral sans fichier de preuve de concept.

Homme regardant un ordinateur

Renforcez vos renseignements de sécurité 


Gardez une longueur d’avance sur les menaces grâce à l’actualité et aux réflexions sur la sécurité, l’IA et bien plus encore, dans la newsletter hebdomadaire Think. 


Aperçu de la recherche

Notre parcours de recherche a commencé par la découverte de la classe COM WaaSRemediation qui prend en charge l’interface IDispatch. Cette interface permet aux clients d'effectuer une liaison tardive. En règle générale, les clients COM disposent des définitions d'interface et de type pour les objets qu'ils utilisent, définies au moment de la compilation. La liaison tardive permet au client de découvrir et d'appeler des méthodes sur l'objet au moment de l'exécution. IDispatch comprend la méthode GetTypeInfo, qui renvoie une interface ITypeInfo. ITypeInfo dispose de méthodes qui peuvent être utilisées pour découvrir les informations de type pour l'objet qui l'implémente.

Si une classe COM utilise une bibliothèque de types, elle peut être interrogée par le client via ITypeLib (via ITypeInfo-> GetContainingTypeLib) afin de récupérer des informations sur les types. De plus, les bibliothèques de types peuvent également référencer d’autres bibliothèques de types pour obtenir des informations supplémentaires sur les types.

Selon l’article de blog de M. Forshaw, WaaSRemediation fait référence à la bibliothèque de types WaaSRemediationLib, qui à son tour fait référence à stdole (OLE Automation). WaaSRemediationLib utilise deux classes COM de cette bibliothèque, StdFont et StdPicture. En effectuant un détournement COM sur l'objet StdFont via la modification de sa clé de registre TreatAs, la classe pointera vers une autre classe COM de notre choix, telle que System.Object dans le cadre .NET. Il convient de noter que M. Forshaw souligne que StdPicture n'est pas viable, car cet objet effectue une vérification pour l'instanciation hors processus. Nous avons donc continué à nous concentrer sur l'utilisation de StdFont.

Les objets .NET nous intéressent grâce à la méthode GetType de System.Object . Grâce à GetType, nous pouvons effectuer une réflexion .NET pour accéder finalement à Assembly.Load. Bien que System.Object ait été choisi, ce type est la racine de la hiérarchie de types dans .NET. Par conséquent, n'importe quel objet COM .NET peut être utilisé.

Une fois l'étape initiale franchie, deux autres valeurs DWORD sous la clé HKLM\Software\Microsoft\.NetFramework étaient nécessaires pour concrétiser notre cas d'utilisation envisagé :

  • AllowDCOMReflection : comme l’a noté M. Forshaw, cette valeur activée nnous permet d'effectuer une réflexion arbitraire pour appeler n'importe quelle méthode .NET. En règle générale, la réflexion .NET sur DCOM est empêchée en raison des mesures d'atténuation décrites dans MS14-009.
  • OnlyUseLatestCLR : avec Procmon, nous avons découvert que cette valeur doit être activée pour charger la dernière version du CLR .NET (version 4), sinon la version 2 est chargée par défaut.

Après avoir confirmé que la dernière version du CLR et de .NET pouvait être chargée lors de nos premiers tests, nous avons compris que nous étions sur la bonne voie.

Du processus local à l’ordinateur distant

En nous concentrant sur les aspects programmatiques à distance, nous avons d'abord utilisé le registre à distance pour manipuler les valeurs de la clé de registre .NetFramework et détourner l'objet StdFont sur la machine cible. Ensuite, nous avons remplacé CoCreateInstance par CoCreateInstanceEx pour instancier l'objet COM WaaSRemediation sur la cible à distance et obtenir un pointeur sur l'interface IDispatch .

Avec un pointeur sur IDispatch, nous appelons la méthode membre GetTypeInfo pour obtenir un pointeur sur l'interface ITypeInfo, qui est piégée dans le serveur. Les méthodes membres appelées ensuite se produisent côté serveur. Après avoir identifié la référence de bibliothèque de type contenue d'intérêt (stdole) et dérivé la référence d'objet de classe qui nous intéressait (StdFont), nous avons finalement utilisé la méthode « remotable » CreateInstance sur l'interface ITypeInfo pour rediriger le flux de lien d'objet StdFont (via la manipulation préalable de TreatAs ) afin d'instancier System.Object.

Comme AllowDCOMReflection est correctement défini, nous pouvons alors effectuer une réflexion .NET sur DCOM pour accéder à Assembly.Load afin de charger un assemblage .NET dans le serveur COM. Puisque nous utilisons Assembly.Load via DCOM, cette technique de mouvement latéral est entièrement sans fichier, car le transfert des octets de l'assembly est géré par la technologie DCOM. Pour une explication détaillée de ce flux technique, de l'instanciation d'objet à la réflexion, veuillez vous référer au diagramme suivant :

organigramme montrant l'instanciation de la classe System.Object
Flux d'instanciation de la classe System.Object

Difficultés de développement

Notre premier et principal problème était d'appeler Assembly.Load_3, via IDispatch->Invoke. Invoke transmet un tableau d'objets à la fonction cible, et Load_3 est la surcharge de Assembly.Load qui prend un seul tableau d'octets. Nous devions donc encapsuler le SafeARRAY d’octets dans un autre SafeARRAY de VARIANTs. au départ, nous avons tenté à plusieurs reprises de transmettre un seul SAFEARRAY d’octets.

Code illustrant comment créer un équivalent non géré de Object Bytc
Création d'un équivalent non géré d'Object Byte

Un autre problème consistait à trouver la surcharge Assembly.Load appropriée. Les fonctions d’assistance étaient tirées du code CVE-2014-0257 de M. Forshaw, qui incluait la fonction GetStaticMethod . Cette fonction utilisait la réflexion .NET sur DCOM pour trouver une méthode statique à partir d’un pointeur de type, du nom de la méthode et de son nombre de paramètres. Assembly.Load possède deux surcharges statiques qui nécessitent un seul argument ; nous avons donc fini par utiliser une solution improvisée. Nous avons constaté que la troisième instance de Load avec un seul argument était le bon choix.

code utilisé pour rechercher la surcharge Assembly.Load appropriée
Recherche de la surcharge appropriée pour Assembly.Load

Difficultés opérationnelles

L'un des principaux inconvénients que nous avons observés avec cette technique était que la durée de vie de la balise générée était limitée au client COM ; dans ce cas, la durée de vie de l'application de notre binaire d'armement « ForsHops.exe » (élégamment nommé, bien sûr). Ainsi, si ForsHops.exe nettoyait ses références COM ou se fermait, il en allait de même pour la balise qui s'exécutait sous svchost.exe de la machine à distance. Nous avons essayé différentes solutions, telles que demander à notre assembly .NET de suspendre indéfiniment son thread principal, exécuter le shellcode dans un autre thread et demander à ForsHops.exe de laisser le thread d'exploitation en suspens, mais aucune n'était satisfaisante.

Le thread principal du chargeur .NET se bloque pendant que le shellcode s'exécute dans un thread distinct
Le thread principal du chargeur .NET se bloque pendant que le shellcode s'exécute dans un thread distinct

Dans son état actuel, ForsHops.exe s'exécute jusqu'à la fermeture de la balise, puis ses opérations de registre sont supprimées. Il existe des possibilités d'amélioration, mais nous laisserons au lecteur le soin de les identifier.

démonstration de l'exécution de ForShops.exe
Exécution de ForShops.exe
Signal de réussite sur Windows 2019 Server
Signal de réussite sur Windows 2019 Server
capture d'écran de Beacon s'exécutant dans un processus PPL svchost
Beacon fonctionne selon un processus PPL svchost
exemple de suppression des modifications par ForShops.exe après la fermeture de Beacon
Suppression des modifications apportées par ForShops.exe après la fermeture de Beacon

Recommandations défensives

Les recommandations de détection proposées par Samir Bousseaden (@SBousseaden) après la publication de leur implémentation par Mohamed Fakroud s'appliquent également à cette technique de mouvement latéral :

  • Détection des événements de charge CLR dans le processus svchost.exe de WaaSMedicSvc
  • Détection de la manipulation (ou de la création) de la clé suivante dans le registre : HKLM\SOFTWARE\Classes\CLSID\{0BE35203-8F91-11CE-9DE3-00AA004BB851}\TreatAs (clé TreatAs de StandardFont CLSID)

De plus, nous recommandons la mise en œuvre des contrôles supplémentaires suivants :

  • Détection de la manipulation DACL de HKLM\SOFTWARE\Classes\CLSID\{0BE35203-8F91-11CE-9DE3-00AA004BB851}
  • Recherche de la présence des valeurs activées OnlyUseLatestCLR et AllowDCOMReflection dans HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework
  • Activation du pare-feu basé sur l'hôte afin de limiter l'accès aux ports éphémères DCOM lorsque cela est possible.

De plus, tirez parti de la règle YARA de validation de concept suivante pour détecter l'exécutable standard ForsHops.exe :

règle Detect_Standard_ForsHops_PE_By_Hash

{
    meta:   
        description = "Detects the standard ForShops PE file by strings"
        reference = "GitHub Project: https://github.com/xforcered/ForsHops/"
    strings:
        $s1 = "System.Reflection.Assembly, mscorlib" wide
        $s2 = "{72566E27-1ABB-4EB3-B4F0-EB431CB1CB32}" wide
        $s3 = "{34050212-8AEB-416D-AB76-1E45521DB615}" wide
        $s4 = "GetType" wide
        $s5 = "Load" wide

    condition:
        all of them
}

Conclusion

Notre implémentation étend légèrement le détournement de COM expliqué dans le blog de M. Forshaw en exploitant les objets COM piégés pour le mouvement latéral plutôt que l'exécution locale pour contourner le PPL. ar conséquent, elle reste sensible aux mêmes détections que les implémentations effectuant une exécution locale.

Vous trouverez ici le code de démonstration de mouvement latéral ForsHops.exe.

Remerciements

Nous remercions tout particulièrement Dwight Hohnstein(@djhohnstein) et Sanjiv Kawa(@sanjivkawa) pour leurs commentaires sur cette recherche et la révision du contenu des articles de blog.

Ressources

Mixture of Experts | 12 décembre, épisode 85

Décryptage de l’IA : Tour d’horizon hebdomadaire

Rejoignez notre panel d’ingénieurs, de chercheurs, de chefs de produits et autres spécialistes de premier plan pour connaître l’essentiel de l’actualité et des dernières tendances dans le domaine de l’IA.

Solutions connexes
IBM Guardium

Protégez vos données les plus critiques ; découvrez, surveillez et sécurisez les informations sensibles dans chaque environnement, tout en automatisant la conformité et en réduisant les risques.

Découvrir IBM Guardium
Solutions de sécurité d’entreprise

Transformez votre programme de sécurité avec le portefeuille de solutions le plus complet.

    Découvrir les solutions de sécurité
    Services de cybersécurité

    Transformez votre entreprise et gérez les risques avec des services de conseil en cybersécurité, de cloud et de sécurité gérée.

    Découvrir les services de cybersécurité
    Passez à l’étape suivante

    Automatisez la protection des données, la détection des menaces et la conformité pour sécuriser votre entreprise sur site et dans le cloud.

    1. Découvrir IBM Guardium
    2. Découvrir les solutions de cybersécurité