Zusammenfassung
Die Play-Ransomware, auch bekannt als PlayCrypt, ist eine Ransomware, die erstmals im Juni 2022 auftauchte. Die Ransomware zielte auf Branchen wie das Gesundheitswesen und die Telekommunikation sowie auf ein breites Spektrum von Regionen wie Lateinamerika, Europa und Nordamerika ab. Die Play-Ransomware ist dafür bekannt, sich über kompromittierte gültige Konten oder durch Ausnutzen bestimmter Schwachstellen Zugriff auf Netzwerke zu verschaffen. Sobald es sich im Netzwerk befindet, nutzt es einen großen Pool bekannter Post-Exploitation-Tools, um seinen Angriff fortzusetzen. Tools wie Bloodhound, PsExec, Mimikatz und AdFind sind einige Beispiele für Tools, die zuvor bei Angriffen mit dieser Ransomware verwendet wurden.
Ein weiterer Aspekt, der die Malware berühmt macht, ist die Vielzahl an Anti-Analyse-Techniken, die sie in ihren Payloads verwendet, wie etwa der Missbrauch von SEH und die Verwendung von ROP zur Umleitung des Ausführungsflusses. Durch den Einsatz von Techniken zur Verlangsamung des Reverse-Engineering-Prozesses erschweren Bedrohungsakteure die Erkennung und Abwehr der Malware.
Bereits im Jahr 2022 veröffentlichten andere Forscher einen hervorragenden Blogbeitrag, in dem sie die Malware selbst und einige der von ihr verwendeten Anti-Analyse-Techniken analysierten. In diesem Blogbeitrag werfen wir erneut einen Blick auf die Anti-Analyse-Techniken der jüngsten Varianten der Play-Ransomware. Wir erklären, wie sie funktionieren und wie wir einige von ihnen mithilfe von Automatisierungsskripten besiegen können.
Renditeorientierte Programmierung (ROP)
Beim Reverse Engineering von Malware müssen wir zunächst sicherstellen, dass der Kontrollfluss nicht verschleiert wird, um die Malware richtig zu verstehen.
Um seinen Kontrollfluss zu verschleiern, verwendet die Play-Ransomware in ihrer Nutzlast häufig eine ROP-Technik. Dies geschieht durch den Aufruf von über hundert Funktionen, die den Wert oben auf dem Stapel patchen und dann den Ausführungsfluss dorthin umleiten. Bevor wir darüber sprechen, wie die Schadsoftware dies genau macht, schauen wir uns zunächst an, wie die Assembleranweisungen CALL und RET im Allgemeinen funktionieren.
Wenn ein CALL erfolgt (in diesem Fall genauer gesagt ein Near Call), schiebt der Prozessor den Wert des Befehlszeigerregisters (in diesem Fall EIP) in den Stapel und verzweigt dann zu der durch den Aufrufzieloperanden angegebenen Adresse, die in diesem Fall ein Offset relativ zum Befehlszeiger ist. Die Adresse im Befehlszeiger plus dieser Offset ergeben die Adresse der aufzurufenden Funktion.
Der RET-Befehl hingegen zeigt das Ende eines Funktionsaufrufs an. Dieser Befehl ist für die Übertragung des Programmkontrollflusses an die Adresse oben auf dem Stapel verantwortlich. Und ja, dies ist genau die Adresse, die ursprünglich durch den Aufrufbefehl gesendet wurde!
Unter Berücksichtigung des Gesagten wäre im Idealfall die hervorgehobene Adresse im Bild unten die nächste Anweisung, die nach einem Aufruf der Zielfunktion (sub_42a4b9) ausgeführt werden würde:
Wie die Malware die Funktionsweise der CALL- und RET-Anweisungen missbraucht, lässt sich im folgenden Bild beobachten:
Sobald die Funktion aufgerufen wird, wird die Adresse 0x42a4b4 in den Stapel geschoben, sodass ESP darauf zeigt. Die aufgerufene Funktion addiert dann den Wert 0xA zur von ESP angezeigten Adresse und kehrt anschließend mithilfe der RET-Anweisung zurück. Diese Vorgänge führen dazu, dass der Kontrollfluss zu 0x42a4be (0x42a4b4 + 0xa) statt zu 0x42a4b4 umgeleitet wird.
Durch die Anwendung dieser Technik macht die Schadsoftware nicht nur die statische Analyse komplexer, da der Programmfluss nicht trivial ist, sondern kann auch das Debuggen erschweren, denn wenn Sie diese Art von Funktion überspringen, können viele Dinge passieren, bevor die reguläre „nächste Anweisung“ ausgeführt wird.
Eine weitere Möglichkeit, mit der die Malware diese ROP-Technik implementiert, ist die Verwendung des im folgenden Code gezeigten Ansatzes, der bei Shellcodes sehr verbreitet ist. Der durch den Zieloperanden der Aufrufanweisung angegebene Offset ist Null, wodurch die Adresse der aufzurufenden Funktion genau der Adresse der nächsten Anweisung entspricht. Diese Adresse wird dann oben auf den Stapel gelegt und die restlichen Vorgänge sind genau dieselben wie im vorherigen Beispiel:
Um die Analyse der Play-Ransomware zu unterstützen, hat Netskope Threat Labs auf Grundlage früherer Arbeiten anderer Forscher ein Skript entwickelt, um die eingesetzte ROP-Verschleierung zu beheben.
Das Skript sucht nach möglichen ROP-Kandidaten, sammelt den Offset, der oben auf dem Stapel hinzugefügt werden soll, und patcht die Adressen, die die ROP-Aufrufe ausführen, mit einem absoluten Sprung, wobei das Ziel die zur Laufzeit berechnete geänderte Transferadresse ist.
Nachfolgend sehen Sie ein Beispiel dafür, wie die Malware-Nutzlast vor und nach der Skriptausführung aussehen würde:
Vor:
Nach:
Anti-Demontage
Eine Anti-Disassemblierungstechnik, mit der Analysten und Disassembler ausgetrickst werden, besteht darin, den Ausführungsfluss auf Ziele zu übertragen, die sich in der Mitte anderer gültiger Anweisungen befinden.
Nehmen wir als Beispiel den Funktionsaufruf bei 0x42a4af, der im obigen ROP-Abschnitt verwendet wird. Die Opcodes für diesen CALL-Befehl sind „E8 05 00 00 00“. Das Byte 0xE8 ist der Operationscode des CALL-Befehls selbst und die anderen 4 Bytes stellen den Zieloperanden dar (den Offset relativ zu EIP).
Wie wir bereits besprochen haben, wäre die Adresse der aufzurufenden Funktion der Wert von EIP (0x42a4b4) + der Offset (0x5), und das ergibt die Adresse 0x42a4b9. Dieser Wert fällt jedoch in das letzte Byte einer anderen gültigen Anweisung bei 0x42a4b5:
An der Ausführung ändert sich durch dieses Verhalten nichts, da der Prozessor die Anweisungen korrekt versteht. Allerdings kann es sein, dass ein Disassembler die Anweisungen nicht korrekt darstellt, je nachdem, welchen Ansatz er verwendet (z. B. linearer Sweep), was die statische Analyse etwas knifflig macht.
Das von uns zum Beheben der ROP-Aufrufe bereitgestellte Skript behandelt dieses Szenario auch für die ROP-Ziele. Wenn man bedenkt, dass wir einen JMP-Befehl zum Patchen der Aufrufe verwenden, zwingen wir letztendlich auch den Disassembler, den richtigen Ablauf zu verstehen.
Junk-Code
Obwohl es sich hierbei um eine sehr einfache Technik handelt, ist sie dennoch erwähnenswert, da sie die Analyse der Malware deutlich verlangsamen kann. Bei der Einfügungstechnik für Junk-/Garbage-Code handelt es sich genau um das, was der Name vermuten lässt: das Einfügen unnötiger Anweisungen in die Binärdatei.
Anders als bei den bisher vorgestellten Techniken lässt sich der Disassembler durch das Einfügen von Junk-Code nicht austricksen, es kann jedoch dazu führen, dass Zeit mit der Analyse unnötigen Codes verschwendet wird. Die Play-Ransomware verwendet dies recht häufig, insbesondere bei den Zielen für ROP-Aufrufe.
Strukturierte Ausnahmebehandlung (SEH)
Eine weitere von der Malware verwendete Anti-Analyse-Technik ist der Missbrauch eines Windows-Mechanismus namens „Strukturierte Ausnahmebehandlung“ , der zur Behandlung von Ausnahmen dient.
Im Windows-Betriebssystem hat jeder Thread eine Struktur namens Thread Environment Block (TEB). In einer x86-Umgebung befindet sich die Adresse von TEB im FS-Register und enthält für den Thread selbst nützliche Informationen und befindet sich im Prozessadressraum. Das erste Feld dieser Struktur ist eine weitere Struktur namens Thread Information Block (TIB) und das erste Element dieser Struktur enthält eine Liste sogenannter „Ausnahmeregistrierungsdatensätze“.
Jeder dieser Datensätze besteht aus einer Struktur, die zwei Werte enthält. Der erste ist ein Zeiger auf den „nächsten“ Datensatz in der Liste und der zweite ist ein Zeiger auf den Handler, der für die Behandlung der Ausnahme verantwortlich ist.
Einfach ausgedrückt wird beim Auftreten einer Ausnahme der letzte der Liste hinzugefügte Datensatz aufgerufen und entschieden, ob er die ausgelöste Ausnahme behandelt oder nicht. Wenn dies nicht der Fall ist, wird der nächste Handler in der Liste aufgerufen und so weiter, bis das Ende der Liste erreicht ist. In diesem Fall wird der Standard-Windows-Handler aufgerufen.
Play missbraucht diese Funktion, indem es seinen eigenen Ausnahmehandler in die Ausnahmebehandlungsliste einfügt und dann eine Ausnahme erzwingt. Im folgenden Beispiel enthält das EBX-Register die Adresse des Ausnahmehandlers der Malware. Sobald dieser als erstes Element der Liste eingefügt ist (die vier hervorgehobenen Anweisungen oben), setzt die Malware EAX auf Null und dividiert es durch Null, wodurch eine Ausnahme verursacht wird (die beiden hervorgehobenen Anweisungen unten):
Sobald die Ausnahme ausgelöst wird, wird der letzte registrierte Handler aufgerufen. Die Malware verwendet diesen ersten Handler, um sich zu registrieren und einen zweiten aufzurufen, indem sie eine zweite Ausnahme erzwingt, jetzt jedoch über die INT1-Anweisung, um eine Debug-Ausnahme zu generieren. Der zweite registrierte Handler ist für die weitere Ausführung der „normalen“ Malware verantwortlich.
Diese Technik kann beim Debuggen der Malware sehr lästig sein, da der Debugger die Ausführung beim Auftreten der Ausnahme stoppen würde, was uns dazu zwingt, den Ausnahmehandler zu finden und vorher sicherzustellen, dass wir die Kontrolle darüber haben.