Salim Bitam

PHANTOMPULSE: Anatomie eines kaperbaren Blockchain-C2-RAT

Elastic Security Labs präsentiert eine detaillierte Reverse-Engineering-Analyse von PHANTOMPULSE, dem langlebigen RAT, der über das REF6598-Intrusion-Set an Opfer im Kryptosektor ausgeliefert wurde.

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_Wrap
  • NtWriteFile_Wrap
  • NtClose_Wrap
  • NtCreateSection_Wrap
  • NtMapViewOfSection_Wrap
  • NtProtectVirtualMemory_Wrap
  • NtWriteVirtualMemory_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:

WasSchlüsselWo der Schlüssel wohnt
C2-Fallback-URL, Mutex, Drop-Pfad-Dateinamen16 Byte: F7 7C 8E 40 DF C1 7B E5 E7 4D 86 79 D5 B3 53 41Eingebettet in .rdata
Hostnamen von Blockchain-Anbietern (UTF-16 LE)8-Byte: 5A 3C 7E 1D 9F 2B 4E 8AEingebettet in .rdata
COM-Höhenmoniker, Nutzdaten der Keylog-Datei0xE95CA237, wird zur Laufzeit berechnet, um die Konstante aus dem Kontext herauszuhalten .rdataBerechnet, nicht gespeichert
C2-URL aus Blockchain-Transaktion extrahiert inputDie Resolver-Wallet-Adresse selbstWiederverwendet 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.

SlotZiel-APIGefälschte Rückgabe (RAX)
DR0WldpQueryDynamicCodeTrust0 (S_OK)
DR1AmsiScanBuffer0x80070057 (E_INVALIDARG)
DR2EtwEventWrite0 (STATUS_SUCCESS)

Der Mechanismus, Schritt für Schritt:

  1. 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.
  2. 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.
  3. Ein Hilfsthread unterbricht den Zielthread, ruft NtGetContextThread / NtSetContextThread auf, 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-Ausnahme STATUS_BREAKPOINT ausgelöst, sodass der VEH die Steckplatztabelle lesen und die DRs ohne Hilfsthread programmieren kann.)
  4. Wenn die geschützte API aufgerufen wird, löst die CPU bei der ersten Anweisung der Funktion Debug Exception -Ausnahme aus.
  5. Der Vektor-Ausnahmebehandler des Implantats fängt die Debug Exception ab, durchläuft seine 4-Slot-Tabelle, um die Auslöseadresse zu finden, und ändert den Thread-Kontext: CONTEXT.Rax wird auf den pro Slot gefälschten Rückgabewert gesetzt, CONTEXT.Rip wird zu einem vorab gespeicherten "skip"-Thunk umgeleitet, der zum Aufrufer zurückkehrt.
  6. Der Handler gibt EXCEPTION_CONTINUE_EXECUTION zurü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.

FeatureNutzlasten erstellenBeweis
Direkte Systemaufrufe (SSN-Extraktion)AktivSSN-Extraktion + Stub-Generierung bestätigt
AMSI / WLDP / ETW HWBP-UmgehungAktivDR0/DR1/DR2 über gemeinsam genutzten Hilfsthread-Primitiv
Drei-Wege-ProzesseinspritzungAktivPhantomInjectDbgNexum und ManualMap sind alle funktional.
Blockchain C2-AuflösungAktivDrei Blockscout-Anbieter wurden befragt
NTDLL-AbkopplungToter CodeZeichenketten vorhanden, keine Code-Referenzen
HEIS-VerschlüsselungDeaktiviertCode-Stub für Verschlüsselung/Entschlüsselung
Registry-resident PE Blob LoaderLegacy-onlyWird nur während der Deinstallation bereinigt.
COM-Hijacking-PersistenzLegacy-onlyWurde während der Deinstallation bereinigt, nie installiert
DruckmonitorpersistenzLegacy-onlyWurde während der Deinstallation bereinigt, nie installiert
KöderschnüreAktiv4 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:

WegMethodeInhaltstypZweck
/v1/telemetry/reportPOSTapplication/jsonHerzschlag mit vollständiger Systemtelemetrie
/v1/telemetry/tasks/<machine_id>ERHALTENBefehl abrufen
/v1/telemetry/upload/POSTimage/bmpScreenshot / Datei-Upload
/v1/telemetry/resultPOSTapplication/jsonBefehlsergebnisübermittlung
/v1/telemetry/keylog/POSTtext/plainKeylog-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[.]orgipv4.icanhazip[.]comcheckip.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:

