Dans son analyse précédente du rapport REF6598, Elastic Security Labs a mis en évidence un ensemble d'intrusions dont la chaîne d'outils Windows a été introduite via une exploitation du plugin Obsidian, a permis une élévation de privilèges grâce à un chargeur PE en mémoire (PHANTOMPULL) et s'est conclue par l'installation d'un RAT (PHANTOMPULSE). Cet article portait sur la livraison. Cet article analyse la phase finale : PHANTOMPULSE, un implant qui intègre trois techniques d'injection de processus, résout son C2 via des entrées de transaction Ethereum/Base/Optimism et contourne l'UAC grâce à la technique de l'schuac e publique. L'analyse met en évidence un canal de commande et de contrôle (C2) basé sur la blockchain et susceptible d'être neutralisé, ainsi qu'une primitive matérielle unifiée de point d'arrêt qui désactive les technologies AMSI, WLDP et ETW, et élimine les traces omniprésentes de développement assisté par IA dans les chaînes de débogage de l'implant.
Principaux points abordés dans cet article
- PHANTOMPULSE met en œuvre trois techniques d'injection inspirées de récents PoC (preuves de concept) publics en matière de sécurité offensive.
- Les primitives AMSI, WLDP et ETW sont contournées via une seule primitive HWBP partagée
- Le résolveur C2 de la blockchain ne procède à aucune vérification de l'expéditeur, ce qui permet à un attaquant de remplacer l'URL C2 de chaque implant en envoyant une seule transaction
- Le fichier binaire contient des indicateurs clairs d'un développement assisté par l'IA
Remarque sur le développement assisté par l'IA
PHANTOMPULSE porte clairement la marque de l'assistance au codage par IA, comme en témoignent les chaînes de débogage.
Les indices les plus évidents :
- Numérotation structurée des étapes dans les journaux d'exploitation :
[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).... - Suivi de la fonction ENTER/DONE:
"[HEIS] encrypt_text_only ENTER"/"[HEIS] encrypt_text_only DONE","KeylogResolveAPIs: ENTER". Le style de diagnostic que les modèles de langage de grande envergure (LLM) adoptent par défaut lorsqu'ils génèrent de nouvelles fonctions. - Diagnostics détaillés:
"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". Un message d'erreur clair, ce qui est inhabituel pour un logiciel malveillant. - Tirets dans les chaînes C:
"elevate: FAIL — no deployed DLL path",">>> .elevate: NOT proxy — spawning trusted host to handle elevation".
Chaîne d'exécution
MainEntryLogic Il s'agit de la fonction d'orchestration qui exécute la séquence d'initialisation complète avant d'entrer dans la boucle C2 :
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
Au démarrage, l'implant effectue un hachage DJB2 du nom d'utilisateur et du nom de l'ordinateur, puis recherche chacun d'eux dans une table précalculée. Une correspondance quitte le processus. Une attaque par force brute menée sur le tableau à l'aide de listes de mots publiques anti-sandbox a permis de récupérer l' 20 s sur les entrées de l' 61 : WDAGUtilityAccount (Windows Defender Application Guard), plusieurs noms de machines virtuelles par défaut de DESKTOP-XXXXXXX, ainsi que les personas de Joe Sandbox (abby, patex, george, john, lisa, frank, RDhJ0CNFevzX).
Évasion par la défense
Appels système directs et wrappers d'API
PHANTOMPULSE résout les fonctions ntdll en parcourant les structures « PEB→Ldr » à l'aide des hachages DJB2, extrait les numéros de service système (SSN) du prologue de chaque fonction NT et génère des stubs d'appels système privés. Ces ébauches sont intégrées dans des fonctions d'assistance de niveau supérieur utilisées dans le reste de l'implant :
NtCreateFile_WrapNtWriteFile_WrapNtClose_WrapNtCreateSection_WrapNtMapViewOfSection_WrapNtProtectVirtualMemory_WrapNtWriteVirtualMemory_Wrap
Le reste de l'implant appelle ces wrappers au lieu des exportations kernel32/ntdll, contournant ainsi les hooks d'ntdll s en mode utilisateur (remplacements IAT, détournements en ligne ou correctifs trampoline) que les produits EDR injectent dans l'interface API documentée.
Une seule fonction d'aide achemine directement chaque écriture sur disque via NtCreateFile + NtWriteFile, en procédant à une suppression puis à une nouvelle tentative en cas d'erreur d'accès.
Obfuscation des chaînes de caractères et des paramètres de configuration
PHANTOMPULSE utilise quatre couches XOR pour différents artefacts :
| Quoi | Clé | Où se trouve la clé |
|---|---|---|
| URL de secours C2, mutex, noms de fichiers du chemin de secours | 16 octets : F7 7C 8E 40 DF C1 7B E5 E7 4D 86 79 D5 B3 53 41 | Intégré dans .rdata |
| Noms d'hôte des fournisseurs de blockchain (UTF-16 LE) | 8 octets : 5A 3C 7E 1D 9F 2B 4E 8A | Intégré dans .rdata |
| Nom du fichier « COM Elevation », contenu du fichier keylog | 0xE95CA237, calculée lors de l'exécution afin d'éviter d'inclure la constante dans .rdata | Calculé, non enregistré |
URL C2 extraite d'une transaction sur la blockchain input | L'adresse du portefeuille du résolveur elle-même | Repris de la clé de recherche publique |
Contournement des fonctions AMSI, WLDP et ETW via des points d'arrêt matériels
PHANTOMPULSE désactive AMSI, la vérification de la fiabilité du code dans la stratégie de verrouillage de Windows, ainsi que la télémétrie ETW, grâce à une seule primitive commune : un point d'arrêt matériel placé à chaque entrée d'API, intercepté par un gestionnaire d'exceptions vectorisé qui simule la valeur de retour sans recourir à un patch en ligne.
| Machine à sous | API cible | Retour falsifié (RAX) |
|---|---|---|
| DR0 | WldpQueryDynamicCodeTrust | 0 (S_OK) |
| DR1 | AmsiScanBuffer | 0x80070057 (E_INVALIDARG) |
| DR2 | EtwEventWrite | 0 (STATUS_SUCCESS) |
Le fonctionnement, étape par étape :
- L'implant résout l'API cible. AMSI et WLDP passent par
LoadLibraryA+ une recherche d'exportation basée sur le hachage ; ETW utilise un parcours PEB→Ldr puisque ntdll est déjà chargé. - Le descripteur HWBP (adresse API cible, mode, valeur de retour falsifiée) est écrit dans l'un des quatre emplacements de 40 octets d'une table d'emplacements globale.
- Un thread d'assistance suspend le thread cible, appelle les fonctions
NtGetContextThread/NtSetContextThreadpour écrire les registres DR0 à DR3 et DR7, puis reprend son exécution.STATUS_BREAKPOINT(Si le gestionnaire d'exceptions vectorisé de l'implant est déjà installé, une exception « in-process » est alors déclenchée, ce qui permet au VEH de lire la table des emplacements et de programmer les DR sans recourir à un thread d'assistance.) - Lorsque l'API protégée est appelée, le processeur génère une exception «
Debug Exception» dès la première instruction de la fonction. - Le gestionnaire d'exceptions vectorisé de l'implant intercepte l'
Debug Exception, parcourt sa table à 4 emplacements pour trouver l'adresse d'exécution, puis modifie le contexte du thread :CONTEXT.Raxest défini sur la valeur de retour falsifiée propre à chaque emplacement, tandis queCONTEXT.Ripest redirigé vers un thunk de saut "préenregistré" qui renvoie le contrôle à l'appelant. - Le gestionnaire renvoie
EXCEPTION_CONTINUE_EXECUTION. L'appelant perçoit le RAX falsifié comme si l'API avait été exécutée.
Le répartiteur gère deux itinéraires. Un gestionnaire (VEH_Dispatcher) traite à la fois les appels ` RaiseException(STATUS_BREAKPOINT) ` propres à l'implant (utilisés pour initialiser et reprogrammer les registres DR à partir de la table des emplacements) et les exceptions ` STATUS_SINGLE_STEP ` qui se déclenchent lorsqu'une API protégée est appelée. Le code d'exception détermine la branche : « STATUS_BREAKPOINT » déclenche la programmation DR, tandis que « STATUS_SINGLE_STEP » déclenche la simulation.
Le gestionnaire n'est pas non plus enregistré directement. AddVectoredExceptionHandler reçoit un petit thunk JMP alloué à l'exécution dans une nouvelle page d'MEM_PRIVATE s (VirtualAlloc + VirtualProtect vers PAGE_EXECUTE_READ). Le thunk est un saut indirect de type « JMP [RIP-relative] » (code d'opération de 6 octets : FF 25 00 00 00 00) suivi, en ligne, de l'adresse du dispatcher. Étant donné qu'aucun octet n'est jamais écrit dans les fichiers AmsiScanBuffer, WldpQueryDynamicCodeTrust ou EtwEventWrite, la détection basée sur les signatures qui recherche des modifications du prologue passe complètement à côté de ce problème.
Variante de construction : sous-systèmes actifs et dormants
Plusieurs sous-systèmes sont présents dans le fichier binaire sous forme de code ou de chaînes de caractères, mais ne sont pas actifs dans cette version. Il s'agit d'une version allégée d'un code source plus volumineux.
- Désactivation de NTDLL: les chaînes de débogage relatives au sous-système de désactivation se trouvent dans
.rdata(UnhookNtdll: ntdll base = %p,applied %d relocation fixups to .text), mais aucune référence n'y est faite. Cette variante est obsolète. - Chargeur de blobs PE résidant dans le registre: les versions antérieures stockaient le fichier PE de l'étape suivante dans le registre. Ce programme ne le fait pas, mais la routine de désinstallation supprime tout de même les entrées obsolètes du registre.
- Persistance du détournement COM: n'est jamais installée par cette version. La logique de nettoyage correspondante reste dans la routine de désinstallation.
- Persistance du moniteur d'impression: même schéma que pour le détournement COM ; chemin d'installation absent, chemin de désinstallation conservé.
Les trois derniers (chargeur de blobs du registre, détournement COM, moniteur d'impression) présentent un schéma inverse : une logique de nettoyage sans logique d'installation, conservée pour assurer la compatibilité ascendante avec les anciens déploiements.
| Fonctionnalité | compilation des charges utiles | Données probantes |
|---|---|---|
| Appels système directs (extraction du SSN) | Actif | Extraction du numéro de sécurité sociale + génération du stub confirmées |
| Contournement AMSI / WLDP / ETW HWBP | Actif | DR0/DR1/DR2 via une primitive de thread d'assistance partagé |
| Injection en trois étapes | Actif | PhantomInject, DbgNexum, ManualMap sont tous opérationnels |
| Résolution C2 relative à la blockchain | Actif | Trois fournisseurs de Blockscout ont été interrogés |
| Désactivation de NTDLL | Code mort | Chaînes présentes, aucune référence au code |
| Cryptage HEIS | Désactivé | Code de chiffrement/déchiffrement simulé |
| Chargeur de blobs PE résidant dans le registre | Ancienne version uniquement | Nettoyage effectué uniquement lors de la désinstallation |
| Persistance du détournement COM | Ancienne version uniquement | Supprimé lors de la désinstallation, jamais installé |
| Persistance de l'impression | Ancienne version uniquement | Supprimé lors de la désinstallation, jamais installé |
| Chaînes leurres | Actif | 4 chaînes factices non référencées dans .rdata |
Commande et contrôle
Résolution C2 relative à la blockchain
PHANTOMPULSE décentralise la recherche C2 via trois fournisseurs Blockscout :
eth.blockscout[.]com(Ethereum L1)base.blockscout[.]com(Base L2)optimism.blockscout[.]com(Optimisme L2)
L'adresse de portefeuille 0xc117688c530b660e15085bF3A2B664117d8672aA est déchiffrée par XOR à partir de la mémoire à l'aide d'une clé de 16 octets. Pour chaque fournisseur, l'implant envoie une requête GET HTTPS (port 443, erreurs de certificat SSL ignorées), récupère le champ « input » de la dernière transaction, le convertit en décimal, le déchiffre par XOR en utilisant les octets de l'adresse du portefeuille comme clé, puis vérifie que le résultat commence par http. En cas d'échec total, le système se rabat sur l'URL fixe https://panel.fefea22134[.]net.
Le résolveur ne vérifie pas l'identité de l'expéditeur de la transaction. Il vérifie simplement que l'input e décodée la plus récente commence par http. N'importe qui peut envoyer une transaction vers ce portefeuille en incluant sa propre URL codée en XOR dans les octets du portefeuille, et chaque instance PHANTOMPULSE de cette campagne qui effectuera une interrogation par la suite sera redirigée vers cette URL. Pour les responsables de la sécurité réseau, il s'agit d'un piège efficace qui ne coûte qu'une seule transaction.
Points de terminaison et signal de santé
Cinq chemins d'accès API sont générés lors de l'exécution, puis rechiffrés en mémoire à l'aide d'une clé propre à chaque session :
| Chemin | Méthode | Type de contenu | Finalité |
|---|---|---|---|
/v1/telemetry/report | POST | application/json | Heartbeat avec télémétrie complète du système |
/v1/telemetry/tasks/<machine_id> | GET | Recherche de commandes | |
/v1/telemetry/upload/ | POST | image/bmp | Capture d'écran / téléchargement de fichiers |
/v1/telemetry/result | POST | application/json | Commande livraison du résultat |
/v1/telemetry/keylog/ | POST | text/plain | Téléchargement des données du journal de bord |
Le heartbeat envoie un profil complet du système au format 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>"
}
Deux champs de réponse sont analysés : "status":"deleted" déclenche une désinstallation complète ; "ip":"<value>" alimente le cache des adresses IP publiques, mais uniquement si la découverte locale (ipif[.]org / icanhazip[.]com/ checkip.amazonaws[.]com) si ce n'est pas déjà fait.
Cadence de boucle et résilience
- Sommeil: durée aléatoire uniforme comprise entre 20 et 40 secondes
- Auto-réparation: s'exécute à la 2e itération, puis toutes les 10 itérations
- Contrôle de l'état de santé: premier appel dès la mise en service de l'implant, puis tous les cinq cycles par la suite. Remplit une structure d'informations système locale (% s sur le processeur, la mémoire vive, la version du système d'exploitation, la durée de fonctionnement et le nom de l'ordinateur).
- Seuil de défaillance: 10 défaillances consécutives du signal de pulsation déclenchent un redémarrage automatique pour la récupération SSL/TLS bloquée
- Nouvelle résolution: en cas d'échec, le processus de nouvelle résolution de la blockchain est lancé ; si l'URL résolue change, le compteur d'échecs est remis à zéro
- Adresse IP publique:
api4.ipify[.]org→ipv4.icanhazip[.]com→checkip.amazonaws[.]com - Vérification de la connectivité: sondes
microsoft[.]com,google[.]com,cloudflare[.]com,github[.]com
Envoi des commandes
Le répartiteur de commandes achemine les commandes en fonction du hachage DJB2. Huit commandes au total :
| Hachures | Commandement | Comportement |
|---|---|---|
0x04CF1142 | inject | Injecter du shellcode, une DLL ou un fichier EXE. Pistes par type : shellcode → PhantomInject; DLL → ManualMap; EXE → DbgNexum. Les contournements AMSI et WLDP HWBP sont installés lors du premier appel à l'inject (le contournement ETW HWBP est déjà en place depuis EvasionInit). |
0x7C95D91A | drop | Placez le fichier sur le disque et exécutez-le. Prend en charge les charges utiles au format DLL, EXE, shellcode (injection APC) et MSI. |
0x9A37F083 | screenshot | Capturez l'image GDI, réduisez-la à une largeur de 960 pixels, puis téléchargez-la au format BMP. |
0x08DEDEF0 | keylog | Démarrez ou arrêtez l'enregistreur de frappe intégré. |
0x4EE251FF | uninstall | Nettoyage et désinstallation en 6 étapes. |
0x65CCC50B | elevate | Contournement de l'UAC via la technique « schuac » (IElevatedFactoryServer::ServerCreateElevatedObject(CLSID_TaskScheduler)) ; enregistrement d'une tâche à privilèges élevés de courte durée qui relance l'implant. |
0xB3B5B880 | downgrade | SYSTÈME → transition vers un compte administrateur. |
0x20CE3BC8 | (redémarrage automatique) | Arrêt automatique en cascade : NtTerminateProcess(-1, 0) effectue d'abord l'appel système direct ; si celui-ci échoue, le système se rabat sur ExitProcess(0). Persistence relance l'implant lors du prochain cycle de tâche prévu. Cela revient, en pratique, à un redémarrage en douceur. |
Le huitième gestionnaire n'apparaît dans aucun journal de débogage. Elle se termine automatiquement ; la tâche planifiée relance l'implant au prochain cycle. L'absence de structure de type LLM (chaînes de débogage) fait de ce gestionnaire l'un des rares du binaire à sembler avoir été ajouté par un développeur humain plutôt que généré par un LLM.
Techniques d'injection
PHANTOMPULSE propose trois techniques d'injection, une par type de charge utile. La commande C2 de l'inject redirige le shellcode vers PhantomInject, les DLL vers ManualMap et les fichiers EXE vers DbgNexum.
Les contournements des points d'arrêt matériels AMSI/WLDP sont installés lors du premier appel à ` inject `, avant l'exécution de tout injecteur.
| Type de charge utile | Injecteur | Stratégie |
|---|---|---|
| Shellcode | PhantomInject | Utilisation de modules dans « dbghelp.dll » via SEC_IMAGE |
| EXE | DbgNexum | Machine à états de l'API de débogage |
| DLL | ManualMap | Mappage manuel complet de la mémoire physique |
PhantomInject : module qui s'intègre à dbghelp.dll
Le « module stomping » permet d'éviter l'allocation de mémoire par l'MEM_PRIVATE, en mappant une DLL Windows légitime en tant qu'« SEC_IMAGE » et en écrasant « .text » :
-
Récupère l'
SeDebugPrivilege(viaOpenProcessToken/LookupPrivilegeValueW/AdjustTokenPrivileges), puis parcourt l'instantané du processus pour l'un des sept processus hôtes candidats (correspondance sans distinction de casse). Essayés par ordre de priorité :sihost.exe,taskhostw.exe,backgroundTaskHost.exe,RuntimeBroker.exe,dllhost.exe,ctfmon.exe,explorer.exe. -
Ouvre
dbghelp.dllviaNtOpenFile, crée la sectionSEC_IMAGE, et la mappe vers la cible viaNtMapViewOfSection -
Analyse la copie locale pour déterminer l'adresse RVA et la taille de la mémoire allouée (
.text), puis la libère -
Sélectionne et suspend un thread, capture le contexte
-
Écrit du shellcode et un trampoline dans l'
.texte de la DLL mappée -
Active la protection
PAGE_EXECUTE_READ -
Renvoie vers le trampoline, reprend le fil de discussion
Pour un analyseur de mémoire, le résultat ressemble à un thread s'exécutant au sein d'une instance légitime d'dbghelp.dll, une zone d'image associée à un fichier comportant le chemin d'accès, le nom de section et le hachage de la première page corrects.
DbgNexum : une API de débogage servant de contrôleur d'exécution
DbgNexum prend en charge les charges utiles EXE. Plutôt que d'écrire d'emblée du code exécutable dans la cible, il utilise l'API de débogage Windows pour faire avancer l'exécution exception par exception : une chaîne ROP dont les gadgets sont des API Windows complètes dans la cible.
Cette technique n'est pas une invention de PHANTOMPULSE. Il s'agit d'une reproduction mot pour mot de dis0rder0x00/DbgNexum, une démonstration publique de faisabilité publiée sur GitHub le 4 janvier 2026. L'opérateur a conservé tel quel le nom de la technique publiée ("DbgNexum") dans les chaînes de débogage de l'implant, et la machine à états interne correspond en tous points : même API d'appât, même nom de section, même chaîne de gadgets et mêmes constantes. PHANTOMPULSE intègre le cœur x64 extrait à une infrastructure opérationnelle dont le PoC ne dispose pas : la sélection du processus hôte (FindHostProcessEx), un mécanisme de secours qui lance une nouvelle instance de SysWOW64\cmd.exe / rundll32.exe / notepad.exe, un programme de démarrage personnalisé pour le chargement de fichiers PE (afin de pouvoir prendre en charge des fichiers EXE complets plutôt que du shellcode brut), et une variante inter-architectures WoW64 distincte.
Pour les charges utiles x64 natives, l'implant pré-positionne le fichier PE, le stub de démarrage et la configuration du trampoline au sein d'une section de mappage de fichiers nommée. Le nom de la section est la chaîne littérale de deux octets « "MZ" » ; l'implant se connecte à l'adresse « DebugActiveProcess » et crée un thread distant à l'adresse « FileTimeToSystemTime » avec un point d'arrêt matériel sur DR0.
Lorsque l'appât atteint le point de rupture, un automate d'états guide la cible à travers cette chaîne d'API :
- Redirigez
RIPversDbgBreakPoint+1en activant le drapeau « trap » ; l'exception à étape unique qui en résulte se propage vers le reste de la chaîne. LocalAlloc(LMEM_ZEROINIT, 3), allouez le tampon de nom de 3 octets.memcpy(buf, kernel32_base, 2), copiez le contenu de la ligne «"MZ"» de l'en-tête DOS du fichier «kernel32.dll» dans le tampon.memset(stack+40, 0, 8): réinitialiser un emplacement d'argument de la pile.OpenFileMappingA(0x1F, FALSE, "MZ"), ouvrez la section préparée avec un accès complet à la cartographie de la section.MapViewOfFile(...), et l'appliquez à la cible.- Redirigez
RIPversmapped_base + 0x400, la page de démarrage. Il s'agit de la seule étape enregistrée directement :DbgNexumLoop64: stage 6 -> stub at %llx, base=%llx. (Le PoC redirige versmapped_base + 0pour le shellcode brut ; PHANTOMPULSE ajoute le décalage+0x400pour accéder à son chargeur PE personnalisé.)
Chaque transition intercepte l'événement de débogage suivant, rétablit l'état de l'instruction de branchement ( RSP), efface l'indicateur de trap, modifie l'instruction de branchement ( RIP ) et les registres d'arguments (RCX, RDX, R8, R9) pour l'appel suivant, puis poursuit l'exécution du programme débogué. DR0 est réutilisé comme point d'arrêt matériel d'exécution à chaque adresse de retour enregistrée ; il n'est donc pas nécessaire d'appliquer des correctifs en ligne ni de procéder à des modifications du code ( WriteProcessMemory ) sur la cible. Du point de vue du noyau, tout ce qui s'est passé, c'est qu'un thread au sein de kernel32.dll a appelé LocalAlloc, OpenFileMappingA et MapViewOfFile.
La voie inter-architectures (PE32 à partir d'un implant 64 bits) est une variante propre à PHANTOMPULSE qui n'est pas présente dans la démonstration de faisabilité publique. Il emprunte un raccourci : l'implant parcourt l'PEB.Ldr e de la cible via NtReadVirtualMemory (en utilisant ProcessWow64Information pour choisir la structure PEB 32 bits ou 64 bits) afin de trouver une DLL dotée d'un point d'entrée appelable, puis pré-mappe une section contenant un stub de chargeur 32 bits et un trampoline dans les deux processus via NtCreateSection + NtMapViewOfSection. La redirection se fait en deux étapes : un appât sur RtlExitUserThread, puis un saut en une seule étape via DbgBreakPointqui redirige vers RIP, le site de destination. Il n'y a pas de chaîne API sur ce chemin, car la section est déjà mappée des deux côtés ; les adresses OpenFileMappingAetMapViewOfFile ne sont donc pas nécessaires.
La sélection d'un hôte inter-architectures s'effectue via FindHostProcessEx, ce qui exclut les processus système critiques (csrss.exe, lsass.exe, smss.exe, winlogon.exe, services.exe, wininit.exe, svchost.exe, MsMpEng.exe) et, si aucun hôte WoW64 utilisable n'est trouvé, revient à la création d'un nouvel hôte SysWOW64\cmd.exe / rundll32.exe / notepad.exe.
ManualMap : outil complet de cartographie PE
ManualMap gère les charges utiles DLL grâce à une implémentation complète du mappage manuel PE :
-
Valide la signature MZ/PE ; rejette PE32 dans le chemin d'accès de l'hôte x64 (journal de débogage :
"PE32 DLL in x64 host is impossible") -
Alloue l'
SizeOfImagee dans la cible viaNtAllocateVirtualMemory -
Copie les en-têtes et les sections dans une mémoire tampon locale
-
Applique les relocalisations de base (
IMAGE_REL_BASED_DIR64,IMAGE_REL_BASED_HIGHLOW) -
Résout les problèmes d'importation via
LoadLibraryA+GetProcAddress -
Efface les en-têtes PE (octets de zéro
SizeOfHeaders) -
Enregistre l'image mise en scène dans l'allocation distante
-
Définit la protection de la mémoire par section
-
Crée un trampoline de 137 octets dans une allocation distante distincte de 2 000 octets (définie sur
PAGE_EXECUTE_READ) :
Le gist complet du shellcode Trampoline contient l'ensemble des octets.
10. Détourne un thread via suspend / get-context / set-context
Escalade des privilèges
La commande « elevate » permet de contourner le contrôle de compte d'utilisateur (UAC) grâce à la technique «schuac » (IElevatedFactoryServer::ServerCreateElevatedObject(CLSID_TaskScheduler)), publiée sous le numéro 129 de l'UACME par zcgonvh, et actuellement référencée sous l'identifiant 74.
Mécanisme
MaintenanceUI.dllLe service « CMaintenanceUIVirtualFactory » (CLSID {A6BFEA43-501F-456F-A845-983D3AD7B8F0}) est enregistré via la clé de registre Elevation; par conséquent, le système d'exploitation fournit aux utilisateurs non administrateurs une instance avec des privilèges élevés. Son interface ` IElevatedFactoryServer ` expose ` ServerCreateElevatedObject(rclsid, riid, ppv)`, que le serveur privilégié utilise pour instancier tout autre CLSID dans son contexte privilégié. PHANTOMPULSE transmet l'adresse CLSID_TaskScheduler, obtient en retour une instance de ITaskService, puis utilise ce service pour enregistrer une tâche HighestAvailable-RunLevel qui relance l'implant.
La commande C2 de l'elevate
Dans le fichier ` ProcessCommands`, le gestionnaire `elevate` :
- Crée l'action de la tâche. La commande est «
<system_dir>\rundll32.exe» avec les arguments «\"<deployed_dll>\",DllRegisterServer». L'identifiant de l'utilisateur estCOMPUTERNAME\USERNAME, issu deGetEnvironmentVariableW. ![Appel de la commande « Elevate »][/assets/images/blockchain-c2-phantompulse-rat-sinkhole/image17.png] - Écrit le marqueur «
.elevate» sous la forme d'un seul octet ("1",0x31), et non sous forme de paramètres encodés. L'écriture passe parNtCreateFile+NtWriteFileafin de contourner les hooks en mode utilisateur. Le marqueur sert uniquement à signaler sa présence ; les paramètres d'élévation sont intégrés dans la définition de la tâche que l'implant s'apprête à enregistrer. - XOR-décrypte le moniker d'élévation de privilèges COM lors de l'exécution : 66 octets provenant de
.rdata, soumis à une opération XOR avec la clé de départ0xE95CA237, ce qui donneElevation:Administrator!new:{A6BFEA43-501F-456F-A845-983D3AD7B8F0}. - Appelle la fonction `
CoGetObject(moniker, &BIND_OPTS3{dwClassContext=CLSCTX_LOCAL_SERVER}, IID_IElevatedFactoryServer, &factory)` pour obtenir un objet `IElevatedFactoryServer*` disposant de privilèges élevés, puis la fonction `factory->ServerCreateElevatedObject(CLSID_TaskScheduler, IID_ITaskService, &elevatedTaskService)` pour obtenir un objet `ITaskService*` qui hérite de ces privilèges. - Enregistre une tâche temporaire
DotNetSvcElevateTaskau niveau d'exécutionHighestAvailableà l'aide de l'action rundll32 ci-dessus. - Supprime toutes les tâches persistantes non privilégiées existantes afin d'éviter que l'ancienne persistance à faible niveau d'intégrité ne se chevauche avec le redémarrage privilégié.
- Appelle la fonction `
ITaskService::Run` sur la tâche temporaire, puis la supprime immédiatement après. Libère le mutex à instance unique et quitte l'implant à niveau d'implémentation intermédiaire.
Nouvelle tentative de secours via le proxy rundll32
Si la chaîne CoGetObject / RegisterTask ne fonctionne pas, un chemin de secours prend le relais. Un processus de démarrage distinct lance une nouvelle instance d'rundll32.exe "<deployed_dll>",DllRegisterServer directement via CreateProcessW, avec des tentatives de reconnexion (">>> .elevate redirect attempt %d"). Au sein de cette fonction rundll32, l'implant détecte les adresses isProxy=1 et elevated=0, puis relance la séquence SCHUAC avec trois variantes d'enregistrement (ELEVATED+INTERACTIVE+user, ELEVATED+INTERACTIVE et INTERACTIVE). En cas de réussite, la tâche exécutée avec des privilèges élevés se lance et le redémarrage avec des privilèges élevés prend le relais. En cas d'épuisement, le proxy enregistre la ligne « ">>> Phase 1: all registration methods failed, cleaning marker" » dans le journal et se ferme.
Relance de rundll32 avec droits d'administrateur
Lorsque la tâche temporaire se déclenche, svchost.exe (Schedule) lance rundll32.exe "<deployed_dll>",DllRegisterServer sous un nouveau jeton à niveau d'intégrité élevé. Le flux de sortie de l'DllRegisterServer ation de l'implant s'exécute en tant que processus d'entrée ; au démarrage, il détecte le marqueur « .elevate » et un jeton à privilèges élevés, puis est redirigé vers le chemin d'accès privilégié :
- Lit et supprime le marqueur «
.elevate». - Réinstalle la persistance dans un contexte privilégié, y compris la tâche de démarrage
DotNetSvcCoreTaskdisponible à l'adresse\Microsoft\Windows\NetFramework\, enregistrée surINTERACTIVE_TOKENetBootTrigger, ce qui nécessite un compte administrateur pour l'enregistrement. - L'implant continue de fonctionner normalement en tant que service à haut niveau d'intégrité.
Routage par état des marqueurs
À chaque démarrage, la fonction ` MainEntryLogic ` appelle la fonction ` GetFileAttributesW ` dans le chemin d'accès ` .elevate `. Si la valeur renvoyée est « INVALID_FILE_ATTRIBUTES », l'implant ignore toute la logique d'élévation et démarre normalement. Si le marqueur existe, l'implant recueille deux informations supplémentaires : si le processus en cours est un proxy rundll32.exe/regsvr32.exe, et si le jeton dispose de privilèges élevés, puis effectue le routage en fonction de cette combinaison :
| Marqueur | Proxy | Surélevé | Ce qui se passe |
|---|---|---|---|
| absent | n/a | n/a | démarrage normal, sans routage particulier |
| Présent | Non | Non | lancer le proxy rundll32 pour relancer la chaîne SchuAC, puis quitter |
| Présent | Oui | Non | réessayez la fonction schuac à l'intérieur de rundll32 ; en cas d'échec, supprimez le marqueur et quittez |
| Présent | * | Oui | Supprimer le marqueur, réactiver la persistance via la tâche de démarrage, poursuivre en mode haute intégrité |
Le contenu du fichier de marqueurs n'est jamais lu ; sa simple présence détermine le routage.
Le document « Exploring Windows UAC Bypasses » d'Elastic Security Labs traite directement des modèles de détection pour la catégorie de contournements « IElevatedFactoryServer ».
Persistance
Trois tâches planifiées
PHANTOMPULSE installe trois tâches planifiées via l'interface COM ITaskService, chacune exécutant rundll32.exe "<stub_dll>",DllRegisterServer:
| Tâche | Déclencheur | Intervalle | Niveau d'exécution |
|---|---|---|---|
DotNetSvcUpdateTask | Identifiant de l'utilisateur + Heure | 3 min | Standard |
DotNetSvcCoreTask | Démarrage + Heure | 15 min | Max. disponible + Caché |
DotNetSvcUserTask | Connexion de l'utilisateur | À la connexion | Standard |
La tâche de démarrage se trouve sous \Microsoft\Windows\NetFramework\ afin de se fondre parmi les tâches de maintenance .NET légitimes. Son corps XML complet est intégré dans .rdata; il n'est pas généré au moment de l'exécution. Les signatures associées à ce bloc de données brut sont conservées d'une compilation à l'autre.
Le programme d'installation essaie plusieurs variantes de secours d'RegisterTask s par tâche, en combinant les types de connexion INTERACTIVE_TOKEN et S4U avec différents formats d'identifiant utilisateur (COMPUTER\User, SID, nom d'utilisateur court). L'ordre exact des tentatives dépend du niveau de privilèges de l'implant (SYSTEM, administrateur ou utilisateur standard) ; en cas d'échec, le système passe à la variante suivante jusqu'à ce que l'une d'entre elles aboutisse.
Déploiement de DLL de base
L'agent déployé est stocké sous forme cryptée et compressée dans le fichier EXE lui-même .rdata. FilelessPersist le déchiffre à la demande et enregistre le résultat sur le disque via (NtCreateFile + NtWriteFile).
Le déchiffrement se déroule en deux étapes :
- Décodez un blob par opération XOR à l'aide d'une clé rotative de 16 octets disponible à l'adresse (
decoded[i] = blob[i] ^ key[i & 0xF]), en utilisantdecoded[0] = 0x1Ecomme premier octet codé en dur qui initialise l'en-tête du bloc LZNT1. RtlDecompressBuffer(COMPRESSION_FORMAT_LZNT1, ...)sur le tampon décodé, qui est une DLL (svcagent.dll).
Supprimer les chemins d'accès par ordre de priorité, en passant au niveau inférieur en cas d'erreur d'accès :
%ProgramData%\AssetMon\svcagent.dll(primaire)%APPDATA%\AssetMon\svcagent.dll%TEMP%\svcagent.dll- Une copie de sauvegarde de l'article «
%ProgramData%» ( ") et de l'article « sleeper » (" ) sur un chemin d'accès distinct
Les analystes peuvent reproduire la DLL déployée hors ligne en extrayant les deux zones ci-dessus de l'EXE, en appliquant la boucle XOR, puis en transmettant le résultat à RtlDecompressBuffer (ou à n'importe quelle implémentation de LZNT1), comme le montre la capture d'écran de CyberChef ci-dessous.
Migration du chargement latéral des DLL
Un bloc situé dans le fichier « SetupRegistryPE » (enregistré avec les préfixes de chaîne de débogage « MigrateSideload » / « MigrateLegacySideloads ») répertorie les processus en cours d'exécution et leurs répertoires d'exécutables, à la recherche de « diagcore.dll ». S'il est trouvé, il remplace le fichier par le fichier de remplacement actuel via CopyFileW.
Réparation automatique
La fonction d'auto-réparation s'exécute à l' 2 e itération de la boucle C2, puis toutes les 10 itérations par la suite, sous réserve que l'indicateur de persistance différée soit désactivé. L'ordre de paiement :
- Vérifiez d'abord la persistance du registre.
CheckRegistryPersistencese trouve en haut du bloc. Si l'état est jugé anormal, l'implant relance immédiatement les processusFilelessPersist(il déchiffre à nouveau et réimplante la DLL stub) etInstallPersistence(il réenregistre les déclencheurs de tâches). - Vérification des tâches.
SelfHealCheckTaskspuis vérifie les trois tâches de persistance (DotNetSvcUpdateTask,DotNetSvcCoreTask,DotNetSvcUserTask) et réinstalle celles qui manquent. La vérification de la tâche de démarrage est conditionnée au contexte SYSTEM ou admin ; les appelants non privilégiés la sautent. - Mise à jour du parc audiovisuel.
DetectInstalledAVs'exécute à la fin pour actualiser la liste des produits audiovisuels visible par l'opérateur.
La condition de privilège est déterminante pour l'expulsion. Dans un contexte non privilégié, la vérification de la tâche de démarrage est ignorée ; la tâche de démarrage n'est donc pas inspectée lors du nettoyage. Pour procéder à une suppression complète, il faut supprimer les trois tâches ainsi que l'entrée de registre dans une seule fenêtre à partir d'un compte administrateur.
Au-delà de la fonction d'auto-réparation par itération, l'implant intègre un mécanisme de persistance différée déclenché par un seul indicateur. Dans les chemins de traitement des signaux de pulsation réussis de la fonction ` C2Loop_Main`, dès que le compteur de signaux de pulsation réussis dépasse la valeur 1 et que l'indicateur est activé, l'implant réexécute les fonctions ` FilelessPersist ` et ` InstallPersistence `, puis désactive l'indicateur. Cela offre à PHANTOMPULSE une deuxième voie de réparation de la persistance qui se déclenche sur la base d'un autre événement que l'auto-réparation par itération.
Collecte
Enregistreur de frappe intégré avec surveillance du presse-papiers
Le keylogger s'exécute en ligne dans la boucle C2, sans thread dédié. Il résout les API provenant de user32.dll lors de l'exécution :
| API | Finalité |
|---|---|
GetAsyncKeyState | Sondage dans un État clé |
GetForegroundWindow | Détection de la fenêtre active |
GetWindowTextA | Capture du titre de la fenêtre |
MapVirtualKeyA / ToUnicode | Traduction des clés |
GetClipboardSequenceNumber | Détection des modifications dans le presse-papiers |
OpenClipboard / GetClipboardData | Lecture du presse-papiers (CF_UNICODETEXT) |
Le fichier journal est chiffré par XOR à l'aide de la graine 0xE95CA237. Les téléchargements n'envoient que les modifications afin d'éviter toute retransmission.
Capture
Les captures d'écran utilisent les API GDI identifiées par hachage. Si la largeur de l'écran dépasse 960 px, l'image est réduite avant le téléchargement. Le fichier BMP brut est généré en mémoire et téléchargé à l'aide de la commande ` Content-Type: image/bmp`. Déclenché à la demande par la commande C2 de l'screenshot (hachage 0x9A37F083).
Reconnaissance du système
Données de reconnaissance recueillies par l'implant :
| Données | Source |
|---|---|
| Processeur | Registre : ProcessorNameString |
| GPU | DriverDesc de la carte graphique dans le Registre (filtres "Microsoft Basic") |
| RAM | GlobalMemoryStatusEx |
| OS | RtlGetVersion avec mise en correspondance des versions de build (de Windows 7 à Windows 11, de Server 2008 à Server 2025) |
| Nom d'utilisateur | GetUserNameW avec redirection vers LookupAccountSidW à partir du jeton explorer.exe |
| Privilège | Types d'élévation de jetons : user, admin, admin_nouac, system |
| AV | DetectInstalledAV compare les processus en cours d'exécution à une liste fixe comprenant environ 25 à 30 noms de processus de fournisseurs d'antivirus |
| Applications | DetectInstalledApps passe en revue une liste de 19 applications sélectionnées avec soin |
| État du pare-feu | Lit la variable « SYSTEM\CurrentControlSet\Services\SharedAccess\Parameters\FirewallPolicy\{Domain,Standard,Public}Profile » pour enregistrer l'état d'activation par profil |
| Services | Comptage des services en cours d'exécution via l'énumération des services |
| Identifiant de la machine | DJB2 (nom du module) ^ numéro de série du volume |
| Adresse IP publique | Chaîne HTTPS multi-API |
La liste des antivirus couverts est exceptionnellement vaste et inclut les principaux produits antivirus grand public occidentaux tels que Defender, Norton, McAfee, Avast, AVG, Avira, Bitdefender, ESET, F-Secure, G Data, Kaspersky, Panda, Sophos, Trend Micro, VIPRE, Webroot, ZoneAlarm, Comodo ainsi que les fournisseurs de solutions EDR (CrowdStrike, SentinelOne, Cylance, Malwarebytes, HitmanPro) sont tous pris en compte. L'implant recherche également AhnLab V3 (sud-coréen), Qihoo 360 / 360 Total Security et Tencent QQPC (chinois), ainsi que K7 Computing (indien). La présence d'éléments Asian-AV est inhabituelle pour les logiciels de vol de données destinés au marché occidental, ce qui correspond à un implant conçu pour des victimes issues de plusieurs marchés régionaux.
L'implant vérifie également si une liste sélectionnée d'applications à forte valeur ajoutée de l' 19 , classées par nom, est présente, et signale les correspondances dans le signal de santé (App detection: found %d apps) :
| Catégorie | Objectifs |
|---|---|
| Portefeuilles de crypto-monnaies | ledger, trezor, bitcoin-core, electrum, exodus, atomic, guarda |
| Messagers | telegram, discord, signal, viber, slack, whatsapp |
| Clients de messagerie | thunderbird, outlook |
| Application d'authentification à deux facteurs | authy |
| Transfert de fichiers / SSH | filezilla, winscp |
| Jeux | steam |
La fonction de détection (DetectInstalledApps) n' analyse pas le registre et ne répertorie pas les processus. Il développe trois racines de variables d'environnement (%LOCALAPPDATA%, %APPDATA%, %ProgramFiles(x86)%), puis concatène un suffixe de chemin relatif en UTF-16 prédéfini pour chaque application (par exemple \Telegram Desktop\, \Authy Desktop\, \Ledger Live\, \@trezor\trezor-suite\, \Steam\steam.exe), et appelle la fonction GetFileAttributesW pour chaque chemin. Un retour sans erreur signifie que l'application est installée et que son nom est enregistré dans la mémoire tampon des résultats de la vérification de l'état.
PHANTOMPULSE n'extrait lui-même aucune donnée de ces sources. Cette liste sert à la reconnaissance des cibles en vue de missions ultérieures. L'opérateur identifie, grâce à Heartbeat, les applications à forte valeur ajoutée dont dispose une victime donnée et détermine quelle charge utile spécialisée il convient d'injecter ensuite via inject ou drop.
Aucune fonctionnalité de vol de portefeuille, de navigateur, de messagerie instantanée ou d'identifiants n'a été identifiée dans l'échantillon analysé ; la liste des cibles sert uniquement à vérifier la présence des éléments concernés et alimente l'arbre de décision de l'opérateur.
Désinstaller
Une procédure de nettoyage en 6 étapes, déclenchée par la commande « uninstall », par la commande « "status":"deleted" » dans une réponse Heartbeat, ou par un indicateur de suppression dans le registre :
| Étape | Action |
|---|---|
| 1/6 | Enregistrer le drapeau d'arrêt dans HKCU et HKLM, arrêter le processus hôte |
| 2/6 | Supprimez toutes les tâches planifiées d' 3 s via le mode de secours COM+ CreateProcessW |
| 3/6 | Supprimer les entrées obsolètes du registre : la valeur NTLoad, les clés de détournement COM et les clés du moniteur d'impression |
| 4/6 | Supprimer les fichiers DLL fantômes, les journaux dormants, les blobs PE du registre et les répertoires ProgramData |
| 5/6 | Supprimer le chemin d'installation et le chemin d'accès au programme du disque |
| 6/6 | Fermez les instances résiduelles d'healthmon.exe, ainsi que toutes les instances d'rundll32.exe qui hébergent svcagent.dll |
L'étape n° 3 e les techniques de persistance héritées : la logique de nettoyage pour le détournement COM et les clés du moniteur d'impression que cette version n'installe jamais.
Attribution
Les techniques opérationnelles, les cibles et les choix d'infrastructure de PHANTOMPULSE correspondent à ceux des groupes d'intrusion cryptographiques liés à la RPDC, parmi lesquels figurent Lazarus, BlueNoroff, UNC5342 (Contagious Interview) et APT38. Plusieurs aspects distincts concordent avec les informations rendues publiques récemment concernant ces groupes.
Des indices qui concordent avec les informations fournies par la RPDC :
- Le C2 identifié via la blockchain grâce aux champs d'
inputs de transaction correspond au modèle de résolveur de « dead drop » que Mandiant attribue à UNC5342 (Contagious Interview) dans l'article « La RPDC adopte EtherHiding ». Les caractéristiques spécifiques de PHANTOMPULSE (XOR de données de portefeuille, Blockscout multi-chaînes) ne constituent pas une empreinte digitale exacte, mais cette catégorie de techniques est désormais associée à la Corée du Nord. - La liste des crypto-portefeuilles de bureau recensés (
ledger,trezor,bitcoin-core,electrum,exodus,atomic,guarda) correspond étroitement à la liste des cibles du logiciel RustDoor / Koi Stealer pour macOS identifié par Unit 42, attribué à la RPDC. - Les implants multiplateformes Windows + macOS ciblant le même profil de victime (le précédent article REF6598 décrivait un variant macOS avec un serveur de commande et de contrôle accessible à l'adresse
0x666[.]infoet un canal Telegram de secours à l'adresset[.]me/ax03bot) constituent une signature de BlueNoroff. - Le ciblage sur Telegram et Messenger est précisément l'une des spécialités de BlueNoroff, comme l'indique la couverture d'Arctic Wolf BlueNoroff.
Recherche de nouveaux domaines C2 à l'aide de la signature en texte clair connue du portefeuille Resolver
Le schéma XOR utilisé par le résolveur de la blockchain divulgue une signature stable de 2 octets que les pirates peuvent exploiter sur l'ensemble de la chaîne, et pas seulement sur un seul portefeuille.
Deux éléments se combinent : chaque URL C2 commence par ht (provenant de http:// ou https://), et la clé XOR correspond exactement à l'adresse ASCII du portefeuille ; par conséquent, ses deux premiers octets sont toujours les caractères littéraux 0 et x. En effectuant une opération XOR entre ht et 0x, on obtient \x58 \x0c. Chaque champ « input » chiffré généré par un résolveur de type PHANTOMPULSE, sur n'importe quelle chaîne, et signé par n'importe quel portefeuille associé, commence par les quatre caractères hexadécimaux « 580c ».
Cela transforme la recherche, qui consistait à surveiller un seul portefeuille, en une analyse systématique de la chaîne à la recherche de la signature. Les données publiques relatives aux transactions sur Ethereum, Base et Optimism peuvent être consultées via BigQuery, Dune ou des nœuds d'archivage complets. Une requête effectuée sur l'ensemble de données public des transactions Ethereum, visant les valeurs d'adresse de type « input » commençant par « 0x580c » et limitée à une fenêtre de temps de bloc récente, a permis de mettre en évidence des portefeuilles de résolution jusqu'alors inconnus, utilisés par la même base de code. Chaque correspondance est validée par décodage, en utilisant l'adresse ASCII du portefeuille de l'expéditeur comme clé : une véritable URL C2 commence par http après décodage. La recette CyberChef suivante permet de déchiffrer l'URL C2.
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 peut déchiffrer les données d'entrée pour révéler le domaine, comme le montre la capture d'écran ci-dessous.
Conclusion
PHANTOMPULSE est conçu à partir de composants connus : module de « stomping », machines à états via l'API de débogage, mappage manuel, contournement des points d'arrêt matériels AMSI/WLDP/ETW, persistance des tâches planifiées et communication C2 via la blockchain. La cohésion et la solidité de l'ensemble témoignent d'un code mature en cours de développement actif. Ces signaux persistants sont de nature comportementale et sont couverts par les protections comportementales d'Elastic pour REF6598.
PHANTOMPULSE et MITRE ATT&CK
Elastic utilise le cadre MITRE ATT&CK pour documenter les tactiques, techniques et procédures communes que les menaces persistantes avancées utilisent contre les réseaux d'entreprise.
Tactiques
Les tactiques expliquent le pourquoi d'une technique ou d'une sous-technique. C'est l'objectif tactique de l'adversaire : la raison pour laquelle il mène une action.
- Accès initial
- Exécution
- Persistance
- Escalade des privilèges
- Évasion par la défense
- Accès aux identifiants
- Découverte
- Collecte
- Commande et contrôle
- Exfiltration
Techniques
Les techniques représentent la manière dont un adversaire atteint un objectif tactique en effectuant une action.
- Phishing : Spearphishing par le biais d'un service
- Interprète de commandes et de scripts : PowerShell
- Injection de processus
- Injection dans un processus : injection de DLL
- Exécution du proxy binaire du système : Msiexec
- Exécution du proxy binaire du système : Rundll32
- Tâche programmée/Job : Tâche programmée
- Exécution de démarrage automatique à l'amorçage ou à l'ouverture de session
- Modifier le registre
- Affaiblir les défenses : Désactiver ou modifier des outils
- Suppression d'indicateurs : suppression de fichiers
- Recherche d'informations sur le système
- Découverte du propriétaire ou de l'utilisateur du système
- Découverte du processus
- Découverte de logiciels : Découverte de logiciels de sécurité
- Capture d'entrée : Enregistrement du clavier
- Données du presse-papiers
- Capture d'écran
- Exfiltration par le canal C2
- Protocole de la couche d'application : Protocoles Web
- Service Web
- Canal crypté
- Masquage des fichiers ou des informations
- Décodage des fichiers ou des informations
- Manipulation des tokens d'accès
- Abuser d'un mécanisme de contrôle d'élévation : Contournement du contrôle de compte d'utilisateur
- API native
- Évasion par virtualisation/boîte à sable : Evasion basée sur le temps
- Flux d'exécution du pirate : chargement latéral de DLL
- Chargement du code réfléchissant
Remédiation
YARA
Elastic Security a créé des règles YARA pour identifier cette activité.
Observations
| Observable | Type | Nom | Référence |
|---|---|---|---|
33dacf9f854f636216e5062ca252df8e5bed652efd78b86512f5b868b11ee70f | SHA-256 | PHANTOMPULSE RAT | Final payload |
70bbb38b70fd836d66e8166ec27be9aa8535b3876596fc80c45e3de4ce327980 | SHA-256 | syncobs.exe | Chargeur PHANTOMPULL |
def66275fa3baffb16e6e4ae0297861d9790ae7161fbc271a2ba05d121f13c70 | SHA-256 | Aller à la balise | Enregistrement GTESTIC_WIN |
panel.fefea22134[.]net | Domain | Panneau C2 | Règle de repli codée en dur pour PHANTOMPULSE |
fea22134[.]net | Domain | C2 domain | Crypté en binaire |
195.3.222[.]251 | ipv4-addr | Serveur de préproduction | PowerShell/déploiement du chargeur |
0xc117688c530b660e15085bF3A2B664117d8672aA | porte-monnaie électronique | Portefeuille Blockchain C2 | ETH/Base/Optimism |
0x38796B8479fDAE0A72e5E7e326c87a637D0Cbc0E | porte-monnaie électronique | Portefeuille de financement | Financement de la résolution C2 |
eth.blockscout[.]com | Domain | Fournisseur de solutions blockchain | Résolution d'URL C2 |
base.blockscout[.]com | Domain | Fournisseur de solutions blockchain | Résolution d'URL C2 |
optimism.blockscout[.]com | Domain | Fournisseur de solutions blockchain | Résolution d'URL C2 |
hVNBUORXNiFLhYYh | mutex | Exemplaire unique | décrypté par XOR |
svcagent.dll | nom-de-fichier | DLL de base | Charge utile de persistance |
AssetMon | répertoire | Répertoire des fichiers DLL de remplacement | %ProgramData% ou %APPDATA% |
healthmon.exe | nom-de-fichier | Compte-gouttes | Nom d'origine du fichier exécutable |
diagcore.dll | nom-de-fichier | DLL de chargement latéral héritée | Migré par MigrateSideload |
.elevate | nom-de-fichier | Repère d'altitude | Itinéraires du relancement surélevé |
DotNetSvcUpdateTask | tâche planifiée | Persistance primaire | Intervalle de 3 minutes |
DotNetSvcCoreTask | tâche planifiée | Persistance du système | 15 minutes, en mode caché |
DotNetSvcUserTask | tâche planifiée | Persistance des données utilisateur | Déclencheur de connexion |
EdgeWebViewUpdateTask | tâche planifiée | Tâche héritée | Nettoyé lors de la désinstallation |
\Microsoft\Windows\NetFramework\DotNetSvcCoreTask | tâches | Chemin d'accès aux tâches de démarrage | Tâche planifiée masquée |
Elevation:Administrator!new:{A6BFEA43-501F-456F-A845-983D3AD7B8F0} | com-moniker | Contournement de l'UAC | ITaskService avec droits étendus |
0x666[.]info | Domain | macOS C2 | programme de distribution pour macOS |
t[.]me/ax03bot | Url | Solution de secours pour Telegram | Point de dépôt sur macOS C2 |
thoroughly-publisher-troy-clara[.]trycloudflare[.]com | Domain | Précédent C2 | Cloudflare Tunnel |
Références
Rapports antérieurs et guides pratiques mentionnés dans la présente analyse :
- Phantom in the vault : Obsidian a abusé de la livraison du RAT PhantomPulse
- Blockscout, l'explorateur Ethereum
- La RPDC adopte EtherHiding
- Interview de Contagious / Des faux recruteurs ciblent les développeurs du secteur des cryptomonnaies
- RustDoor et Koi Stealer pour macOS
- L'évolution de BeaverTail et OtterCookie
- DbgNexum : démonstration de faisabilité
- Numéro 129 de l'UACME : contournement de l'UAC par schuac
- Exploration des méthodes permettant de contourner le contrôle de compte d'utilisateur (UAC) de Windows
- Modification de la mémoire pour contourner AMSI