Das Studium eines böswilligen

Bild

Ich bin auf eine kürzlich bösartige Dokumentdatei gestoßen, die mit Phishing-E-Mails gesendet wurde. Ich entschied, dass dies ein guter Grund ist, Reverse Engineering zu üben und etwas Neues über Habr zu schreiben. Unter der Katze - ein Beispiel für das Parsen eines böswilligen Makro-Droppers und nicht weniger bösartiger DLLs.

Makro


Sha256 aus der Datei - abb052d9b0660f90bcf5fc394db0e16d6edd29f41224f8053ed90a4b8ef1b519 . In der Dokumentdatei selbst befindet sich auf der ersten Seite ein Bild, das darüber informiert, dass diese Datei geschützt ist, und erklärt, wie Makros aktiviert werden. Die Datei enthält zwei große Tabellen mit Zahlen. Zahlen werden in Dezimalform geschrieben, die längsten sind zehnstellig, es gibt sowohl positive als auch negative.

Wenn das Opfer die Ausführung von Makros zulässt (gibt es diejenigen, bei denen diese standardmäßig aktiviert ist?), Wird eine Aktionskette ausgelöst, die letztendlich die Funktion updateb_network ausführtHiermit wird das aktuelle Verzeichnis in ein temporäres Verzeichnis geändert und die darin enthaltene Datei "icutils.dll" erstellt, in der die Zahlen aus der ersten Tabelle in einer Reihe als 32-Bit-Ganzzahl mit einem Vorzeichen notiert werden. Das Ergebnis ist die richtige DLL. Die Klonfunktion wird aus dieser DLL importiert :

Declare PtrSafe Function clone Lib "icutils.dll" _
(ByVal Saved As String, ByVal Time As Integer) As Boolean

Und es beginnt mit zwei Parametern:

R1 = Module1.clone("Cream", 0)

Wenn der Klon Aufruf False zurückgibt, wird die icutils.dll Datei mit Daten aus der zweiten Tabelle und Klon mit den gleichen Parametern überschrieben wieder aufgerufen wird.

Mit Blick auf die Zukunft werde ich sagen, dass die erste DLL 64-Bit ist und nicht auf 32-Bit-Systemen ausgeführt werden kann. Somit wählt das Makro die richtige Binärcode-Architektur aus.

Interessanterweise hat die aktualisierte Funktion b_network einen Code, der keinen funktionalen Zweck hat:

Sub updatedb_network()
...
Dim query_to_change As Variant
    Set query_to_change = CurrentDb.QueryDefs("query_name")
    
    query_to_change.SQL = "SELECT * FROM Table ORDER BY ID Asc"
    query_to_change.SQL = "SELECT Field1, Field2 FROM Table ORDER BY ID Asc"
    query_to_change.SQL = "SELECT Field1, Field2 FROM Table WHERE Field LIKE Fashion"
    query_to_change.SQL = "SELECT Field1, Field2 FROM Table WHERE Field LIKE '" & something & "'"
...
End Sub

Vielleicht ist er hier, um denjenigen, die schnell durch den Code scrollen, einige Zeilen in SQL sehen und denken, dass alles in Ordnung ist, den Anschein einer nützlichen Arbeit zu erwecken? Weiß nicht. Außerdem haben die meisten Funktionen und Variablen zufällige oder nicht reelle Namen (z. B. updateb_network , das nicht mit der Datenbank oder dem Netzwerk interagiert). Obwohl es zum Beispiel die Funktion dump_payload gibt , die 4 Bytes in icutil.dll speichert. In jedem Fall sollte das Vorhandensein der Document_Open- Funktion sofort darauf hinweisen , dass Autoren der Malware sie nicht willkürlich umbenennen können (obwohl sie stattdessen eine andere automatisch gestartete Funktion verwenden können).

Die Makrofunktionalität ist also mehr oder weniger klar. Es ist Zeit, die DLL zu entladen und mit ihrer Analyse fortzufahren.

Erste DLL


Die erste DLL (sha256 7427cc4b6b659b89552bf727aed332043f4551ca2ee2126cca75fbe1ab8bf114 ) 64-Bit.

Die Liste der importierten Funktionen enthält die Funktionen CreateProcessW (Programmstart), CreateRemoteThread (Erstellen eines Threads in einem anderen Prozess), VirtualAllocEx ( Zuweisen eines Speicherblocks in einem anderen Prozess), WriteProcessMemory (Schreiben in den Speicher eines anderen Prozesses), die sofort das Einfügen von Code in einen anderen Prozess vorschlagen Prozess. Nun wollen wir sehen, was genau sie mit IDA Free und Ghidra macht.
Der Haupteinstiegspunkt gibt einfach 1 zurück, macht sonst nichts. Die zweite exportierte Funktion ist der Klon, der vom Makro aufgerufen wird und schädlichen Code enthält.
Die Parameter, mit denen es aufgerufen wird, scheinen nichts zu beeinflussen. Die Anwendung entschlüsselt zwei Datenblöcke. Der erste 0x78-Datenblock mit folgendem Inhalt (bereits entschlüsselt):

https://pastebin.com/raw/Jyujxy7z\x00\x00\x00\x00\x00\x00\x00\xf2i\xe0\x1d\x95h\xbc\x03\xe4#\xe0\x1d<\x04\xe0\x1d\xe6\x00\xde\x01\xa4\x17\xbc\x03x\x01\xe0\x1d\xe2\x16x\x07Qy\xbc\x03@Fx\x07Df\xbc\x03\x89a\xde\x01q\x11\xe0\x1d|Ix\x07D@\xbc\x03\x8a\x01\xde\x01^9\xde\x01\xf2i\xe0\x1d\x95h\xbc\x03\xe4#\xe0\x1d\xab

Der zweite Datenblock ist 0x1D4C lang und enthält ausführbaren Code.

Außerdem werden ein Zeiger auf das Kernel32-Modul, das Ergebnis der GetTickCount () -Funktion und die Adresse der ZwDelayExecution () -Funktion von Kernel32 in die 0x90-Bytestruktur geschrieben .

Anschließend wird der Prozess ( CreateProcessW ) "cmd.exe" erstellt. Mit VirtualAllocEx werden zwei Puffer zugewiesen: mit RW-Berechtigungen mit einer Länge von 0x108 und mit RWX-Berechtigungen mit einer Länge von 0x1D4C. Der RW-Puffer kopiert den obigen Datenblock und die zuvor erwähnte Struktur mit einer Länge von 0 × 90. Die Struktur schreibt auch einen Zeiger auf den entschlüsselten Datenblock (im Adressraum des untergeordneten Prozesses (cmd.exe)). In RWX wird der Puffer kopiert ( WriteProcessMemory)) entschlüsselter Datenblock mit Code.
Anschließend wird im Prozess cmd.exe ein Stream ( CreateRemoteThread ) mit einem Einstiegspunkt am Anfang des RWX-Puffers erstellt. Ein Zeiger auf den RW-Puffer wird als Argument übergeben. Damit ist die Klonfunktion abgeschlossen. Die Aktion wird im Prozess cmd.exe fortgesetzt.

Interessanterweise scheint die Klonfunktion wie ein unerreichbarer Code zu sein, der die Bibliothek " WorkPolyhistor " importiert ( LoadLibraryW ) .

Der in cmd.exe eingefügte Code


Es führt die folgenden Aktionen aus:

  • findet die Adressen der notwendigen Funktionen aus kernel32.dll (seine Adresse wird vom übergeordneten Prozess bezogen)
  • Lasten Ntdll , OLE32 , User32 Bibliotheken
  • Findet Adressen der erforderlichen Funktionen in diesen Bibliotheken.

Es ist interessant, dass es für die meisten Funktionen im Code keinen Funktionsnamen gibt, sondern nur CRC32 im Auftrag von (alle Funktionsnamen aus der geladenen Bibliothek werden durchsucht, bis eine Funktion mit dem gewünschten CRC32 im Auftrag von vorhanden ist). Möglicherweise ist dies ein Schutz gegen das Abrufen der Liste der importierten Funktionen durch das Dienstprogramm "Strings", obwohl es seltsam ist, dass in verschlüsselter Form gespeicherter Code einen solchen Schutz bietet, während die DLL selbst Funktionen einfach nach Namen importiert. Insgesamt werden folgende Funktionen erkannt:

kernel32:

  • GetProcAddress
  • Bibliothek laden
  • Globalalloc
  • GetTempPath
  • GetFileAttributesW
  • CreateProcessW
  • Globalfrei
  • GlobalRealloc
  • Schreibdatei
  • CreateFileW (nach Namen gefunden)
  • Schreibdatei
  • Closehandle
  • Gettickcount
  • ReadFile
  • GetfileSize

ntdll:

  • RtlCreateUnicodeStringFromAsciiz
  • ZwDelayExecution
  • ZwTerminateProcess
  • swprintf

ole32:

  • CoInitialize (namentlich gefunden)
  • CoCreateInstance (nach Namen gefunden)

msvcrt:

  • Rand
  • srand

Als Nächstes erhält der Prozess, der GetTempPath verwendet, den Pfad zum temporären Verzeichnis, erstellt darin eine Datei mit dem Namen 26342235.dat, wobei der Dateiname der vom übergeordneten Prozess empfangene Dezimaldatensatz von TickCount ist und bei jedem neuen Versuch wiederholt wird (d. H. Wenn die Nutzdaten nicht heruntergeladen werden konnten) Beim ersten Versuch wird beim zweiten Versuch eine Datei mit dem Namen 26342236.dat erstellt. Danach wird die Wininet-Bibliothek geladen und es gibt Zeiger auf folgende Funktionen:

  • InternetCloseHandle (crc32: 0xe5191d24)
  • InternetGetConnectedState (crc32: 0xf2e5fc0c)
  • InternetOpenA (crc32: 0xda16a83d)
  • InternetOpenUrlA (crc32: 0x16505e0)
  • InternetReadFile (crc32: 0x6cc098f5)