HashBefehlVerhalten
0x04CF1142injectShellcode/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).
0x7C95D91AdropDatei auf die Festplatte kopieren und ausführen. Unterstützt DLL-, EXE-, Shellcode- (APC-Injection) und MSI-Payloads.
0x9A37F083screenshotGDI-Aufnahme, auf 960px Breite herunterskalieren, als BMP hochladen.
0x08DEDEF0keylogStarten oder stoppen Sie den Inline-Keylogger.
0x4EE251FFuninstall6-stufige Bereinigung und Beendigung.
0x65CCC50BelevateUAC-Umgehung über die schuac -Technik (IElevatedFactoryServer::ServerCreateElevatedObject(CLSID_TaskScheduler)); registriert eine vorübergehend erhöhte Aufgabe, die das Implantat neu startet.
0xB3B5B880downgradeSYSTEM → Ü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-TypEinspritzdüseStrategie
ShellcodePhantomInjectModul-Stamping in dbghelp.dll über SEC_IMAGE
EXEDbgNexumDebug-API-Zustandsmaschine
DLLManualMapVollstä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:

  1. Ermittelt SeDebugPrivilege (über OpenProcessToken / 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.

  2. Öffnet dbghelp.dll über NtOpenFile, erstellt den Abschnitt SEC_IMAGE und ordnet ihn über NtMapViewOfSectiondem Ziel zu.

  3. Analysiert die lokale Kopie nach .text RVA und Größe und gibt sie dann frei.

  4. Wählt einen Thread aus und hält ihn an, erfasst den Kontext

  5. Erstellt ein 82 Byte großes Speicher-Aufruf-Wiederherstellungs-Trampolin

  6. Schreibt Shellcode und Trampolin in .text der zugeordneten DLL

  7. Klappschutz PAGE_EXECUTE_READ

  8. 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:

  1. Leite RIP zu DbgBreakPoint+1 , wobei das Trap-Flag gesetzt ist; die resultierende Einzelschritt-Ausnahme wird in den Rest der Kette überbrückt.
  2. LocalAlloc(LMEM_ZEROINIT, 3), den 3-Byte-Namenspuffer zuweisen.
  3. memcpy(buf, kernel32_base, 2), kopiere "MZ" aus dem DOS-Header von kernel32.dll in den Puffer.
  4. memset(stack+40, 0, 8): einen Stack-Argument-Slot auf Null setzen.
  5. OpenFileMappingA(0x1F, FALSE, "MZ")Öffnen Sie den vorbereiteten Abschnitt mit vollem Zugriff auf die Abschnittszuordnung.
  6. MapViewOfFile(...)Ordnen Sie es dem Ziel zu.
  7. Leite RIP auf mapped_base + 0x400 um, den Bootstrap-Stub. Dies ist die einzige direkt protokollierte Phase: DbgNexumLoop64: stage 6 -> stub at %llx, base=%llx. (Der PoC leitet zu mapped_base + 0 für rohen Shellcode um; PHANTOMPULSE fügt den Offset +0x400 hinzu, 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:

  1. Validiert die MZ/PE-Signatur; lehnt PE32 im x64-Hostpfad ab (Debug-Log: "PE32 DLL in x64 host is impossible")

  2. Weist SizeOfImage im Ziel über NtAllocateVirtualMemoryzu.

  3. Kopiert Header und Abschnitte in einen lokalen Staging-Puffer

  4. Wendet Basis-Relokationen an (IMAGE_REL_BASED_DIR64, IMAGE_REL_BASED_HIGHLOW)

  5. Löst Importe über LoadLibraryA + GetProcAddressauf.

  6. Löscht PE-Header (löscht SizeOfHeaders Bytes)

  7. Schreibt das bereitgestellte Image in die Remote-Zuweisung

  8. Speicherschutz pro Abschnitt festlegen

  9. Erstellt ein 137 Byte großes Trampolin in einem separaten 0x2000 Byte großen Remote-Speicherbereich (auf PAGE_EXECUTE_READ gesetzt):

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:

  1. Erstellt die Aufgabenaktion. Der Befehl lautet <system_dir>\rundll32.exe mit Argumenten \"<deployed_dll>\",DllRegisterServer. Die Benutzerkennung ist COMPUTERNAME\USERNAME von GetEnvironmentVariableW. ![Elevate-Befehlsaufruf][/assets/images/blockchain-c2-phantompulse-rat-sinkhole/image17.png]
  2. Schreibt die .elevate -Markierung als einzelnes Byte ("1", 0x31), nicht als kodierte Parameter. Der Schreibvorgang durchläuft NtCreateFile + 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.
  3. Der COM-Elevation-Moniker wird zur Laufzeit per XOR-Verknüpfung entschlüsselt. Dabei werden 66 Bytes aus .rdata mit dem Seed 0xE95CA237 verknüpft, was zu Elevation:Administrator!new:{A6BFEA43-501F-456F-A845-983D3AD7B8F0} dekodiert wird.
  4. Ruft CoGetObject(moniker, &BIND_OPTS3{dwClassContext=CLSCTX_LOCAL_SERVER}, IID_IElevatedFactoryServer, &factory) auf, um ein erhöhtes IElevatedFactoryServer* zu erhalten, und anschließend factory->ServerCreateElevatedObject(CLSID_TaskScheduler, IID_ITaskService, &elevatedTaskService) um ein erhöhtes ITaskService* zu erhalten, das die Erhöhung erbt.
  5. Registriert eine temporäre Aufgabe DotNetSvcElevateTask auf HighestAvailable RunLevel mit der oben genannten rundll32-Aktion.
  6. Löscht alle zuvor vorhandenen, nicht erhöhten persistenten Aufgaben, damit die alte, niedrig-IL-Persistenz nicht mit dem erhöhten Neustart konkurrieren kann.
  7. Ruft ITaskService::Run fü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 DotNetSvcCoreTask unter \Microsoft\Windows\NetFramework\, die mit INTERACTIVE_TOKEN + BootTrigger registriert 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:

MarkerProxyErhöhtWas passiert
abwesendNormaler Startvorgang, keine spezielle Routenführung
PräsentierenNeinNeinspawn proxy rundll32 to retry the schuac chain, then exit
PräsentierenJaNeinWiederhole den Schuac-Befehl innerhalb von rundll32; bei Erschöpfung lösche die Markierung und beende das Programm.
Präsentieren*JaMarkierung 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:

AufgabeAuslösenIntervallRunLevel
DotNetSvcUpdateTaskBenutzeranmeldung + Zeit3 MinutenStandard
DotNetSvcCoreTaskBooten + Zeit15 MinutenHöchstverfügbar + Versteckt
DotNetSvcUserTaskBenutzeranmeldungBeim AnmeldenStandard

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:

  1. XOR-Dekodierung eines Blobs gegen einen rotierenden 16-Byte-Schlüssel bei (decoded[i] = blob[i] ^ key[i & 0xF], wobei decoded[0] = 0x1E ein fest codiertes erstes Byte ist, das den LZNT1-Chunk-Header initialisiert.
  2. RtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1, ...) im dekodierten Puffer, der eine DLL (svcagent.dll) ist.

Pfade in Prioritätsreihenfolge verwerfen, bei Zugriffsfehlern abbrechen:

  1. %ProgramData%\AssetMon\svcagent.dll (primär)
  2. %APPDATA%\AssetMon\svcagent.dll
  3. %TEMP%\svcagent.dll
  4. 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:

  1. Zuerst die Persistenz in der Registry prüfen. CheckRegistryPersistence Läuft oben im Block. Wenn es einen Fehler meldet, führt das Implantat sofort FilelessPersist (erneute Entschlüsselung und erneutes Ablegen der Stub-DLL) und InstallPersistence (erneute Registrierung der Task-Trigger) erneut aus.
  2. Aufgabenverifizierung. SelfHealCheckTasks Anschließ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.
  3. Aktualisierung des AV-Inventars. DetectInstalledAV wird 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:

APIZweck
GetAsyncKeyStateUmfragen sind ein wichtiger Staat
GetForegroundWindowAktive Fenstererkennung
GetWindowTextAFenstertitel erfassen
MapVirtualKeyA / ToUnicodeSchlüsselübersetzung
GetClipboardSequenceNumberErkennung von Zwischenablageänderungen
OpenClipboard / GetClipboardDataZwischenablage 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:

DatenQuelle
CPURegistrierung: ProcessorNameString
GPURegistrierungsanzeigeadapter DriverDesc (Filter "Microsoft Basic")
RAMGlobalMemoryStatusEx
OSRtlGetVersion mit Build-zu-Versions-Zuordnung (Win7 bis Win11, Server 2008 bis Server 2025)
NutzernameGetUserNameW mit Fallback auf LookupAccountSidW vom explorer.exe Token
PrivilegToken-Erhöhungstyp: user, admin, admin_nouac, system
AVDetectInstalledAV Vergleicht laufende Prozesse mit einer fest codierten Liste von ca. 25–30 Prozessnamen von Antivirenherstellern.
AppsDetectInstalledApps prüft eine kuratierte Liste mit 19 zielgerichteten Apps
Firewall-StatusLiest SYSTEM\CurrentControlSet\Services\SharedAccess\Parameters\FirewallPolicy\{Domain,Standard,Public}Profile um den pro Profil aktivierten Status aufzuzeichnen.
DiensteZählung laufender Dienste über Dienstaufzählung
Maschinen-IDDJB2 (Modulname) ^ Lautstärke-Seriennummer
Öffentliche IP-AdresseMulti-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):

KategorieZiele
Kryptowährungs-Walletsledger, trezor, bitcoin-core, electrum, exodus, atomic, guarda
Botentelegram, discord, signal, viber, slack, whatsapp
E-Mail-Kundenthunderbird, outlook
2FA-Appauthy
Dateiübertragung / SSHfilezilla, winscp
Gamingsteam

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:

SchrittAktion
1/6Schreibe das Kill-Flag in HKCU und HKLM, um den Host-Prozess zu beenden.
2/6Entfernen Sie alle 3 geplanten Aufgaben über COM + CreateProcessW Fallback
3/6Entfernen der alten Registrierungseinstellungen: NTLoad-Wert, COM-Hijacking-Schlüssel, Druckmonitorschlüssel
4/6Löschen Sie Stub-DLLs, Sleeper-Logs, Registry-PE-Blobs und ProgramData-Verzeichnisse.
5/6Installationspfad und Selbstpfad von der Festplatte löschen
6/6Beende 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 input Felder 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[.]info und einem Telegram-Fallback bei t[.]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.

Techniken

Techniken stellen dar, wie ein Angreifer ein taktisches Ziel erreicht, indem er eine Aktion ausführt.

Sanierung

YARA

Elastic Security hat YARA-Regeln erstellt, um diese Aktivität zu identifizieren.

Beobachtungen

ÜberwachbarTypNameReferenz
33dacf9f854f636216e5062ca252df8e5bed652efd78b86512f5b868b11ee70fSHA-256PHANTOMPULSRATTEFinal payload
70bbb38b70fd836d66e8166ec27be9aa8535b3876596fc80c45e3de4ce327980SHA-256syncobs.exePHANTOMPULL Lader
def66275fa3baffb16e6e4ae0297861d9790ae7161fbc271a2ba05d121f13c70SHA-256Go BeaconGTESTIC_WIN-Check-in
panel.fefea22134[.]netDomainC2-PanelPHANTOMPULSE fest codierter Fallback
fea22134[.]netDomainC2 domainIn Binärform verschlüsselt
195.3.222[.]251IPv4-ADDRStaging-ServerPowerShell/Loader-Auslieferung
0xc117688c530b660e15085bF3A2B664117d8672aAKrypto-WalletBlockchain C2 WalletETH/Basis/Optimismus
0x38796B8479fDAE0A72e5E7e326c87a637D0Cbc0EKrypto-WalletFinanzierungskontoC2-Resolutionsfinanzierung
eth.blockscout[.]comDomainBlockchain-AnbieterC2-URL-Auflösung
base.blockscout[.]comDomainBlockchain-AnbieterC2-URL-Auflösung
optimism.blockscout[.]comDomainBlockchain-AnbieterC2-URL-Auflösung
hVNBUORXNiFLhYYhmutexEinzelinstanzXOR-entschlüsselt
svcagent.dllDateinameStub-DLLPersistenznutzlast
AssetMonVerzeichnisStub-DLL-Verzeichnis%ProgramData% oder %APPDATA%
healthmon.exeDateinameTropferUrsprünglicher ausführbarer Name
diagcore.dllDateinameLegacy Sideload DLLMigriert mit MigrateSideload
.elevateDateinameHöhenmarkierungRouten für den erhöhten Neustart
DotNetSvcUpdateTaskgeplante AufgabePrimäre Persistenz3-Minuten-Intervall
DotNetSvcCoreTaskgeplante AufgabeSYSTEMpersistenz15 Minuten, versteckt
DotNetSvcUserTaskgeplante AufgabeBenutzerpersistenzAnmeldeauslöser
EdgeWebViewUpdateTaskgeplante AufgabeLegacy-AufgabeWurde während der Deinstallation bereinigt.
\Microsoft\Windows\NetFramework\DotNetSvcCoreTasktask-uriBoot-TaskpfadVersteckte geplante Aufgabe
Elevation:Administrator!new:{A6BFEA43-501F-456F-A845-983D3AD7B8F0}GemeinschaftsnameUAC-UmgehungErweiterter IT-Frageservice
0x666[.]infoDomainmacOS C2macOS-Dropper
t[.]me/ax03botURLTelegram-FallbackmacOS C2 Dead-Drop
thoroughly-publisher-troy-clara[.]trycloudflare[.]comDomainVorheriges C2Cloudflare Tunnel

Referenzen

Frühere Berichte und in dieser Analyse erwähnte Tools: