In der vorherigen Berichterstattung von Elastic Security Labs über REF6598 wurde ein Angriffsset dokumentiert, dessen Windows-Toolchain über den Missbrauch des Obsidian-Plugins eingeschleust, über einen im Arbeitsspeicher befindlichen PE-Loader (PHANTOMPULL) eskaliert und mit einem RAT (PHANTOMPULSE) abgeschlossen wurde. In diesem Beitrag ging es um die Lieferung. Dieser Beitrag analysiert die letzte Phase: PHANTOMPULSE, ein Implantat, das drei Prozessinjektionstechniken mitbringt, seine C2-Authentifizierung über Ethereum/Base/Optimism-Transaktionseingaben auflöst und die UAC über die öffentliche schuac -Technik umgeht. Die Analyse fördert einen Blockchain-C2-Kanal zutage, der für Sinkholes anfällig ist, ein einheitliches Hardware-Breakpoint-Primitiv, das AMSI / WLDP / ETW deaktiviert, sowie allgegenwärtige KI-gestützte Entwicklungsfingerabdrücke in den Debug-Strings des Implantats.
Wichtigste Erkenntnisse
- PHANTOMPULSE implementiert drei Injektionstechniken, die von kürzlich veröffentlichten Proof-of-Concepts für offensive Sicherheitsmaßnahmen abgeleitet wurden.
- AMSI, WLDP und ETW werden durch ein einzelnes gemeinsam genutztes HWBP-Primitiv umgangen.
- Der Blockchain-C2-Resolver verfügt über keine Absenderverifizierung, wodurch ein Verteidiger die C2-URL für jedes Implantat durch das Posten einer einzigen Transaktion überschreiben kann.
- Starke Indikatoren für KI-gestützte Entwicklung sind im Binärsystem vorhanden.
Eine Anmerkung zur KI-gestützten Entwicklung
PHANTOMPULSE weist deutliche Spuren von KI-gestützter Codierung auf, die in den Debug-Strings sichtbar sind.
Die deutlichsten Aussagen lauten:
- Strukturierte Schrittnummerierung in Betriebsprotokollen:
[STEP 1] Staged mode — payload downloaded from C2 at runtime,[STEP 1/3] Scheduled Task (DotNetSvcUpdateTask, logon + every 3 min),[STEP 2/3] Boot Task (DotNetSvcCoreTask, INTERACTIVE_TOKEN + BootTrigger),[UNINSTALL 4/6] Removing persist_loader DLL + registry PE data...,[REPAIR] Reinstalling boot task (INTERACTIVE_TOKEN).... - ENTER/DONE Funktionsverfolgung:
"[HEIS] encrypt_text_only ENTER"/"[HEIS] encrypt_text_only DONE","KeylogResolveAPIs: ENTER". Der Diagnosestil von LLMs wird beim Generieren neuer Funktionen standardmäßig verwendet. - Ausführliche Diagnose:
"FindHostProcessEx: scan stats: total=%lu sessSkip=%lu openFail=%lu native=%lu wow64=%lu mapReject=%lu dbgReject=%lu sess=%lu","ManualMap: thread hijacked and resumed — DLL injection via thread hijack complete". Selbsterklärende Ausgabe, ungewöhnlich gesprächig für Schadsoftware. - Gedankenstriche in C-Strings:
"elevate: FAIL — no deployed DLL path",">>> .elevate: NOT proxy — spawning trusted host to handle elevation".
Ausführungskette
MainEntryLogic ist die Orchestrierungsfunktion, die die vollständige Initialisierungssequenz ausführt, bevor die C2-Schleife betreten wird:
start
└─ WinMain
└─ MainEntryLogic
1. DynInit // Bootstrap API resolution
2. ElevationStateCheck // ".elevate" marker detection, routes by token elevation state
3. SingleInstanceCheck // XOR-decrypted mutex, exit if already running
4. EvasionInit // Direct syscalls + ETW HWBP
5. SyscallResolverInit // CPUID + hash-based kernel32 resolution
6. SleepMaskInit // Sleep obfuscation setup
7. ComputeMachineID // DJB2(module name) ^ volume serial
8. IsRunningHollowed // Process hollowing self-check
9. CollectSysInfo // CPU, GPU, RAM, OS, AV, apps
10. FilelessPersist // Drop stub DLL, registry artifact
11. InstallPersistence // Three scheduled tasks via COM ITaskService
12. C2Loop_Init → C2Loop_Main
Beim Start berechnet das Implantat DJB2 einen Hashwert für Benutzername und Computername und schlägt diese jeweils in einer vorab berechneten Tabelle nach. Ein Spiel wird beendet. Durch eine Brute-Force-Attacke auf die Tabelle anhand öffentlicher Anti-Sandbox-Wortlisten wurden 20 der 61 Einträge wiederhergestellt: WDAGUtilityAccount (Windows Defender Application Guard), mehrere DESKTOP-XXXXXXX Standard-VM-Namen und die Joe Sandbox-Personas (abby, patex, george, john, lisa, frank, RDhJ0CNFevzX).
Tarnung
Direkte Systemaufrufe und API-Wrapper
PHANTOMPULSE löst ntdll-Funktionen auf, indem es PEB→Ldr mit DJB2-Hashes durchläuft, extrahiert System Service Numbers (SSNs) aus dem Prolog jeder NT-Funktion und erstellt private syscall-Stubs. Diese Stummel sind von übergeordneten Hilfsstrukturen umhüllt, die im restlichen Implantat verwendet werden:
NtCreateFile_WrapNtWriteFile_WrapNtClose_WrapNtCreateSection_WrapNtMapViewOfSection_WrapNtProtectVirtualMemory_WrapNtWriteVirtualMemory_Wrap
Der Rest des Implantats ruft diese Wrapper anstelle von kernel32/ntdll Exporten auf und umgeht damit Benutzermodus- ntdll -Hooks (IAT-Ersetzungen, Inline-Umleitungen oder Trampolin-Patches), die EDR-Produkte in die dokumentierte API-Oberfläche einfügen.
Eine einzige Hilfsfunktion leitet jeden Festplattenschreibvorgang direkt über NtCreateFile + NtWriteFile , wobei bei Zugriffsfehlern ein Lösch- und Wiederholungsversuch erfolgt.
String- und Konfigurationsverschleierung
PHANTOMPULSE verwendet vier XOR-Ebenen für verschiedene Artefakte:
| Was | Schlüssel | Wo der Schlüssel wohnt |
|---|---|---|
| C2-Fallback-URL, Mutex, Drop-Pfad-Dateinamen | 16 Byte: F7 7C 8E 40 DF C1 7B E5 E7 4D 86 79 D5 B3 53 41 | Eingebettet in .rdata |
| Hostnamen von Blockchain-Anbietern (UTF-16 LE) | 8-Byte: 5A 3C 7E 1D 9F 2B 4E 8A | Eingebettet in .rdata |
| COM-Höhenmoniker, Nutzdaten der Keylog-Datei | 0xE95CA237, wird zur Laufzeit berechnet, um die Konstante aus dem Kontext herauszuhalten .rdata | Berechnet, nicht gespeichert |
C2-URL aus Blockchain-Transaktion extrahiert input | Die Resolver-Wallet-Adresse selbst | Wiederverwendet vom öffentlichen Lookup-Schlüssel |
AMSI-, WLDP- und ETW-Umgehung über Hardware-Haltepunkte
PHANTOMPULSE deaktiviert AMSI, die Code-Vertrauensprüfung der Windows-Sperrrichtlinie und die ETW-Telemetrie durch ein einziges gemeinsames Primitiv: einen Hardware-Haltepunkt, der bei jedem API-Eintrag gesetzt wird und von einem vektorisierten Ausnahmebehandler abgefangen wird, der den Rückgabewert ohne Inline-Patching fälscht.
| Slot | Ziel-API | Gefälschte Rückgabe (RAX) |
|---|---|---|
| DR0 | WldpQueryDynamicCodeTrust | 0 (S_OK) |
| DR1 | AmsiScanBuffer | 0x80070057 (E_INVALIDARG) |
| DR2 | EtwEventWrite | 0 (STATUS_SUCCESS) |
Der Mechanismus, Schritt für Schritt:
- Das Implantat löst die Ziel-API auf. AMSI und WLDP verwenden
LoadLibraryA+ hashbasierte Exportsuche; ETW verwendet einen PEB→Ldr-Pfad, da ntdll bereits geladen ist. - Der HWBP-Deskriptor (Ziel-API-Adresse, Modus, gefälschter Rückgabewert) wird in einen von vier 40-Byte-Slots in einer globalen Slot-Tabelle geschrieben.
- Ein Hilfsthread unterbricht den Zielthread, ruft
NtGetContextThread/NtSetContextThreadauf, um DR0–DR3 + DR7 zu schreiben, und setzt ihn dann fort. (Falls der Vektor-Ausnahmebehandler des Implantats bereits installiert ist, wird stattdessen eine In-Process-AusnahmeSTATUS_BREAKPOINTausgelöst, sodass der VEH die Steckplatztabelle lesen und die DRs ohne Hilfsthread programmieren kann.) - Wenn die geschützte API aufgerufen wird, löst die CPU bei der ersten Anweisung der Funktion
Debug Exception-Ausnahme aus. - Der Vektor-Ausnahmebehandler des Implantats fängt die
Debug Exceptionab, durchläuft seine 4-Slot-Tabelle, um die Auslöseadresse zu finden, und ändert den Thread-Kontext:CONTEXT.Raxwird auf den pro Slot gefälschten Rückgabewert gesetzt,CONTEXT.Ripwird zu einem vorab gespeicherten "skip"-Thunk umgeleitet, der zum Aufrufer zurückkehrt. - Der Handler gibt
EXCEPTION_CONTINUE_EXECUTIONzurück. Der Anrufer sieht den gefälschten RAX-Befehl so, als ob die API ausgeführt worden wäre.
Der Dispatcher bedient zwei Wege. Ein Handler (VEH_Dispatcher) verarbeitet sowohl die eigenen RaiseException(STATUS_BREAKPOINT) Aufrufe des Implantats (die verwendet werden, um die DR-Register aus der Slot-Tabelle zu initialisieren und neu zu programmieren) als auch die STATUS_SINGLE_STEP Ausnahmen, die beim Aufruf einer geschützten API ausgelöst werden. Der Ausnahmecode steuert den Zweig: STATUS_BREAKPOINT löst DR-Programmierung aus, STATUS_SINGLE_STEP löst den Spoof aus.
Der Handler ist ebenfalls nicht direkt registriert. AddVectoredExceptionHandler empfängt einen winzigen JMP-Thunk, der zur Laufzeit in einer neuen MEM_PRIVATE Seite (VirtualAlloc + VirtualProtect bis PAGE_EXECUTE_READ) zugewiesen wird. Der Thunk ist ein JMP [RIP-relative] indirekter Sprung (6-Byte-Opcode FF 25 00 00 00 00), gefolgt von der Adresse des Dispatchers. Da niemals Bytes in AmsiScanBuffer, WldpQueryDynamicCodeTrust oder EtwEventWrite geschrieben werden, wird dies bei der signaturbasierten Erkennung, die nach Prolog-Patches sucht, vollständig übersehen.
Build-Variante: Aktive und inaktive Subsysteme
Mehrere Subsysteme existieren in der Binärdatei als Code oder Zeichenketten, sind aber in dieser Version nicht aktiv. Dies ist eine abgespeckte Version einer größeren Codebasis.
- NTDLL-Unhooking: Debug-Strings für ein Unhooking-Subsystem befinden sich in
.rdata(UnhookNtdll: ntdll base = %p,applied %d relocation fixups to .text), aber es gibt keine Referenzen darauf. In dieser Variante tot. - Registry-resident PE Blob Loader: Frühere Builds speicherten die nächste PE-Stufe innerhalb der Registry. Diese Version tut dies nicht, aber die Deinstallationsroutine entfernt trotzdem den alten Registry-Blob.
- COM-Hijack-Persistenz: wurde von diesem Build nie installiert. Die Bereinigungslogik hierfür verbleibt in der Deinstallationsroutine.
- Persistenz des Druckmonitors: gleiches Muster wie bei COM-Hijacking; Installationspfad fehlt, Deinstallationspfad bleibt erhalten.
Die letzten drei (Registry-Blob-Loader, COM-Hijack, Druckmonitor) zeigen das gegenteilige Muster: Bereinigungslogik ohne Installationslogik, beibehalten aus Gründen der Abwärtskompatibilität mit älteren Bereitstellungen.
| Feature | Nutzlasten erstellen | Beweis |
|---|---|---|
| Direkte Systemaufrufe (SSN-Extraktion) | Aktiv | SSN-Extraktion + Stub-Generierung bestätigt |
| AMSI / WLDP / ETW HWBP-Umgehung | Aktiv | DR0/DR1/DR2 über gemeinsam genutzten Hilfsthread-Primitiv |
| Drei-Wege-Prozesseinspritzung | Aktiv | PhantomInjectDbgNexum und ManualMap sind alle funktional. |
| Blockchain C2-Auflösung | Aktiv | Drei Blockscout-Anbieter wurden befragt |
| NTDLL-Abkopplung | Toter Code | Zeichenketten vorhanden, keine Code-Referenzen |
| HEIS-Verschlüsselung | Deaktiviert | Code-Stub für Verschlüsselung/Entschlüsselung |
| Registry-resident PE Blob Loader | Legacy-only | Wird nur während der Deinstallation bereinigt. |
| COM-Hijacking-Persistenz | Legacy-only | Wurde während der Deinstallation bereinigt, nie installiert |
| Druckmonitorpersistenz | Legacy-only | Wurde während der Deinstallation bereinigt, nie installiert |
| Köderschnüre | Aktiv | 4 nicht referenzierte Köderzeichenketten in .rdata |
Command and Control
Blockchain C2-Auflösung
PHANTOMPULSE dezentralisiert die C2-Suche durch drei Blockscout-Anbieter:
eth.blockscout[.]com(Ethereum L1)base.blockscout[.]com(Basis L2)optimism.blockscout[.]com(Optimismus L2)
Die Wallet-Adresse 0xc117688c530b660e15085bF3A2B664117d8672aA wird mittels XOR-Entschlüsselung aus dem Speicher mit einem 16-Byte-Schlüssel ermittelt. Für jeden Anbieter sendet das Implantat eine HTTPS GET-Anfrage (Port 443, SSL-Zertifikatfehler werden ignoriert), liest das Feld input der letzten Transaktion aus, dekodiert es hexadezimal, entschlüsselt es per XOR mit den Bytes der Wallet-Adresse als Schlüssel und überprüft, ob das Ergebnis mit http beginnt. Im Falle eines Totalausfalls wird auf die fest codierte URL https://panel.fefea22134[.]net zurückgegriffen.
Der Resolver überprüft den Absender der Transaktion nicht. Es wird lediglich geprüft, ob das zuletzt dekodierte input mit http beginnt. Jeder kann eine Transaktion an diese Wallet senden, wobei seine eigene URL unter den Wallet-Bytes XOR-kodiert ist, und jede PHANTOMPULSE-Instanz dieser Kampagne, die anschließend eine Abfrage durchführt, wird auf diese URL aufgelöst. Für Netzwerkverteidiger ist dies ein praktikables Sinkhole, das nur eine Transaktion kostet.
Endpunkte und Herzschlag
Fünf API-Pfade werden zur Laufzeit erstellt und im Speicher mit einem sitzungsspezifischen Schlüssel neu verschlüsselt:
| Weg | Methode | Inhaltstyp | Zweck |
|---|---|---|---|
/v1/telemetry/report | POST | application/json | Herzschlag mit vollständiger Systemtelemetrie |
/v1/telemetry/tasks/<machine_id> | ERHALTEN | Befehl abrufen | |
/v1/telemetry/upload/ | POST | image/bmp | Screenshot / Datei-Upload |
/v1/telemetry/result | POST | application/json | Befehlsergebnisübermittlung |
/v1/telemetry/keylog/ | POST | text/plain | Keylog-Daten hochladen |
Der Heartbeat sendet ein vollständiges Systemprofil als JSON:
{
"machine_id": "<uint32>",
"status": "online",
"cpu": "<model>",
"gpu": "<description>",
"ram_mb": "<uint32>",
"os": "<version>",
"username": "<user>",
"computer_name": "<name>",
"cores": "<uint32>",
"screen_w": "<int>",
"screen_h": "<int>",
"privilege": "<user|admin|admin_nouac|system>",
"build": "payloads",
"public_ip": "<ip>",
"av_list": ["<av1>", "<av2>"],
"apps": ["<app1>", "<app2>"],
"last_cmd": "<cmd>",
"last_cmd_result": "<result>"
}
Es werden zwei Antwortfelder analysiert: "status":"deleted" löst eine vollständige Deinstallation aus; "ip":"<value>" füllt den öffentlichen IP-Cache, jedoch nur, wenn die lokale Erkennung (ipif[.]org) funktioniert. / icanhazip[.]com/ checkip.amazonaws[.]com) hat es noch nicht ausgefüllt.
Schleifenrhythmus und Resilienz
- Schlaf: gleichverteilte Zufallsvariable im Intervall [20, 40] Sekunden
- Selbstheilung: wird in Iteration 2 und danach in jeder 10. Iteration ausgeführt.
- Health-Monitor-Tick: Erster Aufruf nach Inbetriebnahme des Implantats, danach alle 5 Iterationen. Füllt eine lokale Systeminformationsstruktur (CPU%, RAM, Betriebssystemversion, Betriebszeit, Computername).
- Fehlerschwelle: 10 aufeinanderfolgende Heartbeat-Fehler lösen einen automatischen Neustart bei festsitzender SSL/TLS-Wiederherstellung aus
- Neuauflösung: Im Fehlerfall wird eine erneute Auflösung über die Blockchain durchgeführt; ändert sich die aufgelöste URL, wird der Fehlerzähler zurückgesetzt.
- Öffentliche IP:
api4.ipify[.]org→ipv4.icanhazip[.]com→checkip.amazonaws[.]com - Verbindungsprüfung: Sonden
microsoft[.]com,google[.]com,cloudflare[.]com,github[.]com
Befehlsausgabe
Der Befehlsverteiler leitet Befehle anhand des DJB2-Hashs weiter. Insgesamt acht Befehle:
| Hash | Befehl | Verhalten |
|---|---|---|
0x04CF1142 | inject | Shellcode/DLL/EXE einschleusen. Routen nach Typ: Shellcode → PhantomInject; DLL → ManualMap; EXE → DbgNexum. Die AMSI- und WLDP-HWBP-Bypässe werden beim ersten inject -Aufruf installiert (der ETW-HWBP ist bereits ab EvasionInit vorhanden). |
0x7C95D91A | drop | Datei auf die Festplatte kopieren und ausführen. Unterstützt DLL-, EXE-, Shellcode- (APC-Injection) und MSI-Payloads. |
0x9A37F083 | screenshot | GDI-Aufnahme, auf 960px Breite herunterskalieren, als BMP hochladen. |
0x08DEDEF0 | keylog | Starten oder stoppen Sie den Inline-Keylogger. |
0x4EE251FF | uninstall | 6-stufige Bereinigung und Beendigung. |
0x65CCC50B | elevate | UAC-Umgehung über die schuac -Technik (IElevatedFactoryServer::ServerCreateElevatedObject(CLSID_TaskScheduler)); registriert eine vorübergehend erhöhte Aufgabe, die das Implantat neu startet. |
0xB3B5B880 | downgrade | SYSTEM → Übergang zu erhöhten Administratorrechten. |
0x20CE3BC8 | (Selbstneustart) | Kaskadierende Selbstterminierung: Zuerst wird NtTerminateProcess(-1, 0) direkter Systemaufruf ausgeführt; falls dieser nicht aufgelöst werden kann, wird auf ExitProcess(0) zurückgegriffen. Persistenz sorgt dafür, dass das Implantat beim nächsten geplanten Aufgaben-Tick erneut gestartet wird. Betrieblich gleichwertig mit einem sanften Neustart. |
Der achte Handler hat keinen Debug-Logeintrag, der ihn benennt. Es beendet sich selbst; die geplante Aufgabe startet das Implantat beim nächsten Tick neu. Das Fehlen von LLM-typischen Gerüsten (Debug-Strings) macht dies zu einem der wenigen Handler in der Binärdatei, der eher vom menschlichen Autor hinzugefügt als von LLM generiert wurde.
Injektionstechniken
PHANTOMPULSE liefert drei Injektionstechniken, eine pro Nutzlasttyp. Der C2-Befehl inject leitet Shellcode an PhantomInject, DLLs an ManualMap und EXEs an DbgNexum weiter.
Die AMSI/WLDP-Hardware-Breakpoint-Bypässe werden beim ersten inject -Aufruf installiert, bevor irgendein Injector ausgeführt wird.
| Payload-Typ | Einspritzdüse | Strategie |
|---|---|---|
| Shellcode | PhantomInject | Modul-Stamping in dbghelp.dll über SEC_IMAGE |
| EXE | DbgNexum | Debug-API-Zustandsmaschine |
| DLL | ManualMap | Vollständige PE-Handbuch-Kartierung |
PhantomInject: Modul greift in dbghelp.dll ein
Modul-Stomping vermeidet die MEM_PRIVATE -Zuweisung, indem eine legitime Windows-DLL als SEC_IMAGE abgebildet und .text überschrieben wird:
-
Ermittelt
SeDebugPrivilege(überOpenProcessToken/LookupPrivilegeValueW/AdjustTokenPrivileges) und durchläuft dann den Prozess-Snapshot für einen von sieben Host-Prozess-Kandidaten (Groß-/Kleinschreibung wird nicht beachtet). In der Reihenfolge ihrer Priorität versucht:sihost.exe,taskhostw.exe,backgroundTaskHost.exe,RuntimeBroker.exe,dllhost.exe,ctfmon.exe,explorer.exe. -
Öffnet
dbghelp.dllüberNtOpenFile, erstellt den AbschnittSEC_IMAGEund ordnet ihn überNtMapViewOfSectiondem Ziel zu. -
Analysiert die lokale Kopie nach
.textRVA und Größe und gibt sie dann frei. -
Wählt einen Thread aus und hält ihn an, erfasst den Kontext
-
Erstellt ein 82 Byte großes Speicher-Aufruf-Wiederherstellungs-Trampolin
-
Schreibt Shellcode und Trampolin in
.textder zugeordneten DLL -
Klappschutz
PAGE_EXECUTE_READ -
Erneut RIP an das Trampolin, Thread wird fortgesetzt
Für einen Speicherscanner sieht das Ergebnis aus wie ein Thread, der innerhalb eines legitimen dbghelp.dll ausgeführt wird, einer dateibasierten Image-Region mit dem richtigen Dateipfad, Abschnittsnamen und Hash der ersten Seite.
DbgNexum: Debug-API als Ausführungscontroller
DbgNexum verarbeitet EXE-Payloads. Anstatt ausführbaren Code im Zielsystem vorab zu schreiben, verwendet es die Windows-Debug-API, um die Ausführung Ausnahme für Ausnahme zu steuern: eine ROP-Kette, deren Gadgets vollständige Windows-APIs im Zielsystem sind.
Die Technik ist nicht von PHANTOMPULSE erfunden. Es handelt sich um eine wörtliche Übernahme von dis0rder0x00/DbgNexum, einem öffentlichen Machbarkeitsnachweis, der am 04.01.2026 auf GitHub veröffentlicht wurde. Der Betreiber behielt den veröffentlichten Techniknamen ("DbgNexum") in den Debug-Strings des Implantats unverändert bei, und die innere Zustandsmaschine ist eine 1:1-Übereinstimmung: dieselbe Köder-API, derselbe Abschnittsname, dieselbe Gadget-Kette und dieselben Konstanten. PHANTOMPULSE umschließt den angehobenen x64-Kern mit einem betriebsfähigen Gerüst, das der PoC nicht besitzt: Host-Prozess-Auswahl (FindHostProcessEx), ein Fallback, der einen neuen SysWOW64\cmd.exe / rundll32.exe / notepad.exe erzeugt, ein benutzerdefinierter PE-Lade-Bootstrap (damit er vollständige EXEs anstelle von rohem Shellcode transportieren kann) und eine separate WoW64-Cross-Architektur-Variante.
Bei nativen x64-Payloads platziert das Implantat die PE, den Bootstrap-Stub und die Trampolin-Konfiguration in einem benannten Dateizuordnungsabschnitt vor. Der Abschnittsname ist die literale Zwei-Byte-Zeichenkette "MZ", das Implantat verbindet sich mit DebugActiveProcess und erstellt einen Remote-Thread auf FileTimeToSystemTime mit einem Hardware-Haltepunkt auf DR0 .
Wenn der Köder den Haltepunkt erreicht, steuert eine Zustandsmaschine das Ziel durch diese API-Kette:
- Leite
RIPzuDbgBreakPoint+1, wobei das Trap-Flag gesetzt ist; die resultierende Einzelschritt-Ausnahme wird in den Rest der Kette überbrückt. LocalAlloc(LMEM_ZEROINIT, 3), den 3-Byte-Namenspuffer zuweisen.memcpy(buf, kernel32_base, 2), kopiere"MZ"aus dem DOS-Header vonkernel32.dllin den Puffer.memset(stack+40, 0, 8): einen Stack-Argument-Slot auf Null setzen.OpenFileMappingA(0x1F, FALSE, "MZ")Öffnen Sie den vorbereiteten Abschnitt mit vollem Zugriff auf die Abschnittszuordnung.MapViewOfFile(...)Ordnen Sie es dem Ziel zu.- Leite
RIPaufmapped_base + 0x400um, den Bootstrap-Stub. Dies ist die einzige direkt protokollierte Phase:DbgNexumLoop64: stage 6 -> stub at %llx, base=%llx. (Der PoC leitet zumapped_base + 0für rohen Shellcode um; PHANTOMPULSE fügt den Offset+0x400hinzu, um auf seinem benutzerdefinierten PE-Loader zu landen.)
Jeder Übergang fängt das nächste Debug-Ereignis ab, stellt RSP wieder her, löscht das Trap-Flag, modifiziert RIP und die Argumentregister (RCX, RDX, R8, R9) für den nächsten Aufruf und setzt den Debuggee fort. DR0 wird als Execute-Hardware-Breakpoint an jeder gespeicherten Rücksprungadresse wiederverwendet, sodass keine Inline-Patches oder WriteProcessMemory gegen das Zielsystem erforderlich sind. Aus Sicht des Kernels geschah lediglich, dass ein Thread innerhalb von kernel32.dll die LocalAlloc, OpenFileMappingA und MapViewOfFile aufrief.
Der architekturübergreifende Pfad (PE32 von einem 64-Bit-Implantat) ist eine Variante, die nur in PHANTOMPULSE verfügbar ist und nicht im öffentlichen PoC enthalten ist. Es nimmt eine Abkürzung: Das Implantat durchläuft das PEB.Ldr des Ziels über NtReadVirtualMemory (wobei ProcessWow64Information verwendet wird, um das 32-Bit- oder 64-Bit-PEB-Layout auszuwählen), um eine DLL mit einem aufrufbaren Einstiegspunkt zu finden, und ordnet dann einen Abschnitt, der einen 32-Bit-Loader-Stub und ein Trampolin enthält, über NtCreateSection + NtMapViewOfSection beiden Prozessen vorab zu. Die Umleitung besteht aus nur zwei Schritten: Köder bei RtlExitUserThread, dann ein durch DbgBreakPointvermittelter Einzelschritt springt RIP zum Trampolin. Auf diesem Pfad gibt es keine API-Kette, da der Abschnitt bereits auf beiden Seiten zugeordnet ist, daher sind OpenFileMappingA/MapViewOfFile nicht erforderlich.
Die Auswahl des architekturübergreifenden Hosts erfolgt über FindHostProcessEx, wodurch kritische Systemprozesse (csrss.exe, lsass.exe, smss.exe, winlogon.exe, services.exe, wininit.exe, svchost.exe, MsMpEng.exe) ausgeschlossen werden. Falls kein verwendbarer WoW64-Host gefunden wird, wird ein neuer SysWOW64\cmd.exe / rundll32.exe / notepad.exe gestartet.
ManualMap: vollständiger PE-Mapper
ManualMap verarbeitet DLL-Nutzdaten mit einer vollständigen manuellen PE-Mapping-Implementierung:
-
Validiert die MZ/PE-Signatur; lehnt PE32 im x64-Hostpfad ab (Debug-Log:
"PE32 DLL in x64 host is impossible") -
Weist
SizeOfImageim Ziel überNtAllocateVirtualMemoryzu. -
Kopiert Header und Abschnitte in einen lokalen Staging-Puffer
-
Wendet Basis-Relokationen an (
IMAGE_REL_BASED_DIR64,IMAGE_REL_BASED_HIGHLOW) -
Löst Importe über
LoadLibraryA+GetProcAddressauf. -
Löscht PE-Header (löscht
SizeOfHeadersBytes) -
Schreibt das bereitgestellte Image in die Remote-Zuweisung
-
Speicherschutz pro Abschnitt festlegen
-
Erstellt ein 137 Byte großes Trampolin in einem separaten 0x2000 Byte großen Remote-Speicherbereich (auf
PAGE_EXECUTE_READgesetzt):
Der vollständige Trampolin-Shellcode-Gist enthält die kompletten Bytes.
10. Übernimmt die Kontrolle über einen Thread mittels suspend / get-context / set-context
Rechteausweitung
Der Befehl elevate ist ein UAC-Bypass mittels der schuac -Technik (IElevatedFactoryServer::ServerCreateElevatedObject(CLSID_TaskScheduler)), veröffentlicht als UACME-Problem Nr. 129 von zcgonvh, derzeit unter der ID 74.
Mechanismus
MaintenanceUI.dll's CMaintenanceUIVirtualFactory (CLSID {A6BFEA43-501F-456F-A845-983D3AD7B8F0}) ist mit einem Elevation -Registrierungsschlüssel registriert, sodass das Betriebssystem Nicht-Administratoren eine Instanz mit erhöhten Rechten übergibt. Seine IElevatedFactoryServer Schnittstelle stellt ServerCreateElevatedObject(rclsid, riid, ppv) bereit, die der Server mit erhöhten Rechten verwendet, um jede andere CLSID in seinem erhöhten Kontext zu instanziieren. PHANTOMPULSE speist es CLSID_TaskScheduler, erhält eine erhöhte ITaskService zurück und verwendet diesen Dienst, um eine HighestAvailable-RunLevel-Aufgabe zu registrieren, die das Implantat neu startet.
Der elevate C2-Befehl
Innerhalb von ProcessCommands befindet sich der Elevate-Handler:
- Erstellt die Aufgabenaktion. Der Befehl lautet
<system_dir>\rundll32.exemit Argumenten\"<deployed_dll>\",DllRegisterServer. Die Benutzerkennung istCOMPUTERNAME\USERNAMEvonGetEnvironmentVariableW. ![Elevate-Befehlsaufruf][/assets/images/blockchain-c2-phantompulse-rat-sinkhole/image17.png] - Schreibt die
.elevate-Markierung als einzelnes Byte ("1",0x31), nicht als kodierte Parameter. Der Schreibvorgang durchläuftNtCreateFile+NtWriteFile, um die Benutzermodus-Hooks zu umgehen. Der Marker ist lediglich ein Anwesenheitsflag; die Höhenparameter werden innerhalb der Aufgabendefinition übertragen, die das Implantat als Nächstes registrieren wird. - Der COM-Elevation-Moniker wird zur Laufzeit per XOR-Verknüpfung entschlüsselt. Dabei werden 66 Bytes aus
.rdatamit dem Seed0xE95CA237verknüpft, was zuElevation:Administrator!new:{A6BFEA43-501F-456F-A845-983D3AD7B8F0}dekodiert wird. - Ruft
CoGetObject(moniker, &BIND_OPTS3{dwClassContext=CLSCTX_LOCAL_SERVER}, IID_IElevatedFactoryServer, &factory)auf, um ein erhöhtesIElevatedFactoryServer*zu erhalten, und anschließendfactory->ServerCreateElevatedObject(CLSID_TaskScheduler, IID_ITaskService, &elevatedTaskService)um ein erhöhtesITaskService*zu erhalten, das die Erhöhung erbt. - Registriert eine temporäre Aufgabe
DotNetSvcElevateTaskaufHighestAvailableRunLevel mit der oben genannten rundll32-Aktion. - Löscht alle zuvor vorhandenen, nicht erhöhten persistenten Aufgaben, damit die alte, niedrig-IL-Persistenz nicht mit dem erhöhten Neustart konkurrieren kann.
- Ruft
ITaskService::Runfür die temporäre Aufgabe auf und löscht sie anschließend sofort. Gibt den Einzelinstanz-Mutex frei und verlässt das Medium-IL-Implantat.
Fallback-Wiederholung über Proxy rundll32
Falls die CoGetObject / RegisterTask -Kette fehlschlägt, greift ein Ausweichpfad. Ein separater Startpfad erzeugt direkt über CreateProcessW ein neues rundll32.exe "<deployed_dll>",DllRegisterServer mit Wiederholungsversuchen (">>> .elevate redirect attempt %d"). Innerhalb dieses rundll32 erkennt das Implantat isProxy=1, elevated=0 und wiederholt die Schuac-Sequenz mit drei Registrierungsvarianten (ELEVATED+INTERACTIVE+user, ELEVATED+INTERACTIVE, INTERACTIVE). Bei Erfolg wird die erhöhte Aufgabe ausgelöst und der erhöhte Neustart übernimmt. Bei Erschöpfung protokolliert der Proxy ">>> Phase 1: all registration methods failed, cleaning marker" und beendet sich.
Neuer Start von Elevated rundll32
Wenn die temporäre Aufgabe ausgelöst wird, startet svchost.exe (Schedule) rundll32.exe "<deployed_dll>",DllRegisterServer unter einem neuen High-IL-Token. Der DllRegisterServer -Export des Implantats dient als Einstiegspunkt; beim Start erkennt er die Markierung .elevate und ein Token mit hohem IL-Wert und leitet die Daten auf den erhöhten Pfad um:
- Liest und löscht die Markierung
.elevate. - Installiert die Persistenz unter erhöhten Rechten neu, einschließlich der Boot-Aufgabe
DotNetSvcCoreTaskunter\Microsoft\Windows\NetFramework\, die mitINTERACTIVE_TOKEN+BootTriggerregistriert ist, wofür ein Administrator zur Registrierung erforderlich ist. - Der normale Implantatbetrieb wird als High-IL-Service fortgesetzt.
Marker-State-Routing
Bei jedem Startvorgang ruft MainEntryLogic GetFileAttributesW auf dem Pfad .elevate auf. Wenn die Funktion INVALID_FILE_ATTRIBUTES zurückgibt, überspringt das Implantat die gesamte Elevationslogik und startet normal. Existiert der Marker, erfasst das Implantat zwei weitere Informationen: ob der aktuelle Prozess ein rundll32.exe/regsvr32.exe Proxy ist und ob das Token erhöht ist. Anschließend leitet es die Daten anhand der Kombination weiter:
| Marker | Proxy | Erhöht | Was passiert |
|---|---|---|---|
| abwesend | – | – | Normaler Startvorgang, keine spezielle Routenführung |
| Präsentieren | Nein | Nein | spawn proxy rundll32 to retry the schuac chain, then exit |
| Präsentieren | Ja | Nein | Wiederhole den Schuac-Befehl innerhalb von rundll32; bei Erschöpfung lösche die Markierung und beende das Programm. |
| Präsentieren | * | Ja | Markierung löschen, Persistenz mit dem Boot-Task neu installieren, als High-IL fortfahren |
Der Inhalt der Markerdatei wird nie gelesen; allein ihre Existenz steuert das Routing.
Elastic Security Labs' Exploring Windows UAC Bypasses behandelt Erkennungsmuster für die IElevatedFactoryServer Klasse von Umgehungen direkt.
Persistenz
Drei geplante Aufgaben
PHANTOMPULSE installiert drei geplante Aufgaben über die COM ITaskService -Schnittstelle, die jeweils rundll32.exe "<stub_dll>",DllRegisterServer ausführen:
| Aufgabe | Auslösen | Intervall | RunLevel |
|---|---|---|---|
DotNetSvcUpdateTask | Benutzeranmeldung + Zeit | 3 Minuten | Standard |
DotNetSvcCoreTask | Booten + Zeit | 15 Minuten | Höchstverfügbar + Versteckt |
DotNetSvcUserTask | Benutzeranmeldung | Beim Anmelden | Standard |
Der Bootvorgang läuft unter \Microsoft\Windows\NetFramework\ , um sich mit legitimen .NET-Wartungsaufgaben zu vermischen. Der vollständige XML-Body ist in .rdata eingebettet und wird nicht zur Laufzeit erstellt. Signaturen auf diesem buchstäblichen Klecks bleiben über verschiedene Builds hinweg erhalten.
Die Installation versucht pro Aufgabe mehrere RegisterTask Fallback-Varianten, indem sie die Anmeldetypen INTERACTIVE_TOKEN und S4U mit verschiedenen Benutzeridentifikatorformaten (COMPUTER\User, SID, Kurzname) kombiniert. Die genaue Reihenfolge der Versuche hängt vom Berechtigungskontext des Implantats ab (SYSTEM, Administrator oder Standardbenutzer); Fehlschläge werden zur nächsten Variante weitergeleitet, bis eine erfolgreich ist.
Stub DLL drop
Der bereitgestellte Agent befindet sich verschlüsselt und komprimiert innerhalb der eigenen .rdata-Datei der EXE-Datei. FilelessPersist entschlüsselt es bei Bedarf und schreibt das Ergebnis über (NtCreateFile + NtWriteFile) auf die Festplatte.
Die Entschlüsselung erfolgt in zwei Schritten:
- XOR-Dekodierung eines Blobs gegen einen rotierenden 16-Byte-Schlüssel bei (
decoded[i] = blob[i] ^ key[i & 0xF], wobeidecoded[0] = 0x1Eein fest codiertes erstes Byte ist, das den LZNT1-Chunk-Header initialisiert. RtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1, ...)im dekodierten Puffer, der eine DLL (svcagent.dll) ist.
Pfade in Prioritätsreihenfolge verwerfen, bei Zugriffsfehlern abbrechen:
%ProgramData%\AssetMon\svcagent.dll(primär)%APPDATA%\AssetMon\svcagent.dll%TEMP%\svcagent.dll- Eine redundante
%ProgramData%"Sleeper"-Kopie an einem separaten Pfad
Analysten können die bereitgestellte DLL offline reproduzieren, indem sie die beiden oben genannten Bereiche aus der EXE auslesen, die XOR-Schleife anwenden und das Ergebnis an RtlDecompressBuffer (oder eine beliebige LZNT1-Implementierung) übergeben, wie im folgenden CyberChef-Screenshot zu sehen ist.
DLL-Sideload-Migration
Ein Block innerhalb von SetupRegistryPE (protokolliert mit den Debug-String-Präfixen MigrateSideload / MigrateLegacySideloads ) listet laufende Prozesse und deren ausführbare Verzeichnisse auf und sucht nach diagcore.dll. Wenn ein solcher Stub gefunden wird, wird die Datei mit dem aktuellen Stub überschrieben (siehe CopyFileW.
Selbstheilung
Die Selbstheilung wird in Iteration 2 der C2-Schleife und danach in jeder 10. Iteration ausgeführt, abhängig davon, ob ein Deferred-Persist-Flag gesetzt ist. Die Reihenfolge der Überprüfung:
- Zuerst die Persistenz in der Registry prüfen.
CheckRegistryPersistenceLäuft oben im Block. Wenn es einen Fehler meldet, führt das Implantat sofortFilelessPersist(erneute Entschlüsselung und erneutes Ablegen der Stub-DLL) undInstallPersistence(erneute Registrierung der Task-Trigger) erneut aus. - Aufgabenverifizierung.
SelfHealCheckTasksAnschließend werden die drei Persistenzaufgaben (DotNetSvcUpdateTask,DotNetSvcCoreTask,DotNetSvcUserTask) überprüft und alle fehlenden neu installiert. Die Überprüfung des Bootvorgangs ist an den SYSTEM- oder Administratorkontext gebunden; Aufrufer ohne entsprechende Berechtigungen überspringen sie. - Aktualisierung des AV-Inventars.
DetectInstalledAVwird am Ende ausgeführt, um die für den Bediener sichtbare AV-Produktliste zu aktualisieren.
Die Frage der Privilegienbeschränkung ist bei einer Zwangsräumung relevant. In einem Kontext ohne erhöhte Rechte wird die Überprüfung des Boot-Tasks übersprungen, sodass der Boot-Task während der Bereinigung nicht untersucht wird. Für eine vollständige Entfernung müssen alle drei Aufgaben sowie das Registry-Artefakt in einem Fenster mit erhöhten Rechten entfernt werden.
Neben der iterationsbasierten Selbstheilung verfügt das Implantat über einen verzögerten Persistenzmechanismus, der durch ein einzelnes Flag ausgelöst wird. Bei erfolgreichen Herzschlägen in C2Loop_Main wird, sobald der Zähler für erfolgreiche Herzschläge bei gesetztem Flag eins überschreitet, der Vorgang FilelessPersist + InstallPersistence erneut ausgeführt und das Flag gelöscht. Dies gibt PHANTOMPULSE einen zweiten Persistenzreparaturpfad, der bei einem anderen Auslöser als der iterationsbasierte Selbstheilungsmechanismus aktiviert wird.
Erfassung
Inline-Keylogger mit Zwischenablageüberwachung
Der Keylogger läuft direkt in der C2-Schleife ohne eigenen Thread. Es löst APIs von user32.dll zur Laufzeit auf:
| API | Zweck |
|---|---|
GetAsyncKeyState | Umfragen sind ein wichtiger Staat |
GetForegroundWindow | Aktive Fenstererkennung |
GetWindowTextA | Fenstertitel erfassen |
MapVirtualKeyA / ToUnicode | Schlüsselübersetzung |
GetClipboardSequenceNumber | Erkennung von Zwischenablageänderungen |
OpenClipboard / GetClipboardData | Zwischenablage lesen (CF_UNICODETEXT) |
Die Logdatei ist mit dem Seed 0xE95CA237 XOR-verschlüsselt. Beim Upload wird nur die Differenz gesendet, um eine erneute Übertragung zu vermeiden.
Screenshot
Screenshots verwenden GDI-APIs, die über Hashwerte aufgelöst werden. Wenn die Desktopbreite 960 Pixel überschreitet, wird das Bild vor dem Hochladen verkleinert. Das Roh-BMP wird im Speicher erstellt und mit Content-Type: image/bmp hochgeladen. Ausgelöst auf Anforderung durch den C2-Befehl screenshot (Hash 0x9A37F083).
Systemaufklärung
Aufklärungsdaten, die das Implantat sammelt:
| Daten | Quelle |
|---|---|
| CPU | Registrierung: ProcessorNameString |
| GPU | Registrierungsanzeigeadapter DriverDesc (Filter "Microsoft Basic") |
| RAM | GlobalMemoryStatusEx |
| OS | RtlGetVersion mit Build-zu-Versions-Zuordnung (Win7 bis Win11, Server 2008 bis Server 2025) |
| Nutzername | GetUserNameW mit Fallback auf LookupAccountSidW vom explorer.exe Token |
| Privileg | Token-Erhöhungstyp: user, admin, admin_nouac, system |
| AV | DetectInstalledAV Vergleicht laufende Prozesse mit einer fest codierten Liste von ca. 25–30 Prozessnamen von Antivirenherstellern. |
| Apps | DetectInstalledApps prüft eine kuratierte Liste mit 19 zielgerichteten Apps |
| Firewall-Status | Liest SYSTEM\CurrentControlSet\Services\SharedAccess\Parameters\FirewallPolicy\{Domain,Standard,Public}Profile um den pro Profil aktivierten Status aufzuzeichnen. |
| Dienste | Zählung laufender Dienste über Dienstaufzählung |
| Maschinen-ID | DJB2 (Modulname) ^ Lautstärke-Seriennummer |
| Öffentliche IP-Adresse | Multi-API-HTTPS-Kette |
Die Liste der AV-Erkennung ist ungewöhnlich breit gefächert und umfasst gängige westliche AV-Produkte für Endverbraucher wie Defender, Norton, McAfee, Avast, AVG, Avira, Bitdefender, ESET, F-Secure, G Data, Kaspersky, Panda, Sophos, Trend Micro, VIPRE, Webroot, ZoneAlarm, Comodo sowie EDR-Anbieter (CrowdStrike, SentinelOne, Cylance, Malwarebytes, HitmanPro). Das Implantat sucht außerdem nach AhnLab V3 (Südkorea), Qihoo 360 / 360 Total Security und Tencent QQPC (China) sowie K7 Computing (Indien). Die Einbeziehung asiatischer AV ist ungewöhnlich für auf westliche Märkte ausgerichtete Warendiebe und steht im Einklang mit einem Implantat, das für Opfer in mehreren regionalen Märkten konzipiert wurde.
Das Implantat prüft außerdem anhand des Namens eine kuratierte Liste von 19 hochwertigen Anwendungen und kennzeichnet Übereinstimmungen im Heartbeat (App detection: found %d apps):
| Kategorie | Ziele |
|---|---|
| Kryptowährungs-Wallets | ledger, trezor, bitcoin-core, electrum, exodus, atomic, guarda |
| Boten | telegram, discord, signal, viber, slack, whatsapp |
| E-Mail-Kunden | thunderbird, outlook |
| 2FA-App | authy |
| Dateiübertragung / SSH | filezilla, winscp |
| Gaming | steam |
Die Erkennungsfunktion (DetectInstalledApps) durchsucht weder die Registry noch listet sie Prozesse auf. Es erweitert drei Umgebungsvariablenwurzeln (%LOCALAPPDATA%, %APPDATA%, %ProgramFiles(x86)%), verkettet einen fest codierten UTF-16-Relativpfadsuffix pro Anwendung (z. B. \Telegram Desktop\, \Authy Desktop\, \Ledger Live\, \@trezor\trezor-suite\, \Steam\steam.exe), und ruft GetFileAttributesW auf jedem Pfad auf. Eine Rückgabe ohne Fehler bedeutet, dass die App installiert ist und der Name im Heartbeat-Ergebnispuffer gespeichert wird.
PHANTOMPULSE selbst extrahiert keine Daten aus diesen Quellen. Die Liste dient der Zielaufklärung für Folgeaufträge. Der Operator erkennt im Heartbeat, welche wertvollen Anwendungen ein bestimmtes Opfer besitzt, und entscheidet, welche spezielle Nutzlast als nächstes über inject oder drop gesendet werden soll.
In der analysierten Stichprobe wurden keine Funktionen zum Diebstahl von Wallets, Browsern, Messengern oder Anmeldeinformationen identifiziert; die Zielliste ist lediglich eine Anwesenheitsprüfung, die den Entscheidungsbaum des Betreibers speist.
Deinstallieren
Eine sechsstufige Bereinigung, ausgelöst durch den Befehl uninstall , durch "status":"deleted" in einer Heartbeat-Antwort oder durch ein Kill-Flag in der Registry:
| Schritt | Aktion |
|---|---|
| 1/6 | Schreibe das Kill-Flag in HKCU und HKLM, um den Host-Prozess zu beenden. |
| 2/6 | Entfernen Sie alle 3 geplanten Aufgaben über COM + CreateProcessW Fallback |
| 3/6 | Entfernen der alten Registrierungseinstellungen: NTLoad-Wert, COM-Hijacking-Schlüssel, Druckmonitorschlüssel |
| 4/6 | Löschen Sie Stub-DLLs, Sleeper-Logs, Registry-PE-Blobs und ProgramData-Verzeichnisse. |
| 5/6 | Installationspfad und Selbstpfad von der Festplatte löschen |
| 6/6 | Beende die verbleibenden healthmon.exe und alle rundll32.exe -Instanzen, die svcagent.dllhosten. |
Schritt 3 enthüllt die Legacy-Persistenztechniken: Bereinigungslogik für COM-Hijacking und Druckmonitor-Schlüssel, die in diesem Build nie installiert werden.
Quellenangabe
Die Vorgehensweise, die Zielauswahl und die Infrastrukturwahl von PHANTOMPULSE stimmen mit den mit Nordkorea verbundenen Krypto-Targeting-Intrusion-Clustern überein, zu denen Lazarus, BlueNoroff, UNC5342 (Contagious Interview) und APT38 gehören. Mehrere unabhängige Dimensionen stimmen mit den jüngsten öffentlichen Berichten über diese Cluster überein.
Signale, die mit den Berichten der DVRK übereinstimmen:
- Blockchain-aufgelöstes C2 über Transaktion
inputFelder entspricht dem Dead-Drop-Resolver-Muster Mandiant Attributes to UNC5342 (Contagious Interview) in DPRK Adopts EtherHiding. Die spezifischen Merkmale von PHANTOMPULSE (Wallet-Byte-XOR, Multi-Chain-Blockscout) sind kein 1:1-Fingerabdruck, aber die Technikklasse ist jetzt mit dem DPRK-Tag versehen. - Die Enumerationsmenge der Desktop-Krypto-Wallets (
ledger,trezor,bitcoin-core,electrum,exodus,atomic,guarda) entspricht weitgehend der RustDoor / Koi Stealer-Zielliste für macOS von Unit 42, die der DVRK zugeschrieben wird. - Bei plattformübergreifenden Windows- und macOS-Implantaten für dasselbe Opferprofil (der vorherige Beitrag REF6598 dokumentierte ein macOS-Pendant mit C2 bei
0x666[.]infound einem Telegram-Fallback beit[.]me/ax03bot) handelt es sich um eine BlueNoroff-Signatur. - Telegram- und Messenger-Targeting ist eine Spezialität von BlueNoroff, wie aus der Berichterstattung von Arctic Wolf BlueNoroff hervorgeht.
Suche nach neuen C2-Domains über die bekannte Klartextsignatur der Resolver-Wallet.
Das vom Blockchain-Resolver verwendete XOR-Schema birgt das Risiko, dass eine stabile 2-Byte-Signatur entsteht. Verteidiger können daher die gesamte Blockchain durchsuchen und nicht nur eine einzelne Wallet.
Zwei Tatsachen kommen zusammen: Jede C2-URL beginnt mit ht (von http:// oder https://), und der XOR-Schlüssel ist die ASCII-Adresse der Wallet wortwörtlich, sodass die ersten beiden Schlüsselbytes immer die Literalzeichen 0 und x sind. Die XOR-Verknüpfung von ht mit 0x ergibt \x58 \x0c. Jedes verschlüsselte input -Feld, das von einem PHANTOMPULSE-artigen Resolver auf einer beliebigen Kette erzeugt und von einer beliebigen zugehörigen Wallet signiert wird, beginnt mit den vier Hexadezimalzeichen 580c.
Dadurch wird die Suche von der Überwachung einer einzelnen Wallet auf das Durchsuchen der gesamten Blockchain nach der Signatur umgestellt. Öffentliche Transaktionsdaten von Ethereum, Base und Optimism können über BigQuery, Dune oder vollständige Archivknoten abgefragt werden. Eine Abfrage des öffentlichen Ethereum-Transaktionsdatensatzes nach input -Werten, die mit 0x580c beginnen, beschränkt auf ein aktuelles Block-Zeitstempel-Fenster, zeigt bisher unbekannte Resolver-Wallets an, die von derselben Codebasis verwendet werden. Jede Übereinstimmung wird validiert, indem mit der ASCII-Adresse der Absender-Wallet als Schlüssel dekodiert wird: Eine echte C2-URL beginnt nach der Dekodierung mit http . Das folgende CyberChef-Rezept kann verwendet werden, um die C2-URL zu entschlüsseln.
SELECT
block_timestamp AS block_time,
from_address AS `from`,
to_address AS `to`,
input AS data
FROM `bigquery-public-data.crypto_ethereum.transactions`
WHERE block_timestamp >= '2026-04-01 00:00:00'
AND input LIKE '0x580c%'
ORDER BY block_timestamp DESC
LIMIT 10000;
CyberChef kann die Eingabedaten entschlüsseln, um die Domain aufzudecken, wie im folgenden Screenshot dargestellt.
Fazit
PHANTOMPULSE wurde aus veröffentlichten Komponenten entwickelt: Modul-Stomping, Debug-API-Zustandsautomaten, manuelle Zuordnung, Hardware-Breakpoint-AMSI/WLDP/ETW-Bypass, Persistenz geplanter Aufgaben und Blockchain-C2. Die Kombination und die damit einhergehende Absicherung deuten auf eine ausgereifte Codebasis hin, die sich in aktiver Weiterentwicklung befindet. Die dauerhaften Signale sind verhaltensbezogen und werden durch die Verhaltensschutzmechanismen von Elastic für REF6598 abgedeckt.
PHANTOMPULSE und MITRE ATT&CK
Elastic verwendet das MITRE ATT&CK-Framework, um gängige Taktiken, Techniken und Verfahren zu dokumentieren, die von Advanced Persistent Threats gegen Unternehmensnetzwerke eingesetzt werden.
Taktiken
Taktiken stellen das Warum einer Technik oder Teiltechnik dar. Es ist das taktische Ziel des Gegners: der Grund für die Ausführung einer Handlung.
- Erstzugriff
- Ausführung
- Persistenz
- Rechteausweitung
- Tarnung
- Zugriff mit Anmeldeinformationen
- Discovery
- Erfassung
- Command and Control
- Exfiltration
Techniken
Techniken stellen dar, wie ein Angreifer ein taktisches Ziel erreicht, indem er eine Aktion ausführt.
- Phishing: Spearphishing per Dienst
- Befehls- und Skriptinterpreter: PowerShell
- Prozessinjektion
- Prozessinjektion: DLL-Injektion
- System Binary Proxy Execution: Msiexec
- System Binary Proxy Execution: Rundll32
- Geplanter Task/Job: Geplanter Task
- Autostart-Ausführung bei Systemstart oder Anmeldung
- Registrierung ändern
- Beeinträchtigung der Abwehr: Deaktivieren oder Ändern von Tools
- Indikatorentfernung: Dateilöschung
- Erkennung von Systeminformationen
- Systembesitzer-/Benutzererkennung
- Prozess-Erkennung
- Softwareerkennung: Sicherheitssoftwareerkennung
- Eingabeerfassung: Keylogging
- Daten aus der Zwischenablage
- Bildschirmaufnahme
- Exfiltration über C2-Kanal
- Anwendungsschichtprotokoll: Webprotokolle
- Webdienst
- Verschlüsselter Kanal
- Verschleierte Dateien oder Informationen
- Dateien oder Informationen dekodieren/entschlüsseln
- Manipulation von Zugriffstoken
- Mechanismus zur Kontrolle der Rechteerweiterungen bei Missbrauch: Umgehen der Benutzerkontensteuerung
- Native API
- Virtualisierung/Sandbox-Umgehung: Zeitbasierte Umgehung
- Hijack-Ausführungsablauf: DLL-Querladen
- Reflektierendes Laden von Codes
Sanierung
YARA
Elastic Security hat YARA-Regeln erstellt, um diese Aktivität zu identifizieren.
Beobachtungen
| Überwachbar | Typ | Name | Referenz |
|---|---|---|---|
33dacf9f854f636216e5062ca252df8e5bed652efd78b86512f5b868b11ee70f | SHA-256 | PHANTOMPULSRATTE | Final payload |
70bbb38b70fd836d66e8166ec27be9aa8535b3876596fc80c45e3de4ce327980 | SHA-256 | syncobs.exe | PHANTOMPULL Lader |
def66275fa3baffb16e6e4ae0297861d9790ae7161fbc271a2ba05d121f13c70 | SHA-256 | Go Beacon | GTESTIC_WIN-Check-in |
panel.fefea22134[.]net | Domain | C2-Panel | PHANTOMPULSE fest codierter Fallback |
fea22134[.]net | Domain | C2 domain | In Binärform verschlüsselt |
195.3.222[.]251 | IPv4-ADDR | Staging-Server | PowerShell/Loader-Auslieferung |
0xc117688c530b660e15085bF3A2B664117d8672aA | Krypto-Wallet | Blockchain C2 Wallet | ETH/Basis/Optimismus |
0x38796B8479fDAE0A72e5E7e326c87a637D0Cbc0E | Krypto-Wallet | Finanzierungskonto | C2-Resolutionsfinanzierung |
eth.blockscout[.]com | Domain | Blockchain-Anbieter | C2-URL-Auflösung |
base.blockscout[.]com | Domain | Blockchain-Anbieter | C2-URL-Auflösung |
optimism.blockscout[.]com | Domain | Blockchain-Anbieter | C2-URL-Auflösung |
hVNBUORXNiFLhYYh | mutex | Einzelinstanz | XOR-entschlüsselt |
svcagent.dll | Dateiname | Stub-DLL | Persistenznutzlast |
AssetMon | Verzeichnis | Stub-DLL-Verzeichnis | %ProgramData% oder %APPDATA% |
healthmon.exe | Dateiname | Tropfer | Ursprünglicher ausführbarer Name |
diagcore.dll | Dateiname | Legacy Sideload DLL | Migriert mit MigrateSideload |
.elevate | Dateiname | Höhenmarkierung | Routen für den erhöhten Neustart |
DotNetSvcUpdateTask | geplante Aufgabe | Primäre Persistenz | 3-Minuten-Intervall |
DotNetSvcCoreTask | geplante Aufgabe | SYSTEMpersistenz | 15 Minuten, versteckt |
DotNetSvcUserTask | geplante Aufgabe | Benutzerpersistenz | Anmeldeauslöser |
EdgeWebViewUpdateTask | geplante Aufgabe | Legacy-Aufgabe | Wurde während der Deinstallation bereinigt. |
\Microsoft\Windows\NetFramework\DotNetSvcCoreTask | task-uri | Boot-Taskpfad | Versteckte geplante Aufgabe |
Elevation:Administrator!new:{A6BFEA43-501F-456F-A845-983D3AD7B8F0} | Gemeinschaftsname | UAC-Umgehung | Erweiterter IT-Frageservice |
0x666[.]info | Domain | macOS C2 | macOS-Dropper |
t[.]me/ax03bot | URL | Telegram-Fallback | macOS C2 Dead-Drop |
thoroughly-publisher-troy-clara[.]trycloudflare[.]com | Domain | Vorheriges C2 | Cloudflare Tunnel |
Referenzen
Frühere Berichte und in dieser Analyse erwähnte Tools:
- Phantom im Tresor: Obsidian missbraucht, um PhantomPulse RAT zu liefern
- Blockscout Ethereum Explorer
- Nordkorea führt EtherHiding ein
- Ansteckendes Vorstellungsgespräch / Gefälschte Personalvermittler zielen auf Entwickler im Kryptosektor ab
- RustDoor und Koi Stealer für macOS
- BeaverTail und OtterCookie Evolution
- DbgNexum-Machbarkeitsnachweis
- UACME-Problem Nr. 129: Schuac-UAC-Umgehung
- Erkundung von Windows-UAC-Umgehungen
- Speicherpatching AMSI-Bypass