Heute möchten wir Ihnen zeigen, auf welche Weise Experten Malware analysieren.
Wir möchten Ihnen einen Einblick in den Code geben, der eine der raffiniertesten digitalen Bedrohungen darstellt. In diesem aktuellen Fallbeispiel arbeiten wir mit einem Speicherauszug (Absturzabbild) eines mit Uroburos infizierten Systems. Um die Analyse zu erleichtern, haben wir die Erweiterung PyKd hinzugefügt, die zusätzliche Python-Unterstützung bietet. WinDbg verfügt über eine eigene Skriptsprache, ist aber nicht ganz einfach zu verstehen. Die Python-Erweiterung kann hier kostenlos heruntergeladen werden: http://pykd.codeplex.com/
Für diesen Artikel wurde der Computer mit dem Uroburos-Dropper infiziert, der den folgenden md5-Hashwert aufweist: 626576e5f0f85d77c460a322a92bb267.
Visualisierung der Hooks
Das Uroburos-Rootkit fügt mehrere Hooks hinzu, um seine Aktivitäten zu verbergen. In unserem speziellen Fall wird das Hooking als Technik verwendet, um das Verhalten bestimmter Systemfunktionen zu verändern: Das Rootkit täuscht die Ausgabe der Microsoft Windows-API vor. Beispielsweise versteckt es Registry-Einträge, Dateien und vieles mehr.
Für diesen Zweck nutzen die Rootkit-Entwickler Interrupts. Im Folgenden geben wir die Interrupt Descriptor Table (IDT) wieder. In der IDT-Tabelle werden Zeiger auf ISR (Interrupt-Service-Routinen) gespeichert, die aufgerufen werden, wenn ein Interrupt ausgelöst wird.
Das letzte Argument des WinDbg-Befehls ist die zu disassemblierende Länge (L0x16). Die Funktion beginnt mit einer Reihe von Nulloperationen (NOP). Die Malware verwendet den Interrupt 0xC3. Im nächsten Schritt ist zu ermitteln, wie und wann dieser Interrupt ausgelöst wird. Hier ist der Code am Beginn der Funktion IoCreateDevice ():
Wir sehen, dass der zweite Befehl int 0xC3 (Interrupt 0xC3) lautet. Dank der PyKd-Erweiterung können wir sehr einfach ein Python-Skript erstellen, das jede Funktion mit diesem Interrupt erkennt:
Mit der Funktion !chkimg hätten wir den Hook ganz einfach identifizieren können. Es war jedoch eine gute Übung, mit PyKd zu experimentieren.
Ein weiterer interessanter Schritt besteht darin, einen Auszug des Treibercodes zu erstellen. Dazu müssen wir zunächst den Beginn der PE finden. Wir können die Adresse anhand der Adresse des Codes finden, der beim Auslösen eines Interrupt ausgeführt wird:
Diese Ausgabe zeigt uns zwei bemerkenswerte Dinge:
- Zum einen nutzt der Treiber das bekannte Kernel-Memory-Pooltag „NtFs“ von Windows. Die Windows-Komponenten markieren den zugewiesenen Speicherblock mit einem speziellen Tag. Doch das Rootkit verwendet dasselbe Tag wie der legitime Treiber ntfs.sys. Auf diese Weise soll das Rootkit verborgen und der analysierende Experte getäuscht werden.
- Zum andern sieht die Ausgabe wie der Anfang einer PE aus. Doch die PE ist kompromittiert: Der MZ-Header ist nicht verfügbar und einige Informationen fehlen. So ist beispielsweise der Wert für SizeOfImage (85980000+0x140) gleich Null...
Das Rootkit verändert den Anfang der PE, um sich selbst zu verbergen. Einige Tools analysieren den Speicher und suchen nach dem MZ-String, um den Anfang einer PE zu identifizieren. Wenn wir im vorliegenden Fall diese Tools für die Suche nach einer PE-Datei verwendet hätten, wären wir mit dieser Automatisierung niemals in der Lage gewesen, die Malware zu identifizieren. Hier ist eine manuelle Auswertung erforderlich. Um einen Speicherauszug unseres Treibers zu erstellen, müssen wir die PE rekonstruieren. Wie bereits oben erwähnt kennen wir die Größe der Binärdatei jedoch nicht. Deshalb müssen wir einen großen Auszug erstellen, um sicher zu gehen, dass kein Teil der Binärdatei vergessen wird.
In unserem Fall weist das Rootkit das Modul fdisk.sys auf. Laut dem oben angezeigten Code scheint das Modul nicht geladen zu sein. Doch wie wir zuvor analysiert haben, ist der Code tatsächlich in dem infizierten System vorhanden. Die Entwickler haben also eine Möglichkeit gefunden, die Module zu entladen, während der Schadcode noch läuft!
Wir können die Treiber auflisten:
Der von unserem Modul verwendete Treiber ist \driver\Null. Alle anderen Module sind legitime, von Windows verwendete Module. Wir können die Geräte anzeigen, die dem Treiber zugeordnet sind, auf den wir uns konzentrieren:
Zwei Objekte sind besonders interessant: FWPMCALLOUT und RawDisk1. In den folgenden Kapiteln erfahren Sie warum.
WFP callout
Das erste Gerät heißt FWPMCALLOUT. Aufgrund des Gerätenamens können wir vermuten, dass das Rootkit einen Callout für Windows Filtering Platform (WFP) registriert. Bei der WFP handelt es sich um verschiedene API- und Systemdienste, die eine Plattform für die Erstellung von Netzwerkfilteranwendungen bereitstellen. In unserem Fall nutzt das Rootkit diese Technologie, um eine Deep-Packet-Inspection (DPI) und Modifikationen am Netzwerkdatenfluss vorzunehmen. Zweck dieses Geräts ist es, relevante Daten abzufangen und Befehle zu empfangen, sobald eine Verbindung zum Command & Control-Server oder zu anderen infizierten Rechnern der lokalen Umgebung hergestellt wird, welche als Relaisstationen verwendet werden.
Da es keinen Befehl gibt, mit dem man die WFP-Callouts einfach auflisten kann, müssen wir die benötigten Informationen in mehreren Schritten extrahieren:
Zunächst enthält die Variable netio!gWfpGlobal den Ausgangspunkt für die WEP-Datenstrukturen:
Die erste Zahl ist das Offset, das die Gesamtzahl der erstellten Callouts enthält – natürlich in Hexadezimalzahlen:
Die zweite Zahl ist das Offset mit dem Array, in dem die Callout-Struktur gespeichert ist:
Zu guter Letzt verwenden wir einen einzeiligen Befehl, um die Elemente dieses Arrays aufzulisten:
Die Liste der Elemente erinnert uns an die Informationen, die wir in der IDT gesehen haben: Zwei Adressen werden nicht aufgelöst. Diese beiden WFP-Callouts sind: 0x859b5040 und 0x859b5520. WinDbg ist nicht in der Lage, diese beiden Adressen aufzulösen, weil die Adressen nicht bekannt sind. Es sind keine Adressen von Microsoft. Da wir jetzt die Adressen haben, können wir mit dem Befehl !pool bestätigen, dass die Adressen sich in derselben Region befinden wie der Code, der beim Auslösen eines Interrupt ausgeführt wird:
Dank diesem Befehl sind wir in der Lage, die Dateien aufzulisten, die vor dem Betriebssystem verborgen werden.
Zwang zur digitalen Signatur
Microsoft hat für die 64-Bit-Versionen von Windows Vista und für neuere Betriebssysteme eine Treibersignierungsrichtlinie entwickelt. Zum Laden eines Treibers muss die .sys-Datei von einem authentifizierten Herausgeber signiert sein. Entwickler können den Treibersignierungszwang in der Entwicklungsphase eines Treibers deaktivieren. Das heißt, Entwickler müssen in der Entwicklungsphase nicht jede kompilierte Treiberversion signieren. Dieser Modus wird als „Testmodus“ bezeichnet. In unserem Fall ist das Rootkit nicht signiert und hätte daher normalerweise keine Chance, von der Microsoft-Richtlinie akzeptiert zu werden. Es umgeht jedoch die Kontrollen, indem es das digitale Signaturverfahren deaktiviert. Der Status dieser Funktion wird in der globalen Variable nt!g_cienabled gespeichert. Vergleichen Sie den Wert dieser Variablen auf einem sauberen, nicht infizierten System mit denselben Informationen auf einem infizierten System:
Wir können deutlich erkennen, dass die Malware den Treibersignierungszwang deaktiviert hat. Eigentlich könnten wir dasselbe Ergebnis mit dem Befehl bcdedit.exe -set TESTSIGNING OFF erreichen, also mit dem Befehl zum Wechsel in den Testmodus, um den nicht signierten Treiber laden zu können. Der Unterschied ist jedoch folgender: Der Befehl bcdedit.exe löst aus, dass unten auf dem Desktop ein Meldungsfenster angezeigt wird. Diese Methode wäre also nicht gerade unauffällig. Der Vorgang könnte sofort entdeckt werden.
Weitere Informationen zur Umgehung des Treibersignierungszwangs durch die Malware finden Sie in unserem Artikel im SecurityBlog: Uroburos – Detaillierte Analyse der Umgehung des Kernel-Schutzes
Fazit
Was Sie soeben gesehen haben, war nur ein sehr kleiner Ausschnitt aus der umfangreichen Analyse komplexer Malware und eine sehr kurze Einführung in WinDbg. Im Allgemeinen ist es ziemlich schwer, ein derart komplexes Tool zu verstehen. Doch bei der Analyse eines Kernel-Rootkits bleibt den Experten keine andere Wahl.
Die Ergebnisse erscheinen absolut logisch und nachvollziehbar, wenn sie wie hier im Artikel übersichtlich mit Codeausschnitten dokumentiert werden. Aber bitte glauben Sie uns: Die Arbeit mit Malware-Code erfordert viel Training, Erfahrung und Zeit.