Das Komponenten-Objektmodell (COM) ist seit den frühen 1990er Jahren ein Eckpfeiler der Microsoft Windows-Entwicklung und ist in modernen Windows-Betriebssystemen und -Anwendungen immer noch sehr verbreitet. Die Abhängigkeit von COM-Komponenten und die umfangreiche Funktionsentwicklung im Laufe der Jahre haben eine großzügige Angriffsfläche geschaffen. Im Februar 2025 veröffentlichte James Forshaw (@tiraniddo) von Google Project Zero einen Blogbeitrag, in dem er einen neuartigen Ansatz zum Missbrauch der Distributed COM (DCOM)-Remoting-Technologie beschrieb, bei dem eingeschlossene COM-Objekte verwendet werden können, um .NET-verwalteten Code im Kontext eines serverseitigen DCOM-Prozesses auszuführen. Forshaw hebt mehrere Anwendungsfälle für die Ausweitung von Berechtigungen und die Umgehung von Protected Process Light (PPL) hervor.
Basierend auf Forshaws Forschungen veröffentlichte Mohamed Fakroud (@T3nb3w) Anfang März 2025 eine Implementierung der Technik zur Umgehung von PPL-Schutzmaßnahmen. Jimmy Bayne (@bohops) und ich haben im Februar 2025 ähnliche Untersuchungen durchgeführt, die uns dazu verursacht haben, eine Proof-of-Concept-Technik für dateilose Lateralbewegungen zu entwickeln, bei der gefangene COM-Objekte missbraucht werden.
COM ist ein binärer Schnittstellenstandard und eine Middleware-Serviceebene, die es ermöglicht, unterschiedliche, modulare Komponenten für die Interaktion untereinander und mit Anwendungen verfügbar zu machen, unabhängig von der zugrunde liegenden Programmiersprache. Beispielsweise können in C++ entwickelte COM-Objekte problemlos mit einer .NET-Anwendung verbunden werden, sodass Entwickler verschiedene Softwaremodule effektiv integrieren können. DCOM ist eine Remoting-Technologie, die es COM-Clients ermöglicht, über Interprozesskommunikation (IPC) oder Remote Procedure Calls (RPC) mit COM-Servern zu kommunizieren. Viele Windows-Dienste implementieren DCOM-Komponenten, auf die lokal oder remote zugegriffen werden kann.
COM-Klassen werden in der Regel registriert und in der Windows-Registrierung gespeichert. Ein Client-Programm interagiert mit einem COM-Server, indem es eine Instanz der COM-Klasse erstellt, die als COM-Objekt bezeichnet wird. Dieses Objekt stellt einen Zeiger auf eine standardisierte Schnittstelle bereit. Der Client verwendet diesen Zeiger, um auf die Methoden und Eigenschaften des Objekts zuzugreifen, wodurch die Kommunikation und Funktionalität zwischen Client und Server erleichtert wird.
COM-Objekte sind häufig Gegenstand von Untersuchungen zur Bewertung der Anfälligkeit für Sicherheitslücken und zur Identifizierung von Funktionen, die für Missbrauch genutzt werden könnten. Ein eingeschlossenes COM-Objekt ist eine Fehlerklasse, bei der ein COM-Client eine COM-Klasse in einem prozessunabhängigen DCOM-Server instanziiert, wobei der Client das COM-Objekt über einen referenzierten Objektzeiger steuert. Je nach den Umständen kann dieser Kontrollvektor sicherheitsrelevante Logikfehler aufweisen.
Forshaws Blog beschreibt einen Anwendungsfall für einen PPL-Bypass, bei dem die Schnittstelle IDispatch, wie sie in der COM-Klasse WaaSRemediation verfügbar ist, manipuliert wird, um COM-Objekte zu missbrauchen und .NET-Code auszuführen. WaaSRemediation ist im Dienst WaaSMedicSvc implementiert, der als geschützter svchost.exe-Prozess im Kontext von NT AUTHORITY\SYSTEM ausgeführt wird. Forshaws hervorragende Anleitung bildete die Grundlage für unsere angewandte Forschung und Entwicklung einer Proof-of-Concept-Technik für dateilose Lateralbewegungen.
Unsere Forschungsreise begann mit der Untersuchung der WaaSRemediation COM-Klasse, die die Schnittstelle IDispatch unterstützt. Diese Schnittstelle ermöglicht es Kunden die späte Bindung durchzuführen. In der Regel werden die Schnittstellen- und Typen-Definitionen für die von COM-Clients verwendeten Objekte zur Kompilierungszeit festgelegt. Im Gegensatz dazu ermöglicht die späte Bindung dem Client, Methoden für das Objekt zur Laufzeit zu ermitteln und aufzurufen. IDispatch enthält die Methode GetTypeInfo, die eine ITypeInfo-Schnittstelle zurückgibt. ITypeInfo verfügt über Methoden, mit denen Typinformationen für das Objekt ermittelt werden können, das es implementiert.
Wenn eine COM-Klasse eine Typbibliothek verwendet, kann sie vom Client über ITypeLib (abgerufen über ITypeInfo-> GetContainingTypeLib) abgefragt werden, um Typinformationen abzurufen. Darüber hinaus können Typbibliotheken auch auf andere Typbibliotheken verweisen, um zusätzliche Typinformationen zu erhalten.
Laut Forshaws Blogbeitrag verweist WaaSRemediation auf die Typenbibliothek WaaSRemediationLib, die wiederum auf stdole (OLE Automation) verweist. WaaSRemediationLib verwendet zwei COM-Klassen aus dieser Bibliothek, StdFont und StdPicture. Durch die Durchführung von COM-Hijacking auf das StdFont-Objekt mittels Änderung seines TreatAs-Registrierungsschlüssels wird die Klasse auf eine andere COM-Klasse unserer Wahl verweisen, beispielsweise System.Object im .NET Framework. Forshaw weist darauf hin, dass StdPicture nicht geeignet ist, da dieses Objekt eine Überprüfung auf Instanziierung außerhalb des Prozesses durchführt. Daher haben wir uns auf die Verwendung von StdFont konzentriert.
.NET-Objekte sind für uns interessant wegen der GetType-Methode von System.Object . Mit GetType lässt sich eine .NET-Reflexion durchführen, um schließlich auf Assembly.Load zuzugreifen. Obwohl System.Object ausgewählt wurde, stellt dieser Typ zufällig die Wurzel der Typhierarchie in .NET dar. Daher könnte jedes .NET-COM-Objekt verwendet werden.
Nachdem die ersten Voraussetzungen geschaffen waren, gab es zwei weitere DWORD-Werte unter dem Schlüssel HKLM\Software\Microsoft\.NetFramework, die erforderlich waren, um unseren Anwendungsfall zu realisieren:
Nachdem wir in unseren ersten Tests bestätigt hatten, dass die neueste Version von CLR und .NET geladen werden konnte, waren wir überzeugt, auf dem richtigen Weg zu sein.
Wir haben uns auf die programmatischen Aspekte der Fernsteuerung konzentriert und zunächst die Remote Registry verwendet, um die Werte des Registrierungsschlüssels .NetFramework zu manipulieren und das StdFont-Objekt auf dem Zielcomputer zu übernehmen. Anschließend haben wir CoCreateInstance durch CoCreateInstanceEx ersetzt, um das COM-Objekt WaaSRemediation auf dem Remote-Ziel zu instanziieren und einen Zeiger auf die Schnittstelle IDispatch zu erhalten.
Mit einem Zeiger auf IDispatch rufen wir die Mitgliedsmethode GetTypeInfo auf, um einen Zeiger auf die Schnittstelle ITypeInfo zu erhalten, die im Server gespeichert ist. Die danach aufgerufenen Mitgliedsmethoden werden serverseitig ausgeführt. Nachdem wir die gewünschte Typbibliotheksreferenz (stdole) identifiziert und die gewünschte Klassenobjektreferenz (StdFont) abgeleitet hatten, verwendeten wir schließlich die „remotable” CreateInstance-Methode der ITypeInfo-Schnittstelle, um den StdFont-Objektverknüpfungsfluss (über eine vorherige TreatAs-Manipulation) umzuleiten und System.Object zu instanziieren.
Da AllowDCOMReflection korrekt konfiguriert ist, können wir .NET-Reflection über DCOM ausführen, um auf Assembly.Load zuzugreifen und eine .NET-Assembly in den COM-Server zu laden. Da wir Assembly.Load über DCOM verwenden, ist diese Technik der Lateralbewegung völlig dateilos, da die Übertragung der Assembly-Bytes durch die DCOM-Remoting-Magie übernommen wird. Eine detaillierte Erläuterung dieses technischen Ablaufs von der Objektinstanziierung bis zur Reflexion finden Sie in der folgenden Abbildung:
Unser erstes und wichtigstes Problem war der Aufruf von Assembly.Load_3 über IDispatch->Invoke. Invoke übergibt ein Objekt-Array mit Argumenten an die Zielfunktion, und Load_3 ist die Überladung von Assembly.Load, die ein einzelnes Byte-Array akzeptiert. Daher mussten wir das SAFEARRAY mit Bytes in ein anderes SAFEARRAY mit VARIANTs einbetten – zunächst versuchten wir immer wieder, ein einzelnes SAFEARRAY mit Bytes zu übergeben.
Ein weiteres Problem bestand darin, die richtige Überladung von Assembly.Load zu finden. Die Hilfsfunktionen wurden aus Forshaws Code CVE-2014-0257 übernommen, der die Funktion GetStaticMethod enthielt. Diese Funktion verwendete .NET-Reflection über DCOM, um eine statische Methode anhand eines Typzeigers, des Methodennamens und der Anzahl der Parameter zu finden. Assembly.Load verfügt über zwei statische Überladungen, die ein einzelnes Argument akzeptieren; daher haben wir uns für eine provisorische Lösung entschieden. Wir stellten fest, dass die dritte Instanz von Load mit einem einzelnen Argument die richtige Wahl war.
Einer der größten Nachteile, den wir bei dieser Technik beobachtet haben, war, dass die Lebensdauer des erzeugten Beacons auf den COM-Client beschränkt war. In diesem Fall war die Anwendungslebensdauer unserer Waffenzubehör-Binärdatei „ForsHops.exe“ (natürlich ein eleganter Name). Wenn also ForsHops.exe seine COM-Referenzen bereinigte oder beendet wurde, geschah dies auch mit dem Beacon, der unter svchost.exe auf dem Remote-Rechner lief. Wir haben verschiedene Lösungen ausprobiert, beispielsweise unsere .NET-Assembly ihren Hauptthread unbegrenzt auszuführen, Shellcode in einem anderen Thread auszuführen und ForsHops.exe den Exploit-Thread weiterlaufen zu lassen, aber keine Lösung war elegant.
In seinem aktuellen Zustand läuft ForsHops.exe, bis der Beacon beendet wird. Zu diesem Zeitpunkt entfernt es seine Registrierungsvorgänge. Es gibt Möglichkeiten zur Verbesserung, aber das überlassen wir dem Leser.
Die von Samir Bousseaden (@SBousseaden) vorgeschlagene Richtlinie zur Erkennung, die Mohamed Fakroud nach der Veröffentlichung ihrer Implementierung vorgeschlagen hat, gilt auch für diese Technik der Lateralbewegung:
Darüber hinaus empfehlen wir die Implementierung der folgenden zusätzlichen Kontrollen:
Zusätzlich kann die folgende Proof-of-Concept-YARA-Regel zur Erkennung der Standard-Ausführungsdatei ForsHops.exe verwendet werden:
Regel Detect_Standard_ForsHops_PE_By_Hash
Unsere Implementierung erweitert den in Forshaws Blog beschriebenen COM-Missbrauch geringfügig, indem sie gefangene COM-Objekte für Lateralbewegungen nutzt, anstatt sie für die lokale Ausführung zur Umgehung von PPL einzusetzen. Daher ist sie nach wie vor denselben Erkennungsmechanismen ausgesetzt wie Implementierungen, die eine lokale Ausführung durchführen.
Den Proof-of-Concept-Code für Lateralbewegungen „ForsHops.exe“ finden Sie hier.
Besonderer Dank gilt Dwight Hohnstein (@djhohnstein) und Sanjiv Kawa (@sanjivkawa) für ihr Feedback zu dieser Forschungsarbeit und die Überprüfung der Inhalte des Blogbeitrags.