Mélofée revient, et il a évolué ! Trois ans après sa découverte, de nouveaux échantillons de cet implant Linux se révèlent nettement plus sophistiqués : décomposition en modules, chargeables et déchargeables à chaud, des fonctionnalités de shell, de fichiers et d'exécution de commandes, reconfiguration à distance de l'infrastructure C2 et toujours une grande furtivité grâce à un rootkit noyau. Stormshield documente ici la rétro-ingénierie complète de ces variants, lève le voile sur deux clusters d'infrastructure armés de certificats factices, et établit avec une confiance élevée un lien de filiation avec d'autres familles d'implants ciblant Windows.
Contexte
Mélofée est une famille de malware ciblant les systèmes Linux, documentée pour la première fois en 2023 [1] et attribuée à des groupes d'attaquants avancés probablement liés à des intérêts étatiques chinois.
Lors d'une investigation, nous avons identifié de nouveaux échantillons liés à cette famille.
Nous présenterons dans cet article les nouvelles fonctionnalités des implants montrant une modularisation accrue du code, ainsi qu'une évolution des protocoles de communication supportés. Au travers de cet article, nous montrerons que ces nouveaux échantillons partagent des similitudes importantes avec des codes existants tels que CrowDoor, Hemigate, ou RatelS. Ces similitudes nous permettent d'évaluer que ces différents codes sont très probablement partagés entre plusieurs groupes d'attaquants liés à des intérêts étatiques chinois.
Mélofée depuis 2023 : contexte et état de l'art

