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 für den Missbrauch der Distributed COM (DCOM) Remoting-Technologie vorstellte, bei dem gefangene COM-Objekte zur Ausführung von verwaltetem .NET-Code im Kontext eines serverseitigen DCOM-Prozesses verwendet werden können. Forshaw hebt mehrere Anwendungsfälle für die Eskalation 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 führten im Februar 2025 ähnliche Forschung durch, was dazu geführt hat, dass wir eine Proof-of-Concept-Technik für Lateralbewegung entwickelt haben, indem wir gefangene COM-Objekte missbrauchen.
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 zugrundeliegenden 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 Fernkommunikationstechnologie, die es COM-Clients ermöglicht, über Interprozesskommunikation (IPC) oder Remote Procedure Calls (RPC) mit COM-Servern zu kommunizieren. Viele Windows-Services implementieren DCOM-Komponenten, die lokal oder remote zugänglich sind.
COM-Klassen werden typischerweise in der Windows-Registrierung registriert und gespeichert. Ein Clientprogramm interagiert mit einem COM-Server, indem es eine Instanz der COM-Klasse erstellt, die als COM-Objekt bezeichnet wird. Dieses Objekt stellt einen Verweis auf eine standardisierte Schnittstelle bereit. Der Client verwendet diesen Zeiger, um auf die Methoden und Eigenschaften des Objekts zuzugreifen, was die Kommunikation und Funktionalität zwischen Client und Server erleichtert.
COM-Objekte sind häufig Gegenstand von Untersuchungen, um die Anfälligkeit für Sicherheitslücken zu bewerten und missbrauchbare Funktionen zu identifizieren. Ein eingeschlossenes COM-Objekt ist eine Fehlerklasse, in 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 Bedingung kann dieser Steuerungsvektor 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 wird im WaaSMedicSvc-Service 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 laterale Bewegungen.
Unsere Forschungsreise begann mit der Untersuchung der COM-Klasse WaaSRemediation, die die Schnittstelle IDispatch unterstützt. Diese Schnittstelle ermöglicht es Clients, eine späte Bindung durchzuführen. Normalerweise haben COM-Clients die Schnittstellen- und Typdefinitionen für die Objekte, die sie verwenden, zur Kompilierungszeit definiert. Stattdessen ermöglicht Late Binding dem Client, Methoden zum Laufzeitpunkt zu entdecken und auf das Objekt anzuwenden. IDispatch enthält die Methode GetTypeInfo, die eine ITypeInfo-Schnittstelle zurückgibt. ITypeInfo bietet Methoden, mit denen man Typinformationen für das implementierte Objekt entdecken kann.
Wenn eine COM-Klasse eine Typbibliothek verwendet, kann diese vom Client über ITypeLib (erhältlich ü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 referenziert WaaSRemediation die Typbibliothek WaaSRemediationLib, welche wiederum auf stdole (OLE Automatisierung) verweist. WaaSRemediationLib nutzt zwei COM-Klassen aus dieser Bibliothek, StdFont und StdPicture. Durch die Durchführung eines COM Hijacking auf dem StdFont Objekt via Änderung des TreatAs Registrierungsschlüssels, zeigt die Klasse auf eine andere COM Klasse unserer Wahl, wie System.Object im Framework .NET. Forshaw weist darauf hin, dass StdPicture nicht in Frage kommt, da dieses Objekt eine Prüfung auf prozessfremde Instanziierung durchführt. Wir haben uns daher auf die Verwendung von StdFont konzentriert.
.NET-Objekte sind für uns interessant wegen der GetType-Methode von System.Object. Über GetType können wir .NET Reflection ausführen, um schließlich auf Assembly.Load zuzugreifen. Obwohl System.Object gewählt wurde, ist dieser Typ zufällig die Wurzel der Typhierarchie in .NET. Daher könnte jedes .NET COM-Objekt verwendet werden.
In der Anfangsphase waren zwei weitere DWORD-Werte unter dem Schlüssel HKLM\Software\Microsoft\.NetFramework erforderlich, um unseren vorgestellten Anwendungsfall zu verwirklichen:
Als wir bei unseren ersten Tests bestätigten, dass die neueste Version von CLR und.NET geladen werden konnte, wussten wir, dass wir auf dem richtigen Weg waren.
Um uns auf die programmatischen Aspekte der Fernsteuerung zu konzentrieren, haben wir zunächst Remote Registry verwendet, um die Werte der.NetFramework-Registrierungsschlüssel zu manipulieren und das StdFont-Objekt auf dem Zielcomputer zu kapern. Als nächstes haben wir CoCreateInstance durch CoCreateInstanceEx ersetzt, um das WaaSRemediation COM-Objekt auf dem Remote-Ziel zu instanziieren und einen Zeiger auf die IDispatch- Schnittstelle zu erhalten.
Mit einem Zeiger auf IDispatch rufen wir die Member-Methode GetTypeInfo auf, um einen Zeiger auf die ITypeInfo-Schnittstelle zu erhalten, die auf dem Server gespeichert ist. Anschließend aufgerufene Member-Methoden werden serverseitig ausgeführt. Nachdem wir die relevante Typbibliotheksreferenz (stdole) identifiziert und die nachfolgende relevante Klassenobjektreferenz (StdFont) abgeleitet hatten, verwendeten wir schließlich die „remotable” CreateInstance-Methode auf der ITypeInfo-Schnittstelle, um den StdFont-Objektverknüpfungsfluss (über vorherige TreatAs-Manipulation) umzuleiten und System.Object zu instanziieren.
Da AllowDCOMReflection korrekt eingestellt ist, können wir anschließend .NET Reflection über DCOM durchfü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 Reflektion finden Sie im folgenden Diagramm:
Unser erstes und wichtigstes Problem war der Aufruf von Assembly.Load_3 über IDispatch->Invoke. Invoke übergibt ein Objekt-Array von Argumenten an die Zielfunktion, und Load_3 ist die Überladung von Assembly.Load , die ein einzelnes Byte-Array akzeptiert. Daher mussten wir den SAFEARRAY von Bytes in einen weiteren SAFEARRAYvon VARIANT s hüllen – anfangs versuchten wir immer wieder, einen einzelnen SAFEARRAY von Bytes zu übertragen.
Ein weiteres Problem war die Suche nach der richtigen Assembly.Load-Überlastung. Die Hilfsfunktionen wurden aus Forshaws CVE-2014-0257-Code übernommen, der die Funktion GetStaticMethod enthielt. Diese Funktion nutzte .NET-Reflexion über DCOM, um eine statische Methode anhand eines Typzeigers, des Methodennamens und der Anzahl ihrer Parameter zu finden. Assembly.Load hat zwei statische Überlastungen, die ein einziges Argument benötigen; Deshalb haben wir letztlich eine hackige Lösung verwendet. Uns wurde klar, dass die dritte Instanz von Load mit einem einzigen Argument unsere richtige Wahl war.
Einer der größten Nachteile, die wir bei dieser Technik beobachtet haben, war, dass die Lebensdauer des erzeugten Beacons auf den COM-Client beschränkt war; in diesem Fall die Lebensdauer unserer Anwendung „ForsHops.exe“ (natürlich elegant benannt). Wenn also ForsHops.exe seine COM-Referenzen bereinigt oder beendet wird, wird auch der Beacon, der unter svchost.exe auf dem Remote-Rechner läuft, beendet. Wir haben verschiedene Lösungen ausprobiert, zum Beispiel dass unsere .NET-Assembler ihren Hauptthread unbegrenzt hängen lässt, Shellcode in einem anderen Thread ausführt und ForsHops.exe den ausnutzen-Thread hängen lässt, aber nichts war elegant.
Im aktuellen Zustand läuft ForsHops.exe so lange, bis der Beacon beendet wird; dann werden die Registry-Operationen entfernt. Es gibt Möglichkeiten zur Verbesserung, aber das überlassen wir dem Leser.
Die von Samir Bousseaden (@SBousseaden) vorgeschlagene Erkennung nachdem Mohamed Fakroud ihre Implementierung veröffentlicht hat, gilt auch für diese Lateralbewegung:
Des Weiteren empfehlen wir die Implementierung der folgenden zusätzlichen Kontrollmaßnahmen:
Nutzen Sie außerdem die folgende YARA-Regel als Proof-of-Concept, um die Standard-Executable ForsHops.exe zu erkennen:
Rule 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 die laterale Bewegung anstelle der lokalen Ausführung für die PPL-Umgehung nutzt. Daher ist es weiterhin denselben Erkennungsmechanismen ausgesetzt wie Implementierungen, die eine lokale Ausführung durchführen.
Den ForsHops.exe Proof-of-Concept-Code für die laterale Bewegung finden Sie hier.
Ein besonderer Dank geht an Dwight Hohnstein (@djhohnstein) und Sanjiv Kawa (@sanjivkawa) für ihr Feedback zu dieser Forschung und die Überprüfung von Blogbeiträgen.