Mit InternetGetConnectedState geprüft , ob es ein Netzwerk ist - wenn nicht, die Anwendung die nicht existente Adresse nennt und fällt (wie zum Schutz der Adresse bestimmen , wo es stellt sich peyload aus der Maschine Netzwerk isoliert verwendet , ist der einzige Fall , wenn die Anwendung nicht normal beendet wird , den Rest -. Aus 3 Versuche , wonach cmd.exe mit ZwTerminateProcess beendet wird ). Wenn ein Netzwerk vorhanden ist, werden die Nutzdaten mithilfe der gefundenen Funktionen von der vom übergeordneten Prozess (https://pastebin.com/raw/Jyujxy7z) übergebenen URL heruntergeladen und in der zuvor erstellten Datei mit der Erweiterung .dat gespeichert.

Als nächstes wird die Nutzlast aus der .dat-Datei gelesen, dekodiert (base64), mit XOR mit CRC32 von der URL entschlüsselt. Überprüfen Sie, ob die ersten 2 Bytes der entschlüsselten Daten 'MZ' sind. Wenn ja, wird das Ergebnis in einer Datei mit demselben Namen, aber derselben Erweiterung gespeichert. exe

Python-Entschlüsselungscode
from binascii import crc32
from base64 import b64decode


def decrypt_payload(payload_b64: bytes, url: str):
    payload_bin = b64decode(payload_b64.decode())
    key = str(crc32(url.encode())).encode()
    decrypted = bytearray()
    for i, b in enumerate(payload_bin):
        decrypted.append(b ^ key[i % len(key)])
    return bytes(decrypted)

Mit der Funktion CreateProcessW wird die gespeicherte Datei gestartet. Wenn alles gut geht, wird der Prozess cmd.exe mit ZwTerminateProcess beendet . Wenn etwas schief gelaufen ist (außer dem Fehlen eines Netzwerks), wird alles neu wiederholt, es werden maximal 3 Versuche unternommen, und die Namen der dat- und exe-Dateien werden jedes Mal um 1 erhöht.

Zweite DLL


Die zweite DLL (sha256 006200fcd7cd1e71be6c2ee029c767e3a28f480613e077bf15fadb60a88fdfca ) 32 Bit.

Darin ist die wichtigste bösartige Funktionalität in der Klonfunktion implementiert . Es entschlüsselt auch 2 Puffer. Der erste Puffer hat eine Größe von 0x78 (120) Bytes, solche Daten werden entschlüsselt und in ihn geschrieben (in entschlüsselter Form):

https://pastebin.com/raw/Jyujxy7z\x00\x00\x00\x00\x00\x00\x00\x1e(\xf0\x0e\xc5r\xc0;\x12)\xc0;Jr\xc0;Y4\xbc\x03/Mx\x07\x038\xde\x01\x9e\x05\xe0\x1d#\x08\xbc\x03\xeeU\xf0\x0e\x18{x\x078\x1a\xf0\x0e\xccg\xf0\x0eze\xde\x01\x89&\xe0\x1d\xf6\x1f\xe0\x1d

Es ist zu sehen, dass am Anfang dieselbe URL wie in der x64-Version ist.

Ein zweiter Puffer der Größe 0x4678 Byte wird mit RWX-Berechtigungen zugewiesen. Der Code wird darin entschlüsselt, woraufhin eine Funktion mit einem Offset von 0x4639 vom Anfang des Puffers aus aufgerufen wird.

Ich habe diesen Code nicht im Detail analysiert. Er findet auch Funktionen auf CRC32, startet notepad.exe und fügt dort Code ein, der Nutzdaten von derselben URL auf pastebin herunterlädt.

Nutzlast mit Pastebin


Die mit Pastebin entschlüsselte Nutzlast ist eine 32-Bit-Exe-Datei (sha256 9509111de52db3d9a6c06aa2068e14e0128b31e9e45ada7a8936a35ddfaf155f ). Ich habe sie aus Zeitgründen noch nicht im Detail zerlegt.

Fazit


Im Allgemeinen hat mich die Malware mit vielen Fehlern ziemlich schlecht geschrieben beeindruckt (ich nenne sie hier nicht absichtlich). Als würden sie aufpeitschen.
DLL findet in Speicherfunktionen, die später nirgendwo verwendet werden. Möglicherweise wird dieser Code wie ein Makro regelmäßig von Cyberkriminellen neu geschrieben, wenn er von Virenschutzprogrammen erkannt wird, wodurch solche Artefakte im Code verbleiben.

Es ist auch interessant, dass in der "DLL" -Version der DLL, die auf der x64-Festplatte "abgelegt" wird, die Namen der "gefährlichen" importierten Funktionen nicht maskiert sind (Sie können sie zumindest als Zeichenfolgen sehen) und in dem Code, der im Speicher entschlüsselt ist und nicht auf die Festplatte passt, sich auf CRC32 befinden Name, nicht nur mit Namen.

Die Pastebin-Nutzlast wurde einige Tage später entfernt.

PS KDPV von hier genommen

All Articles