Les chercheurs décrivaient alors une famille de malware ciblant les serveurs Linux, attribuée avec un niveau de confiance élevé à des groupes d'attaquants liés à la Chine, notamment des acteurs proches de APT41 [1, 15].
L'analyse de trois échantillons découverts en 2022 a mis en évidence l'évolution continue de l'implant, caractérisée par l'intégration progressive d'un rootkit noyau basé sur le projet open source Reptile, lequel a ensuite été examiné par AhnLab en juillet 2023 [3].
Dès cette première analyse, Mélofée présentait plusieurs fonctionnalités caractéristiques des implants Linux modernes :
- Exécution de commandes à distance ;
- Gestion de fichiers ;
- Ouverture d'un shell interactif ;
- Collecte d'informations système ;
- Communication avec des serveurs de commande et contrôle (C2) ;
- Mécanismes de persistance.
L'analyse de l'infrastructure liée à Mélofée a également permis d'identifier des liens avec plusieurs outils déjà observés dans des campagnes associées à des groupes APT chinois, notamment ShadowPad, HelloBot, PlugX, Spark, Cobalt Strike et StowAway [1, 11].
En novembre 2024, XLab (Qianxin) a publié une analyse [4] d'un nouveau variant ciblant les systèmes RHEL 7.9. Cette publication confirme la poursuite du développement de l'implant depuis sa découverte, avec plusieurs évolutions techniques détaillées dans la suite de ce document. Les chercheurs notent également le nombre limité d'échantillons disponibles, ce qui suggère un usage restreint à des cibles spécifiques.
Évolutions entre les versions 2023 et 2024
Le fonctionnement principal de l'implant reste similaire entre les différentes versions. Les mêmes commandes de base sont présentes, avec uniquement une renumérotation des identifiants de commande entre les versions.
Plusieurs évolutions apparaissent toutefois entre les échantillons de 2023 et le variant observé en 2024 :
- Gestion des processus : la version 2024 ajoute des commandes permettant de lister et de terminer des processus ;
- Persistance : le mécanisme évolue avec l'utilisation de tâches crontab, l'utilisation d'un fichier de service systemd se faisant passer pour un service légitime vmware ;
- Chargement du driver noyau : le pilote est désormais chiffré en RC4 et directement intégré au binaire principal sous forme d'overlay, contrairement aux versions précédentes où il était fourni séparément par l'installateur ;
- Modification du code interne : plusieurs éléments du code ont été renommés, ce qui suggère une réorganisation ou une reconstruction partielle du code source.
Nouveaux variants en 2026
Description
L'analyse de trois échantillons montre que Mélofée a évolué depuis les versions précédemment observées. Si les mécanismes de communication réseau et le chiffrement RC4 restent similaires, plusieurs changements ont été identifiés, notamment l’ajout de nouvelles capacités, la modularisation de certaines fonctionnalités sous forme de librairie dynamique et des modifications internes de l’implant. Ces évolutions sont détaillées dans les sections suivantes.
L'implant contient un module principal, capable d'exécuter quelques commandes de base. Il est également capable de supporter des fonctionnalités aditionnelles via le téléchargement de modules complémentaires depuis le C2.
Le tableau ci‑dessous récapitule l’ensemble des commandes supportées :
ID | Description | Remarques |
Commandes de base de l'implant (Module embarqué 0x1000) | ||
0x1004 | Récupération de la configuration C2 active. | |
0x1005 | Chargement d'une nouvelle configuration C2, mais ne remplace pas la configuration embarquée. | Cette commande prend en paramètre une structure de données contenant jusqu'à trois configurations C2. |
0x1006 | Désinstaller l’implant et supprimer tous les fichiers qu’il a créés. | |
0x1007 | Proxy TCP. | |
0x100A | Inventaire des modules chargés. | |
0x100B | Commande déclarée mais non implémentée. | |
0x100C | Déchargement d'un module. | Cette commande prend en paramètre l'identifiant d'un module (par exemple 0x3000). |
0x100D | Forward server. | Fonctionalité déjà existante |
0x100E | Interrompt toutes les connexions et met l’implant en pause pour une durée définie. | Cette commande accepte un paramètre numérique représentant la durée en minutes de mise en veille de l'implant. |
Identifiants utilisée en réponse (traités par le C2) | ||
0x1001 | Cette identifiant est utilisé dans un paquet contenant les informations relatives à la victime, puis attend en retour la valeur magic number transmise par le serveur C2 afin de poursuivre la communication. | Cet identifiant est généré de manière transparente par l'implant à chaque connexion au C2 pour amorcer le dialogue. L'attaquant n'a jamais à solliciter cette commande. |
0x1002 | Identifiant utilisé par le module pour demander un téléchargement de module complémentaire au C2 | Cet identifiant est renvoyé après une demande de l'opérateur |
0x1003 | Signalement de présence (heartbeat) | L'implant envoie également l'identifiant unique basé sur le condensat JSHash des informations système. |
Commande du module Shell (0x2000) | ||
0x2001 | Interactive shell interface. | |
Commandes du module pour la gestion des fichiers et répertoires (0x3000) | ||
0x3002 | Lister le contenu d'un dossier. | |
0x3003 | Supprimer un fichier ou un dossier. | |
0x3004 | Créer un nouveau dossier. | |
0x3005 | Modifier les dates de création, d'accès et de modification des fichiers où des répertoires. | |
0x3006 | Lancer le téléchargement d'un fichier depuis le serveur de l'attaquant vers la machine de la victime. | |
0x3007 | Lancer l'exfiltration d'un fichier depuis la machine de la victime vers le serveur de l'attaquant. | |
Commande du module pour l'exécution de commande à distance (0x4000) | ||
0x4001 | Exécution de commande à distance. | |
Fonctionnement global
Phase d'initialisation de l'implant
L'implant prend plusieurs arguments en ligne de commande :
/t:assure une persistance via lacrontab;/s:assure une persistance du malware via un servicesystemd;/r:lance le binaire en mode démon via un appel àdaemon;/u:désinstalle l'implant et les fichiers de persistance associés ;hide:active la fonction de camouflage du rootkit ;show:désactive la fonction de camouflage du rootkit.
Lors de son exécution, l'implant effectue des actions préparatoires afin d'établir son environnement d'exécution afin de :
- Auto-référencement : l'implant lit le fichier
/proc/self/exeafin de récupérer son propre chemin d'exécution sur le système ; - Verrou d'instance unique : l'implant met en place un mutex non bloquant via l'appel
flock()sur un fichier dédié (/tmp/lock_axdans les échantillons analysés). Ce mécanisme empêche plusieurs instances de fonctionner simultanément sur une même machine ; - Vérification de compatibilité du noyau : avant de charger le rootkit, l'implant vérifie l'environnement d'exécution de la machine compromise. Il récupère la version du noyau Linux via l'appel
uname(), puis s'assure qu'il est compatible avec le rootkit. Si ce n'est pas le cas, l'implant abandonne le chargement du rootkit et poursuit son exécution dans le cas contraire. Le rootkit fournit les capacités de dissimulation utilisées par l'implant. La communication entre le processus utilisateur et le module noyau repose sur une interfaceioctl()utilisant le code de requête0xE0E0E0E.
Le fonctionnement de ce rootkit ne sera pas détaillé dans cette analyse, celui-ci ayant déjà été documenté par XLab Qianxin [4].
Phase de collecte d'informations système
Avant tout contact avec le serveur C2, l'implant collecte plusieurs informations sur la machine compromise afin de constituer une fiche d'identification de l'hôte. Cette collecte permet à l'opérateur de disposer d'un contexte sur la machine infectée avant l'exécution des fonctionnalités opérationnelles de l'implant.
L'implant génère tout d'abord un identifiant unique de machine via l'algorithme JSHash (Justin Sobel [13]).
uint Calculate_JSHash(char *param_1, uint param_2)
{
uint local_c = 0x4e67c6a7;
for (uint i = 0; i < param_2; i++) {
local_c = local_c ^ (local_c >> 2) + local_c * 0x20 + (int)param_1[i];
}
return local_c;
}
Cette implémentation utilise la constante d'initialisation 0x4E67C6A7. La valeur hachée est calculée à partir de plusieurs attributs système récupérés par l'implant :
- la plateforme cible, dans notre cas "Linux" ;
- la distribution Linux ;
- l'utilisateur courant ;
- le nom d'hôte de la machine.
En complément de cet identifiant, l'implant collecte les informations suivantes :
- Nom d'hôte : récupération du nom de la machine ;
- Utilisateur courant : récupération du compte associé à la session active ;
- Distribution Linux : identification du système d'exploitation (via la lecture du fichier
/etc/issueou/etc/redhat-release) ; - Adresses IPv4 locales : interrogation des interfaces réseau (via un appel à la fonction
getifaddrs) ; - Plateforme cible : Valeur fixe indiquant l'environnement (
linux) ; - Horodatage : récupération de la date et de l'heure système via un appel à
localtime(et un formatage au format%m-%d-%Y %H:%M:%S).
L'ensemble des informations collectées est ensuite concaténé dans une chaîne texte séparée par des tabulations :
<Machine_ID_JSHASH>\t<Hostname>\t<Username>\t<Distribution>\t<Local_IPs>\t<Platform>\t<Timestamp>
Cette fiche d’identification est envoyée au serveur C2 à chaque connexion. L’implant ne se contente pas de l’envoyer au premier contact. Il refait automatiquement cette collecte et renvoie la fiche après :
- Lors d'une reconnexion après coupure ;
- En sortie de période de veille ;
- Suite à un redémarrage de l'implant.
Protocoles de communication
Afin d'assurer sa liaison, l'implant intègre une configuration de secours comprenant jusqu'à trois serveurs C2 (définis par un hôte, un port et un type de protocole). Il tente de se connecter à chacun d'eux successivement jusqu'à ce qu'une connexion aboutisse, ce qui fige le canal actif et stoppe les autres tentatives. L'analyse du code a mis en évidence plusieurs mécanismes de communication distincts pour ces entrées.
Le tableau suivant présente les caractéristiques de chaque type identifié :
Type | Nom | Description |
1 / 5 | TcpConn | Mode TCP classique. L'implant résout l'adresse du serveur via getaddrinfo(), crée un socket IPv4 TCP puis établit la connexion avec connect(). Aucun échange préalable supplémentaire n'est réalisé. |
2 | HttpConn | Mode TCP avec une poignée de main applicative au format HTTP minimal. Après l'établissement de la connexion TCP, l'implant envoie POST / HTTP/1.1rn et attend la réponse HTTP/1.1 200 OKrn avant d'initialiser la session. |
3 | HttpsConn | Mode reposant sur une connexion TLS suivie d'une Handshake HTTP minimale similaire à celle du type 2, utilisée pour valider le canal de communication avant l'initialisation de la session C2. |
4 | TlsConn | Mode établissant une connexion TCP encapsulée dans TLS. Les captures réseau réalisées en environnement contrôlé confirment l'utilisation de TLS 1.2. |
Format du protocole applicatif
Chaque message applicatif suit une structure à deux parties :
┌───────────────────────────┬─────────────────────────┐
│ HEADER (16 octets, clair) │ PAYLOAD (N octets, RC4) |
└───────────────────────────┴─────────────────────────┘
L'en-tête, transmis en clair, possède la structure suivante :
struct PacketHeader {
uint32_t type; // Command Opcode
uint32_t length; // Payload Size
uint32_t param1; // Usage varying with command type
uint32_t param2; // Usage varying with command type
};
Les deux derniers champs servent d'opérandes pour certaines instructions. À titre d'exemple, lors d'une demande de téléchargement, le quatrième champ véhicule l'identifiant du module requis.
La charge utile (payload) optionnelle est, quand elle est présente, chiffrée en RC4 au moyen d'une clé statique embarquée dans les implants (Trbv5245GTF dans les échantillons analysés).
Exemple 1 : Demande de téléchargement de module (0x1002)
Le paquet réseau prend la forme suivante :
00 00 10 02 00 00 00 00 00 00 00 02 00 00 30 00
└───type───┘└───length─┘ └───param1─┘ └───param2─┘
0x1002 0 2 0x3000
Lors de cette demande, les paramètres de la structure sont définis ainsi :
- Type : 0x1002 (identifiant de réponse utilisé par l'implant) ;
- Taille du payload : 0 (aucun contenu additionnel dans le payload) ;
- Paramètre 1 : 2 (code fixe de sous-commande) ;
- Paramètre 2 : Identifiant du module demandé (ici, 0x3000 pour la gestion de fichiers) ;
- Payload : Vide
Exemple 2 : Suppression de fichier (0x3003)
Le paquet réseau prend la forme suivante :
00 00 30 03 00 00 00 0d 00 00 00 00 00 00 00 00
└──type──┘ └─length─┘ └─param1─┘ └─param2─┘
0x3003 13 octets 0 0
(DelFile)
Payload (13 octets, RC4(`/tmp/test.txt`))
Hexdump:
00000000 00 00 30 03 00 00 00 0d 00 00 00 00 00 00 00 00 |..0.............|
00000010 2f 74 6d 70 2f 74 65 73 74 2e 74 78 74 |/tmp/test.txt |
Une fois le module chargée en mémoire, l'appel de ses fonctionnalités internes s'effectue selon une structure de données spécifique. Dans ce cas précis, les champs paramètre 1 et paramètre 2 restent à zéro, car la donnée utile est entièrement déportée dans le payload. Ce dernier contient le chemin du fichier à cibler (par exemple /tmp/test.txt), chiffré en RC4.
Exemple 3 : Le paquet d'enregistrement
Le paquet réseau prend la forme suivante :
Header (16 bytes, clear):
00 00 10 01 00 00 00 8e 00 00 00 00 00 00 00 00
└──type──┘ └─length──┘ └─param1─┘ └─param2──┘
0x1001 142(0x8e) 0 0
Payload (142 bytes, RC4 encryption), once decrypted :
1496026344 localhost.localdomain root Red Hat Enterprise Linux Server release 7.9 (Maipo) 127.0.0.1 192.168.100.128 linux 08-02-2026 10:53:21
Hexdump:
00000000 00 00 10 01 00 00 00 8e 00 00 00 00 00 00 00 00 |................|
00000010 31 34 39 36 30 32 36 33 34 34 09 6c 6f 63 61 6c |1496026344.local|
00000020 68 6f 73 74 2e 6c 6f 63 61 6c 64 6f 6d 61 69 6e |host.localdomain|
00000030 09 72 6f 6f 74 09 52 65 64 20 48 61 74 20 45 6e |.root.Red Hat En|
00000040 74 65 72 70 72 69 73 65 20 4c 69 6e 75 78 20 53 |terprise Linux S|
00000050 65 72 76 65 72 20 72 65 6c 65 61 73 65 20 37 2e |erver release 7.|
00000060 39 20 28 4d 61 69 70 6f 29 09 31 32 37 2e 30 2e |9 (Maipo).127.0.|
00000070 30 2e 31 20 31 39 32 2e 31 36 38 2e 31 30 30 2e |0.1 192.168.100.|
00000080 31 32 38 20 09 6c 69 6e 75 78 09 30 38 2d 30 32 |128 .linux.08-02|
00000090 2d 32 30 32 36 20 31 30 3a 35 33 3a 32 31 |2026 10:53:21 |
Ce message permet à l'implant de remonter les caractéristiques de chaque hôte compromis ainsi que son identifiant unique.
Authentification des liaisons auprès du serveur C2
L'implant valide sa communication avec le serveur C2 en une ou deux étapes selon le mode de communication sélectionné. Ces contrôles sont strictement bloquants : si une validation échoue, l'implant reste inactif et n'entre jamais dans sa boucle d'exécution de commandes.
Phase de pré-connexion HTTP (Spécifique au modes HttpConn et HttpsConn)
Cet échange applicatif constitue le tout premier contact réseau sous le protocole HTTP. L'implant commence par envoyer une chaîne statique de 17 octets :
50 4f 53 54 20 2f 20 48 54 54 50 2f 31 2e 31 0d 0a
POST / HTTP/1.1\r\n (17 bytes)
Hexdump:
00000000 50 4f 53 54 20 2f 20 48 54 54 50 2f 31 2e 31 0d |POST / HTTP/1.1.|
00000010 0a |.|
Le serveur C2 doit obligatoirement répondre par exactement 17 octets contenant la chaîne :
48 54 54 50 2f 31 2e 31 20 32 30 30 20 4f 4b 0d 0a
HTTP/1.1 200 OK\r\n (exactly 17 bytes)
Hexdump:
00000000 48 54 54 50 2f 31 2e 31 20 32 30 30 20 4f 4b 0d |HTTP/1.1 200 OK.|
00000010 0a |. |
La vérification dans le binaire est particulièrement stricte. L'analyse du code montre que l'implant contrôle d'abord la taille exacte reçue (0x11 en hexadécimal, soit 17 octets), puis effectue une comparaison octet par octet en mémoire :
if (bytes_received == 0x11) {
iVar1 = memcmp(&http_buffer, "HTTP/1.1 200 OK\r\n", 0x11);
if (iVar1 == 0) {
Si la taille reçue est différente, ou si le contenu ne correspond pas exactement, l'implant interrompt la connexion. Ce mécanisme basique lui permet de s'assurer qu'il dialogue bien avec son infrastructure.
Authentification de la liaison (commune à tous les modes)
Obligatoire pour l'ensemble des mécanismes de communication, cet échange intervient immédiatement après la transmission du paquet d'enregistrement initial (voir l'exemple de structure 0x1001 ci-dessous). Le serveur C2 doit alors répondre par exactement 4 octets bruts, sans aucun en-tête ni chiffrement :
11 22 33 44 (value 0x11223344 en network byte order)
Le code correspondant :
BaseConn::recvn(pBVar5, &local_ec, 4, 60000); // Reads exactly 4 bytes, timeout 60s
if ((iVar3 == 0) && (my_htonl(local_ec) == 0x11223344))
Si les 4 octets reçus ne correspondent pas strictement à cette constante, ou si le délai de 60 secondes est dépassé, la connexion est immédiatement rejetée par l'implant.
Récapitulatif du fonctionnement global
L'architecture globale demeure inchangée par rapport aux versions de 2023 et 2024, mais les implants se distinguent désormais par l'ajout de nouvelles fonctionnalités qui sont détaillées dans le prochain paragraphe.
Présentation des nouvelles fonctionnalités
Récupération de la configuration réseau active
Cette fonctionnalité, identifiée par l'ID 0x1004, permet de récupérer la configuration réseau active de l'implant et de la transmettre au serveur de commande et de contrôle (C2).
Chargement d'une nouvelle configuration réseau
Cette fonctionnalité, identifiée par l'ID 0x1005, permet de charger dynamiquement une nouvelle configuration C2 sans modifier la configuration réseau embarquée.
Le diagramme ci-dessous illustre la logique du chargement d'une nouvelle configuration réseau au sein de l'implant :

L'implant effectue une vérification stricte du fichier de configuration qui doit être :
- Taille égale à 228 octets (0xe4) : l'implant valide le fichier externe et applique la nouvelle configuration.
- Taille différente ou fichier absent : le fichier est jugé invalide. L'implant rejette la modification et utilise la configuration embarquée.
Gestion dynamique de modules
L'implant utilise un système de module lui permettant de charger dynamiquement des fonctionnalités complémentaires.
Cette modularisation est basée sur les éléments suivants:
- Un identifiant de module calculé dynamiquement par un masque de bits :
dwModuleID = dwCommandId & 0xF000; - Une liste chaînée contenant les modules déjà chargés (initialisée avec le module central embarqué
0x1000) ; - L'exposition par chaque module d'une interface commune (détaillée ci après).
L'implant supporte 11 modules (en complément du module central), identifiés de 0x2000 à 0xC000.
L'analyse statique des implants a également permis d'identifier plusieurs références à des chemins temporaires utilisés lors du mécanisme de chargement dynamique des modules.
En effet, lors du déploiement d'un module par l'attaquant, celui-ci est stocké dans un fichier nommé au format /tmp/PLGID.
Par ailleurs, deux commandes supplémentaires ont été ajoutées dans l'implant permettant de gérer ces plugins :
- La commande
0x100A, permettant d'obtenir la liste des modules actifs au sein de l'implant ; - La commande
0x100Cpermettant le déchargement d'un module. Elle offre à l'opérateur la possibilité de retirer un module actif sans nécessiter de redémarrage.
Téléchargement et chargement de module
Le diagramme ci-dessous retrace les différentes étapes du chargement d'un module par l'implant :

Modules connus
Nos investigations ont permis d'identifier trois modules, associés aux identifiants 0x2000, 0x3000 et 0x4000. Les modules associés aux identifiants 0x5000 à 0xc000 n'ont pas pu être identifiés.
Identifiant | Nom de fichier | SHA256 | Fonctionnalité |
0x2000 | /tmp/2000 | cbce7dc8649b37c5db411dfee3a74e8cace2b48fdc8350bfa5b4846c5d9ed2ae | Shell interactif |
0x3000 | /tmp/3000 | 9d01724193d9570a6c75bbcbb171d29df290207007d004cf75d133dd9aa475f4 | Gestion de fichiers |
0x4000 | /tmp/4000 | 129349a221e6efcc9a047efdfd81197f796fcf38877344f17f85651b21e33427 | Exécution de commande à distance |
Interface de plugin (commun à tous les modules)
Les modules analysés présentent une structure commune et exportent tous une fonction nommée xmain servant de point d'entrée.
Chaque module implémente une interface identique (GetPlgInterface), composée de trois fonctions :
GetPlugId: Cette fonction retourne l'identifiant du module.WritePlugin: Cette fonction est appelée par l'orchestrateur en lui fournissant la commande demandée par l'attaquant ainsi que ses paramètres éventuels.SetBackCall: Cette fonction permet à l'orchestrateur de fournir un certain nombre de fonctions utilitaires à chaque module (telle que l'exécution de shell interactif ou la gestion de tunnels réseau).
Par ailleurs, l'ensemble des modules analysés utilisait les mêmes classes pour gérer ses communications : BaseConn, elle même utilisant une classe utilitaire SocketApi exposant une surcouche des fonctions standard de la libc.
Il est également à noter que le module principal de l'implant expose une interface identique.
Module de shell interactif (CShell)
Contrairement aux versions de 2023 et 2024 où elle était directement intégrée, cette capacité d'exécution de commandes à distance est désormais externalisée sous forme de module.
Son fonctionnement repose sur la création d'un pseudo-terminal (PTY) pour offrir un shell classique. Le module y redirige les flux d'entrée, de sortie standard et d'erreur, puis tente de lancer l'interpréteur /bin/bash (avec un repli automatique vers /bin/sh en cas d'échec). Avant le lancement du shell, l'environnement d'exécution est configuré notamment via les variables TERM et HISTFILE afin de contrôler l'affichage et de désactiver l'enregistrement de l'historique des commandes.
Module de gestion des fichiers et répertoires (CFile)
Auparavant intégrées directement au cœur de l'implant Mélofée (versions 2023-2024), les capacités de manipulation de fichiers sont désormais externalisées.
Ce module permet à l'opérateur de charger dynamiquement les fonctionnalités suivantes :
- Énumération des fichiers et répertoires ;
- Suppression de fichiers ;
- Création de répertoires ;
- Modification des horodatages des fichiers ;
- Envoi de fichiers vers la machine compromise ;
- Téléchargement de fichiers depuis la machine compromise.
Module d'exécution de commandes à distance (CCmd)
Autrefois implémenté dans l'implant principal de Mélofée, cette capacité d'exécution a été externalisée dans un module. Le composant reçoit une commande, l'exécute localement sur l'hôte via un appel au binaire /bin/sh, puis récupère sa sortie standard ainsi que sa sortie d’erreur avant de transmettre le résultat au serveur C2.
Contrairement au module de session shell, cette fonctionnalité est strictement limitée à des lancements de commandes unitaires et n'offre aucun terminal interactif.
Infrastructure
Lors de nos investigations, nous avons pu identifier deux clusters d'infrastructure liés à ces implants, sans toutefois pouvoir identifier d'autres implants communiquant avec cette infrastructure.
L'ensemble des IOCs identifiés est disponible dans les annexes de cet article.
Cluster Symantec
L'ensemble des adresses IP et des domaines utilisés en C2 dans les samples les plus récents exposaient le même certificat autosigné possédant un champ Issuer usurpant l'identité de Symantec (C=US, ST=California, L=California, O=Symantec Corp).
En utilisant l'empreinte SHA1 de ce certificat (dbbcb279a1f1a258832174ce63c295c5080de249) comme point de pivot, il a été possible d'identifier plusieurs serveurs C2 très probablement liés à cette menace.
Il est à noter que les TTPs consistant à utiliser des certificats se faisant passer pour des produits liés à l'informatique, ainsi que des noms de domaines contenant update ont déjà été documentés pour des serveurs liés à l'outil ShadowPad [6].
Cluster Xdevops
Lors de l'analyse de l'échantillon 4400096e8b39cb2641abec17c6dddad845ed6415e79d60adc2af1dcbd2837c59, nous avons identifié que l'adresse IP résolue par son serveur de C2 exposait également un certificat autosigné (Issuer: /C=US/ST=MI/L=Southfield/O=xdevops/OU=xdevops/CN=update.miss-soft[.]com, SHA-1: b6df18f66cf4364be2946d6b981e69763aafde68).
En utilisant ce certificat comme point de pivot, nous avons identifié un deuxième cluster d'activité, enregistrant des domaines ressemblants à des domaines Amazon.
Similarités avec des familles de codes malveillants existantes
Les échantillons Mélofée étudiés lors de notre investigation présentent de nombreuses similarités avec plusieurs familles d'implants existants, bien que ceux-ci ciblent le système d'exploitation Windows.
Les familles qui ressortent de cette analyse sont les suivantes :
- SparrowDoor / CrowDoor, une famille d'implants Windows découverts par ESET en 2025, et lié au groupe d'attaquants FamousSparrow [5] ;
- TernDoor, une famille d'implants possiblement dérivés de CrowDoor, documenté par Cisco Talos [7] ;
- Hemigate: une famille d'implants partagée par plusieurs groupes d'attaquants [8] ; [8] ;
- LibreCoin/Ratels, une famille d'implants probablement liée à Hemigate [8, 11, 12].
En particulier, les similarités suivants ont été confirmées lors de notre analyse :
- Utilisation de l'algorithme RC4 avec une clé fixe pour déchiffrer la configuration et chiffrer les communications [5, 7, 8, 9, 11, 12] ;
- Mécanisme similaire de mise à jour de la configuration dans un fichier chiffré [5, 11] ;
- Similarités fonctionnelles dans l'architecture globale des implants : utilisation de threads pour paralléliser les commandes et utilisation d'évènements pour la synchronisation [5, 8] ;
- Similarités dans les protocoles de communication entre Mélofée, CrowDoor et RatelS [5, 8, 12] ;
- Mécanisme de gestion des modules par application d'un masque de bits sur l'ID de commande et liste chaînée [5, 12] ;
- Le nom d'export utilisé pour le chargement des modules est très similaire : xmain pour Mélofée, fmain pour RatelS et CrowDoor [5, 8, 11, 12] ;
- Exposition d'une interface à chaque module (PluginInterface vs PlgInterface) [5].
Par ailleurs, comme le montre le tableau suivant, les noms de classes utilisés dans les modules de CrowDoor sont identiques :
Identifiant CrowDoor | Identifiant Mélofée | Nom de classe utilisée dans les modules CrowDoor |
0x60000 | 0x2000 | CShell |
0x30000 | 0x3000 | CFile |
0x20000 | 0x4000 | CCmd |
Avec un niveau de confiance élevée, nous estimons que Mélofée est très probablement lié à ces différentes familles de codes malveillants, et est potentiellement développé par les mêmes équipes.
Par ailleurs, ces similarités montrent un probable partage d'outils entre différents groupes d'attaquants, ce qui est déjà évoqué par plusieurs publications étudiant ces implants [5, 7, 8, 9, 10, 11, 12].
Détection via les firewalls Stormshield
Au sein de nos firewalls Stormshield Network Security (SNS), plusieurs signatures dédiées à la détection de l'activité Mélofée sont déjà en place :
- ssl:server:certificate.107 : signature permettant de détecter l'utilisation de certificats utilisés par Mélofée ;
- tcp:client:port.68 : signature détectant l'envoi d'un paquet d'enregistrement par un implant Mélofée à un serveur C2.
Selon le niveau d'IDS/IPS configuré, les firewalls SNS lèveront des alarmes voire bloqueront les paquets que ces signatures permettront d'identifier.
Sur l'interface de votre SNS, vous pourrez retrouver les alarmes levées dans la partie Monitoring - Logs/Journaux d'audit - Alarmes [14].
Conclusion
L'analyse des nouveaux échantillons de Mélofée montre que cette famille d'implants est toujours active et en évolution continue, près de trois ans après sa découverte.
Les évolutions majeures identifiées, telle que la modularisation de fonctions historiquement intégrées à l'implant et l'ajout de commandes permettant de reconfigurer à distance l'infrastructure C2 montrent une maturation de l'outillage utilisé par les attaquants.
Par ailleurs, les similarités structurelles du code soutiennent l'hypothèse d'un partage de code entre plusieurs groupes d'attaquants probablement liés à des intérêts étatiques chinois , ce qui complexifie la tâche des défenseurs et brouille l'attribution basée uniquement sur les outils.
Références
- [1] ExaTrack, Mélofée: a new alien malware in the Panda's toolset targeting Linux hosts, March 28, 2023 - https://blog.exatrack.com/melofee/
- [2] Reptile rootkit - https://github.com/R3x/linux-rootkits/blob/main/Reptile/kernel/main.c
- [3] AhnLab ASEC, Reptile Malware Targeting Linux Systems, July 20, 2023 - https://asec.ahnlab.com/en/55785/
- [4] XLab (Qianxin), New Zero-Detection Variant of Melofee Backdoor from Winnti Strikes RHEL 7.9, November 12, 2024 - https://blog.xlab.qianxin.com/analysis_of_new_melofee_variant_en/
- [5] ESET Research, You will always remember this as the day you finally caught FamousSparrow, March 26, 2025 - https://www.welivesecurity.com/en/eset-research/you-will-always-remember-this-as-the-day-you-finally-caught-famoussparrow/
- [6] HuntIO , Tracking ShadowPad Infrastructure Via Non-Standard Certificates, Feb 9, 2024 - https://hunt.io/blog/tracking-shadowpad-infrastructure-via-non-standard-certificates
- [7] Cisco Talos, UAT-9244 targets South American telecommunication providers with three new malware implants, March 5, 2026 - https://blog.talosintelligence.com/uat-9244/
- [8] Cyber Defense Institute, Inc/TrendMicro, The Secret Life of RATs: connecting the dots by dissecting multiple backdoors, 2024 - https://jsac.jpcert.or.jp/archive/2024/pdf/JSAC2024_1_7_hara_nakajima_kawakami_en.pdf
- [9] ITOCHU Cyber & Intelligence Inc, Sequel: Gifts from Tropical Pirates - Who is the Sender? Look for the Attacker Group, 2023 - https://blog-en.itochuci.co.jp/entry/2023/10/06/173200
- [10] Daniel Lunghi , Leon M Chang, Trend Micro, The Rise of Collaborative Tactics Among China-aligned Cyber Espionage Campaigns, October 22nd, 2025 - https://www.trendaisecurity.com/en-us/resources-insights/trendai-security-blog/premier-pass-as-a-service
- [11] Yi-Chin Chuang, Yu-Tung Chang, Team T5, Unveiling TeleBoyi: Chinese APT Group Targeting Critical Infrastructure Worldwide, 2024 - https://jsac.jpcert.or.jp/archive/2024/pdf/JSAC2024_1_8_yi-chin_yu-tung_en.pdf
- [12] Yoshihiro Ishikawa, Takuma Matsumoto, LAC Co.,Ltd., New Modular Malware RatelS: Shades of PlugX - https://www.botconf.eu/botconf-presentation-or-article/new-modular-malware-ratels-shades-of-plugx/
- [13] General Purpose Hash Function Algorithms - https://www.partow.net/programming/hashfunctions/#JSHashFunction
- [14] Stormshield, Manuel Utilisateur SNS v4 - Logs-List of Views, 2026 - https://documentation.stormshield.eu/SNS/v4/fr/Content/User_Configuration_Manual_SNS_v4/Audit_Logs/Logs-List_of_Views.htm
- [15] APT41, MITRE ATT&CK® - https://attack.mitre.org/groups/G0096/
Annexes
Mapping des techniques observées (MITRE ATT&CK)

IOCs
Type | Usage | Valeur | Description and remarque |
Implants | |||
HASH | Backdoor | 8255d5a423ce79c69e42685cbf8e708b4239650c01b2898a7efe856582bb3aaf | Implant Linux |
HASH | Backdoor | dd081c130d7c3a3c18e06a26300dcfd65ee70e6b23b729edb54cb0f0a5829df9 | Implant Linux |
HASH | Backdoor | 50daadd49b8df4f0190d0badfde89f8e6a6e61af664ef1444984028a005f40d8 | Implant Linux |
HASH | Backdoor | 4400096e8b39cb2641abec17c6dddad845ed6415e79d60adc2af1dcbd2837c59 | Implant Linux (ancienne version) |
Rootkits | |||
HASH | Rootkit | aa2fd252a6f5a09b8d8422fbd1037febefe2aa99317e3c3973889384a80e29b7 | Rootkit embarqué au sein de l'implant "50daadd49b8df4f0190d0badfde89f8e6a6e61af664ef1444984028a005f40d8" |
HASH | Rootkit | 6678216ace0ff224d6a5ae6bf1ca29e66fba9fceaa715e27440e85d5bfb06069 | Rootkit embarqué au sein de l'implant "dd081c130d7c3a3c18e06a26300dcfd65ee70e6b23b729edb54cb0f0a5829df9" |
Modules | |||
HASH | Module | 129349a221e6efcc9a047efdfd81197f796fcf38877344f17f85651b21e33427 | Module d’exécution de commandes à distance |
HASH | Module | 9d01724193d9570a6c75bbcbb171d29df290207007d004cf75d133dd9aa475f4 | Module de gestion des fichiers et des répertoires |
HASH | Module | cbce7dc8649b37c5db411dfee3a74e8cace2b48fdc8350bfa5b4846c5d9ed2ae | Module pour le Shell interactif |
Infrastructure Cluster "Symantec" | |||
Domaine | C2 | windefender[.]net:443 | Associé à l'implant "50daadd49b8df4f0190d0badfde89f8e6a6e61af664ef1444984028a005f40d8" |
Domaine | C2 | www[.]windefender[.]net:443 | |
IP | C2 | 103[.]215[.]216[.]117:443 | Associé à l'implant "8255d5a423ce79c69e42685cbf8e708b4239650c01b2898a7efe856582bb3aaf" |
IP | C2 | 89[.]44[.]198[.]107:443 | |
IP | C2 | 92.38.169[.]152 | Résolution DNS du domaine windefender[.]net |
IP | C2 | 38.54.71[.]107 | Résolution DNS du domaine windefender[.]net (ayant exposé le certificat dbbcb279a1f1a258832174ce63c295c5080de249) |
IP | C2 | 130.94.91[.]53 | Résolution DNS du domaine windefender[.]net (ayant exposé le certificat dbbcb279a1f1a258832174ce63c295c5080de249) |
IP | C2 | 38.54.71[.]56 | Résolution DNS du domaine windefender[.]net (ayant exposé le certificat dbbcb279a1f1a258832174ce63c295c5080de249) |
Domaine | C2 | windowsupdates[.]us:80 | Associé à l'implant "dd081c130d7c3a3c18e06a26300dcfd65ee70e6b23b729edb54cb0f0a5829df9" |
IP | C2 | 45[.]80[.]208[.]232:80 | |
IP | C2 | 185.163.2[.]100 | Probable C2 (ayant exposé le certificat dbbcb279a1f1a258832174ce63c295c5080de249) |
Domaine | C2 | microsoftupdates[.]top | Domaine résolvant vers 185.163.2[.]100 |
IP | C2 | 180.149.44[.]115 | Probable C2 (ayant exposé le certificat dbbcb279a1f1a258832174ce63c295c5080de249) |
Domaine | C2 | windowsupdates[.]us | Domaine résolvant vers 180.149.44[.]115 |
IP | C2 | 103.215.216[.]181 | Probable C2 (ayant exposé le certificat dbbcb279a1f1a258832174ce63c295c5080de249) |
Domaine | C2 | microupdate[.]top | Domaine résolvant vers 103.215.216[.]181 |
IP | C2 | 103.215.216[.]75 | Probable C2 (ayant exposé le certificat dbbcb279a1f1a258832174ce63c295c5080de249) |
IP | C2 | 103.215.216[.]117 | Probable C2 (ayant exposé le certificat dbbcb279a1f1a258832174ce63c295c5080de249) |
IP | C2 | 103.215.216[.]116 | Probable C2 (ayant exposé le certificat dbbcb279a1f1a258832174ce63c295c5080de249) |
IP | C2 | 103.215.216[.]27 | Probable C2 (ayant exposé le certificat dbbcb279a1f1a258832174ce63c295c5080de249) |
Domaine | C2 | microupdate[.]me | Domaine résolvant vers 103.215.216[.]27 |
IP | C2 | 46.246.98[.]131 | Probable C2 (ayant exposé le certificat dbbcb279a1f1a258832174ce63c295c5080de249) |
IP | C2 | 185.163.2[.]34 | Probable C2 (ayant exposé le certificat dbbcb279a1f1a258832174ce63c295c5080de249) |
IP | C2 | 185.163.2[.]79 | Probable C2 (ayant exposé le certificat dbbcb279a1f1a258832174ce63c295c5080de249) |
IP | C2 | 185.163.2[.]81 | Probable C2 (ayant exposé le certificat dbbcb279a1f1a258832174ce63c295c5080de249) |
IP | C2 | 23.95.34[.]184 | Probable C2 (ayant exposé le certificat dbbcb279a1f1a258832174ce63c295c5080de249) |
IP | C2 | 172.86.114[.]201 | Probable C2 (ayant exposé le certificat dbbcb279a1f1a258832174ce63c295c5080de249) |
IP | C2 | 130.94.91[.]165 | Probable C2 (ayant exposé le certificat dbbcb279a1f1a258832174ce63c295c5080de249) |
IP | C2 | 103.87.9[.]148 | Probable C2 (ayant exposé le certificat dbbcb279a1f1a258832174ce63c295c5080de249) |
IP | C2 | 45.67.230[.]185 | Probable C2 (ayant exposé le certificat dbbcb279a1f1a258832174ce63c295c5080de249) |
IP | C2 | 154.205.137[.]88 | Probable C2 (ayant exposé le certificat dbbcb279a1f1a258832174ce63c295c5080de249) |
IP | C2 | 146.71.85[.]33 | Probable C2 (ayant exposé le certificat dbbcb279a1f1a258832174ce63c295c5080de249) |
IP | C2 | 103.215.216[.]162 | Probable C2 (ayant exposé le certificat dbbcb279a1f1a258832174ce63c295c5080de249) |
IP | C2 | 103.215.216[.]61 | Probable C2 (ayant exposé le certificat dbbcb279a1f1a258832174ce63c295c5080de249) |
IP | C2 | 180.149.44[.]43 | Probable C2 (ayant exposé le certificat dbbcb279a1f1a258832174ce63c295c5080de249) |
Infrastructure Cluster "xdevops" | |||
Domaine | C2 | awsclouds.awspull[.]com | Associé à l'implant "4400096e8b39cb2641abec17c6dddad845ed6415e79d60adc2af1dcbd2837c59" |
IP | C2 | 192.3.55[.]220 | Associé à l'implant "4400096e8b39cb2641abec17c6dddad845ed6415e79d60adc2af1dcbd2837c59", ayant résolu le domaine awsclouds.awspull[.]com et ayant exposé le certificat 0c1666b274ddb44dd5c7a11f03c8c041f6bccf0c7dae924626ef9d15b1cc41d5 |
IP | C2 | 38.54.110[.]44 | Probable C2 (ayant exposé le certificat b6df18f66cf4364be2946d6b981e69763aafde68) |
IP | C2 | 45.61.148[.]33 | Probable C2 (ayant exposé le certificat b6df18f66cf4364be2946d6b981e69763aafde68) |
IP | C2 | 2.56.166[.]139 | Probable C2 (ayant exposé le certificat b6df18f66cf4364be2946d6b981e69763aafde68) |
Domaine | C2 | update.wwwubuntu[.]com | Probable C2 (ayant résolu vers plusieurs adresses IP résolu vers 38.54.110[.]44, 45.61.148[.]33, 2.56.166[.]139) |
IP | C2 | 2.56.166[.]84 | Probable C2 (ayant exposé le certificat b6df18f66cf4364be2946d6b981e69763aafde68) |
Domaine | C2 | amzaonaws[.]org | Probable C2 (ayant résolu vers 2.56.166[.]84) |
Fichiers | |||
Path | IOC | /tmp/lock_ax | Mutex utilisé par l'implant |
Path | IOC | /tmp/[ID] | Fichier temporaire utilisé pour stocker les modules (ID étant compris entre 2000 et c000) |
Path | IOC | /etc/systemd/system/vmware.service | Fichier utilisé pour la persistance |
Path | IOC | /tmp/.mpwzlof | Fichier utilisé pour installer la persistance |
Process Name | IOC | [md] | Nom de processus (hors kernel) |
Signatures Yara, Sigma et SNS (Stormshield)
Signatures Yara
rule UNK_APT_MelofeeImplant_2026
{
meta:
description = "Detects Melofee Linux implant"
author = "romain.carette - (Stormshield CTI)"
family = "Melofee"
hashes = "50daadd49b8df4f0190d0badfde89f8e6a6e61af664ef1444984028a005f40d8,dd081c130d7c3a3c18e06a26300dcfd65ee70e6b23b729edb54cb0f0a5829df9,8255d5a423ce79c69e42685cbf8e708b4239650c01b2898a7efe856582bb3aaf"
created = "2026-08-15"
modified = "2026-09-02"
score = 100
tlp = "TLP-CLEAR"
strings:
$sym_xmain = "xmain" ascii
// This functionality allows incoming TCP traffic to be redirected to a local port and is used by Melofee to implement a network redirection mechanism.
$iptables_add = "iptables -t nat -A PREROUTING -p tcp -s %s --dport %d -j REDIRECT --to-port %d" ascii
$iptables_del = "iptables -t nat -D PREROUTING -p tcp -s %s --dport %d -j REDIRECT --to-port %d" ascii
$pevents_src = "pevents.cpp" ascii
$pevents_ns1 = "neosmart::CreateEventx" ascii
$pevents_ns2 = "neosmart::WaitForMultipleEvents" ascii
$code_initmod = {
b9 ?? ?? ?? ??
48 89 da
48 89 c6
bf af 00 00 00
b8 00 00 00 00
e8
}
$code_selfdelete = {
bf ?? ?? ?? ??
e8 ?? ?? ?? ??
89 45 ??
83 7d ?? 00
0f 8e ?? ?? ?? ??
8b 45 ??
48 98
c6 84 05 ?? ?? ?? ?? 00
}
condition:
uint32(0) == 0x464c457f and
3 of them
}
rule UNK_APT_MelofeeImplantLib
{
meta:
description = "Detects plugin libraries (.so) of the Melofee Linux implant family"
author = "romain.carette - Stormshield CTI"
date = "2026-08-24"
malware_family = "Melofee"
hashes = "9d01724193d9570a6c75bbcbb171d29df290207007d004cf75d133dd9aa475f4,cbce7dc8649b37c5db411dfee3a74e8cace2b48fdc8350bfa5b4846c5d9ed2ae,129349a221e6efcc9a047efdfd81197f796fcf38877344f17f85651b21e33427"
created = "2026-08-15"
modified = "2026-09-02"
score = 100
tlp = "TLP-CLEAR"
strings:
// SocketApi network layer
$sock1 = "_ZN9SocketApi7ConnectEiPK8sockaddri" ascii
$sock2 = "_ZN9SocketApi6SocketEiiiRi" ascii
$sock3 = "_ZN9SocketApi6ListenEii" ascii
$sock4 = "_ZN9SocketApi6AcceptEiP8sockaddrPiRi" ascii
$sock5 = "_ZN9SocketApi4SendEiPKviRi" ascii
$sock6 = "_ZN9SocketApi4RecvEiPviRi" ascii
$sock7 = "_ZN9SocketApi4PeekEiPviRi" ascii
$sock8 = "_ZN9SocketApi4BindEiPK8sockaddri" ascii
$sock9 = "_ZN9SocketApi13GetAddrInfo_xEPKcS1_PK8addrinfoPPS2_" ascii
$sock10 = "_ZN9SocketApi18FreeAddrInfoWrap_xEP8addrinfo" ascii
$sock11 = "_ZN9SocketApi11GetsocknameEiP8sockaddrPi" ascii
$sock12 = "_ZN9SocketApi11GetpeernameEiP8sockaddrPi" ascii
$sock13 = "_ZN9SocketApi5CloseEi" ascii
// BaseConn connection wrapper
$conn1 = "_ZN8BaseConn5sendnEPvi" ascii
$conn2 = "_ZN8BaseConn5recvnEPvim" ascii
$conn3 = "_ZN8BaseConn4peekEPviRim" ascii
$conn4 = "_ZTI8BaseConn" ascii
$conn5 = "_ZTV8BaseConn" ascii
// Packet handling + RC4
$pkt1 = "_Z11WritePacketSt10shared_ptrI8BaseConnEP9_PkHeaderSs" ascii
$pkt2 = "_Z10ReadPacketSt10shared_ptrI8BaseConnEP9_PkHeaderRSs" ascii
$rc4_1 = "_Z6re_RC4PhPc" ascii
$rc4_2 = "_Z7re_SboxPhS_" ascii
$rc4_3 = "_Z5RC4_2Pci" ascii
$rc4_4 = "_Z3RC4PciS_" ascii
// Network helpers
$hton1 = "_Z9my_htonllm" ascii
$hton2 = "_Z8my_htonst" ascii
$hton3 = "_Z8my_htonlj" ascii
// Shared internal string utilities
$util1 = "_Z5splitRKSsS0_RSt6vectorISsSaISsEE" ascii
$util2 = "_Z4joinRKSt6vectorISsSaISsEERKSs" ascii
// Plugin entry point symbol
$entry = "xmain" ascii fullword
condition:
uint32(0) == 0x464c457f and // ELF magic
uint16(16) == 3 and // e_type == ET_DYN (shared object)
(
6 of ($sock*)
or 2 of ($conn*)
or 10 of them
or ($entry and 2 of ($sock*, $conn*))
)
}
Signature Sigma
title: Detection of temporary files used by Mélofée for module storage
id: 8e6f2a3c-4b7d-4e1a-9c2f-5d8a1b3e7f90
status: experimental
description: Detects the creation, in /tmp/, of temporary files whose names correspond to a hexadecimal identifier. These files are used to store modules/plugins that will subsequently be loaded via dlopen. The filename corresponds to a hexadecimal identifier ranging from 0x2000 to 0xC000.
references:
- Stormshield CTI Internal Analysis – Mélofée Linux Implant
author: romain.carette - (Stormshield CTI)
date: 2026-08-26
tags:
logsource:
product: linux
category: file_event
detection:
selection:
TargetFilename|re: '^/tmp/[2-9a-cA-C]000$'
condition: selection
falsepositives:
- Legitimate temporary files with randomly generated hexadecimal names (rare but possible)
level: medium