Depuis plusieurs années, le groupe d’espionnage Turla cible divers établissements. Récemment, nous avons retrouvé plusieurs nouvelles versions de Carbon, une porte dérobée de deuxième étape faisant partie de l’arsenal du groupe Turla. L’année dernière, dans le cadre de son rapport décrivant une attaque subie par RUAG, un organisme de défense qui relève du gouvernement suisse, l’équipe d’intervention en cas d’urgence informatique suisse GovCert.ch a effectué une analyse technique de ce maliciel.

Ce billet de blogue souligne les innovations techniques relevées dans les dernières versions de Carbon que nous avons découvertes.

Si on se fie aux différents numéros de version de Carbon dont nous disposons, il est évident que cette porte dérobée est toujours en développement. Selon les versions internes retrouvées dans le code, nous voyons que de nouvelles versions sont produites régulièrement. On sait également que le groupe change d’outils une fois que ces derniers ont été exposés. Ainsi, nous avons remarqué qu’entre deux versions majeures, on change les exclusions mutuelles et les noms des fichiers.

Vecteurs d'infection

Le groupe Turla est reconnu pour son travail rigoureux et divisé en étapes. D’abord, il étudie les systèmes des victimes, puis il déploie ses outils les plus avancés comme Carbon.

Généralement, une attaque de Carbon commence par un utilisateur qui reçoit un courriel de harponnage ou qui visite un site infecté qu’il consulte régulièrement : on appelle cette technique une attaque de point d’eau.

Une fois l’attaque réussie, une porte dérobée de première étape, comme Tavdig,[1] ou Skipper [2] est installée sur le poste de l’utilisateur. La reconnaissance terminée, une porte dérobée de deuxième étape, comme Carbon, s’installe dans les systèmes essentiels.

Analyse technique

Carbon est une porte dérobée avancée que le groupe Turla utilise pour voler des renseignements de cibles qui l’intéressent.

Ce maliciel partage certaines ressemblances avec « Uroburos » [3], un dissimulateur d’activité utilisé par le même groupe. L’élément commun le plus pertinent est la voie de communication. En effet, les deux programmes établissent des canaux de communication entre différents composants de maliciels. Les objets de communication sont mis en œuvre de la même façon, les structures et les tableaux virtuels semblent identiques, à l’exception que Carbon compte moins de canaux de communication. En effet, Carbon pourrait être une version « réduite » d’Uroburos (sans noyau ni code d’exploitation).

Avant de décider d’installer Carbon sur un système, le groupe Turla envoie généralement un outil de reconnaissance (étape 1) à la cible. Cet outil recueille divers renseignements sur l’ordinateur et le réseau de la victime (par exemple, à l’aide de Tavdig ou de Skipper). Si la cible est considérée comme suffisamment intéressante, on lui enverra des maliciels plus avancés (comme Carbon ou Uroburos).

Architecture globale

Le maliciel Carbon est composé des éléments suivants :

  • un programme seringue qui installe les composants et le fichier de configuration de Carbon;
  • un composant qui communique avec le serveur de commande et de contrôle;
  • un orchestrateur qui gère les tâches, les répartit aux autres ordinateurs sur le réseau et insère dans un processus légitime la bibliothèque de liens dynamiques qui communique avec le serveur de commande et de contrôle;
  • un chargeur qui exécute l’orchestrateur.

Datation au Carbon

L’orchestrateur et la bibliothèque versée relèvent de deux versions de développement distinctes.

Grâce aux dates de compilation et aux numéros de versions internes figés dans le code dans les fichiers, on peut déduire le calendrier suivant :

Tableau 1 – Calendrier de développement de Carbon

Nombre del paquete Hash Detección
goodish.weather CA2250A787FAC7C6EEF6158EF48A3B6D52C6BC4B Android/Spy.Banker.HH
goodish.weather A69C9BAD3DB04D106D92FD82EF4503EA012D0DA9 Android/Spy.Banker.HU
follon.weather F533761A3A67C95DC6733B92B838380695ED1E92 Android/Spy.Banker.HW

Fichiers de Carbon

Les fichiers de l’architecture de Carbon changent de nom selon la version, mais leurs noms internes restent toujours les mêmes (dans les métadonnées) :

  • programme seringue : « SERVICE.EXE »
  • chargeur : « SERVICE.DLL » ou « KmSvc.DLL »
  • orchestrateur : « MSIMGHLP.DLL »
  • bibliothèque versée : « MSXIML.DLL »

Chacun de ces fichiers existe en version 32 bits et 64 bits.

Répertoire courant

Carbon crée plusieurs fichiers qui contiennent des journaux, des tâches à exécuter et une configuration qui modifie le comportement du maliciel. Le contenu de la majorité de ces fichiers est chiffré à l’aide de l’algorithme CAST-128 [4].

Un répertoire courant contiendra les fichiers et les dossiers associés à Carbon. Ce répertoire est choisi au hasard parmi les dossiers se trouvant sous %ProgramFiles%, à l’exception de « WindowsApps ».

Les noms de fichiers sont figés dans le code de l’orchestrateur. Les mêmes noms sont utilisés dans la version 3.7x+. Puisque la bibliothèque injectée accède aux mêmes fichiers que l’orchestrateur, il est encore plus facile d’associer une version de bibliothèque à un orchestrateur.

Arborescence des fichiers de Carbon 3.7x :

\%carbon_working_folder\%   // dossier de base 
├── 0208 // résultats des tâches et fichiers de journaux 
│   ├── C_56743.NLS // contient la liste des fichiers à envoyer au serveur de commande et de contrôle. Ce fichier n’est pas compressé ni chiffré.
├── asmcerts.rs
├── getcerts.rs
├── miniport.dat  // fichier de configuration 
├── msximl.dll    // bibliothèque versée (x32))
├── Nls // contient des tâches (des commandes à exécuter ou un fichier PE) et leurs fichiers de configuration.
│   ├── a67ncodc.ax  // tâches que l’orchestrateur doit exécuter 
│   ├── b9s3coff.ax  // tâches que la bibliothèque versée doit exécuter 
├── System   // dossier de modules d’extension 
│   ├── bootmisc.sdi // inutilisé 
├── qavscr.dat    // journal des erreurs 
├── vndkrmn.dic   // journal 
└── ximarsh.dll   // bibliothèque versée (x64) 

Depuis la version 3.80, tous les noms de fichier ont changé.

Arborescence des fichiers de Carbon 3.8x :

\carbon_working_folder\%   // base folder
├── \%carbon_working_folder\%   // dossier de base
├── 0409  // contient des tâches (des commandes à exécuter ou un fichier PE) et leurs fichiers de configuration. 
│   ├── cifrado.xml    // tâches que la bibliothèque versée doit exécuter
│   ├── encodebase.inf // tâches que l’orchestrateur doit exécuter
├── 1033 // résultats des tâches et fichiers des journaux
│   ├── dsntype.gif // contient la liste des fichiers à envoyer au serveur de commande et de contrôle. Ce fichier n’est pas compressé ni chiffré. 
├── en-US  // dossier de modules d’extension
│   ├── asmlang.jpg // inutilisé
├── fsbootfail.dat  // journal des erreurs
├── mkfieldsec.dll  // bibliothèque versée (x32) 
├── preinsta.jpg    // journal
├── wkstrend.xml    // fichier de configuration
├── xmlrts.png
└── zcerterror.png

Accès aux fichiers

Dans la plupart des cas, lorsque le maliciel accède à un fichier du dossier courant de Carbon, les étapes suivantes se déroulent :

  • une exclusion mutuelle particulière est déclenchée afin d’assurer un accès exclusif;
  • le fichier est déchiffré (CAST-128);
  • une fois les opérations relatives au fichier terminées, le fichier est chiffré à nouveau (CAST-128);
  • l’exclusion mutuelle est délivrée.

Exclusions mutuelles

Dans Carbon 3.7x, les exclusions mutuelles suivantes sont créées par l’orchestrateur :

  • « Global\\MSCTF.Shared.MUTEX.ZRX » (utilisé pour assurer un accès exclusif à « vndkrmn.dic »)
  • « Global\\DBWindowsBase » (utilisé pour assurer un accès exclusif à « C_56743.NLS »)
  • « Global\\IEFrame.LockDefaultBrowser » (utilisé pour assurer un accès exclusif à « b9s3coss.ax »)
  • « Global\\WinSta0_DesktopSessionMut » (utilisé pour assurer un accès exclusif à « a67ncodc.ax »)
  • « Global\{5FA3BC02-920F-D42A-68BC-04F2A75BE158} » (utilisé pour assurer un accès exclusif aux nouveaux fichiers créés dans le dossier « Nls »)
  • « Global\\SENS.LockStarterCacheResource » (utilisé pour assurer un accès exclusif à « miniport.dat »)
  • « Global\\ShimSharedMemoryLock » (utilisé pour assurer un accès exclusif à « asmcerts.rs »)

Dans les versions 3.8x, les noms des fichiers et des exclusions mutuelles ont changé :

  • « Global\\Stack.Trace.Multi.TOS » (utilisé pour assurer un accès exclusif à « preinsta.jpg »)
  • « Global\\TrackFirleSystemIntegrity » (utilisé pour assurer un accès exclusif à « dsntype.gif »)
  • « Global\\BitswapNormalOps » (utilisé pour assurer un accès exclusif à « cifrado.xml »)
  • « Global\\VB_crypto_library_backend » (utilisé pour assurer un accès exclusif à « encodebase.inf »)
  • « Global\{E41B9AF4-B4E1-063B-7352-4AB6E8F355C7} » (utilisé pour assurer un accès exclusif aux nouveaux fichiers créés dans le dossier « 0409 »)
  • « Global\\Exchange.Properties.B » (utilisé pour assurer un accès exclusif à « wkstrend.xml »)
  • « Global\\DatabaseTransSecurityLock » (utilisé pour assurer un accès exclusif à « xmlrts.png »)

Ces exclusions mutuelles sont également utilisées dans la bibliothèque de liens dynamiques pour veiller à l’exécution de l’orchestrateur.

Fichier de configuration

Le fichier de configuration détermine le comportement du maliciel. Le format du fichier rappelle celui des fichiers « inf » utilisés par Windows. Il contient entre autres :

  • une valeur « object_id », soit un identifiant universellement unique servant à identifier la victime. Lorsque la valeur n’est pas configurée dans le fichier, le maliciel le génère au hasard;
  • une liste de processus dans lesquels on a versé le code (iproc);
  • la fréquence et le moment de l’exécution des tâches, des journaux de sauvegarde et de la connexion au serveur de commande et de contrôle ([TIME]);
  • les adresses IP des autres ordinateurs dans le réseau ([CW_LOCAL]);
  • les adresses de serveur de commande et de contrôle ([CW_INET]);
  • les canaux de communication nommés utilisés pour communiquer avec la bibliothèque versée et avec les autres ordinateurs ([TRANSPORT]).

Ce fichier pourrait être mis à jour ultérieurement. En effet, dans la bibliothèque de communication, certaines clés sont utilisées pour chiffrer et déchiffrer les données. Ces clés se trouvent dans une section [CRYPTO] du fichier de configuration qui n’existe pas au moment où ce fichier est versé à partir des ressources du chargeur.

Fichier de configuration de Carbon 3.77 :

[NAME]
object_id=
iproc = iexplore.exe,outlook.exe,msimn.exe,firefox.exe,opera.exe,chrome.exe
ex = #,netscape.exe,mozilla.exe,adobeupdater.exe,chrome.exe
[TIME]
user_winmin = 1800000
user_winmax = 3600000
sys_winmin = 3600000
sys_winmax = 3700000
task_min = 20000
task_max = 30000
checkmin = 60000
checkmax = 70000
logmin =  60000
logmax = 120000
lastconnect=111
timestop=
active_con = 900000
time2task=3600000
[CW_LOCAL]
quantity = 0
[CW_INET]
quantity = 3
address1 = doctorshand.org:80:/wp-content/about/
address2 = www.lasac.eu:80:/credit_payment/url/
address3 = www.shoppingexpert.it:80:/wp-content/gallery/
[TRANSPORT]
system_pipe = comnap
spstatus = yes
adaptable = no
[DHCP]
server = 135
[LOG]
logperiod = 7200
[WORKDATA]
run_task=
run_task_system=

Fichier de journal

L’architecture de Carbon comprend un fichier de journal qui enregistre les actions effectuées par le maliciel et les renseignements sur le système qui pourraient être utiles pour l’opérateur du programme malveillant (par exemple, si un outil d’analyse comme WireShark est en cours d’exécution sur le poste).

Le format du journal n’a pas changé depuis la version 3.71 :

  • Date|Heure|ID d’objet|Source|Message
exemple
[LOG]
start=1
20/02/17|12:48:24|8hTdJtUBB57ieReZAOSgUYacts|s|OPER|New object ID generated '8hTdJtUBB57ieReZAOSgUYacts'|
20/02/17|12:48:24|8hTdJtUBB57ieReZAOSgUYacts|s|ST|3/81|0|
20/02/17|12:48:24|8hTdJtUBB57ieReZAOSgUYacts|s|START OK

Ce fichier est constamment sauvegardé et envoyé au serveur de commande et de contrôle.

Programme seringue :

Le programme seringue est le seul fichier exécutable qui n’est pas une bibliothèque de liens dynamiques. Il s’agit du premier fichier PE à s’exécuter : il sert à extraire les autres composants de ses ressources.

Les fichiers PE qui servent à charger les principaux composants sont extraits dans le répertoire du système Windows, tandis que l’orchestrateur, la bibliothèque servant à communiquer avec le serveur de commande et de contrôle et le fichier de configuration sont extraits dans le répertoire courant de Carbon.

Une nouvelle section est ajoutée à un fichier « .inf » choisi au hasard sous %SystemRoot%\INF. Le nom de la section est l’immatriculation du volume de l’ordinateur infecté et une valeur « root » est créée dans le répertoire courant de Carbon sélectionné.

Exemple :

[5049654F] root="C:\Program Files\Windows Portable Devices"Chargeur

Cette partie du composant sert à charger l’orchestrateur.

Un serveur, qui assure la persistance de Carbon, est créé. Selon la version du système d’exploitation de l’ordinateur infecté, il peut s’appeler « srservice », « ipvpn » ou « hkmsvc ».

On peut trouver le répertoire courant de Carbon en parcourant le dossier « %windir%\inf » et en cherchant le fichier qui contient le chemin d’accès de base de Carbon.

En dernier lieu, la fonction « ModuleStart » (dans la version 3.71) ou « ModStart » (depuis la version 3.77) de l’orchestrateur (situé dans le dossier de base de Carbon) est lancée.

Orchestrateur

L’orchestrateur est la composante principale de l’architecture de Carbon. Il sert principalement à insérer un code dans un processus qui communique légitimement sur Internet à répartir les tâches de la bibliothèque versée à d’autres ordinateurs du même réseau à l’aide de canaux de communication nommés ou par TCP.

Le maliciel crée sept fils d’exécution. Puisque chacun de ces fils a un rôle précis, il est facile de relever les caractéristiques de Carbon :

Extraction de la configuration

Étant donné que le maliciel peut mettre à jour le fichier de configuration, certains attributs, comme le serveur de commande et de contrôle, sont surveillés toutes les 10 minutes.

Vérification périodique du dossier de stockage de Carbon

Un dossier de stockage se trouve dans le répertoire courant de Carbon. Ce dossier contient certains fichiers téléchargés depuis le serveur de commande et de contrôle (des tâches qui sont des commandes à exécuter ou des fichiers PE, ainsi que les fichiers de configuration associés).

Ce fil s’exécutera de façon continue et vérifiera toutes les deux heures [5] s’il reste assez d’espace disponible dans le dossier. Si l’espace est insuffisant, il inscrira une note dans le fichier de journal.

Exécution des tâches

Au cours du processus de l’orchestrateur, l’exécution des tâches se fait un peu de la même façon que dans la bibliothèque de communication (voir Exécution des tâches sous Bibliothèque de communication).

Contrairement à la bibliothèque de communication, la liste des tâches à exécuter se trouve dans le fichier « encodebase.inf » (pour les versions 3.8x) ou « a67ncode.ax ».

Chaque ligne est écrite de la façon suivante :

  • task_id | task_filepath | task_config_filepath | task_result_filepath | task_log_filepath | [execution_mode | username | password]

Les cinq premiers champs sont obligatoires, tandis que les trois derniers sont facultatifs. Si le champ « execution_mode » comporte une valeur, celle-ci changera la façon dont la tâche sera exécutée.

  • 0 ou 1 : exécution normale
  • 2 : la tâche s’exécute dans le contexte de sécurité d’un utilisateur en particulier (les authentifiants sont recueillis à partir des champs d’utilisateur et de mot de passe)
  • 3 ou 4 : la tâche s’exécute dans le contexte de sécurité de l’utilisateur représenté par le jeton « explorer.exe »

Poste à poste

Comme Uroburos (ou Snake), Carbon peut répartir des tâches à d’autres ordinateurs du même réseau au moyen d’un canal de communication nommé ou par TCP. Ainsi, il est possible d’envoyer et d’exécuter des tâches sur des ordinateurs qui n’ont pas d’accès Internet.

Canaux de communication

Uroburos utilisait diverses voies de communication que l’on peut catégoriser comme suit :

  • type 1 : TCP
  • type 2 : enc, np, reliable, frag, m2b, m2d
  • type 3 : t2m
  • type 4 : UDP, doms, domc

Carbon utilise un nombre restreint de canaux de communication :

  • type 1 : TCP, b2m
  • type 2 : np, frag, m2b

Les données envoyées aux autres postes sont généralement fragmentées et transportées par TCP ou au moyen d’un canal de communication nommé. Par exemple, si des données fragmentées sont transmises d’un ordinateur à l’autre à l’aide d’un canal nommé, un objet « frag.np » est configuré. Dans ce cas, le constructeur « frag » de classe mère sera exécuté, puis le constructeur de sous-classe « np ».

Chaque objet repose sur une structure composée de plusieurs gestionnaires : initialisation de la communication, connexion (à un canal de communication ou à une adresse IP), lecture de données, envoi de données, etc.

Acheminement d’une tâche vers un autre ordinateur

Diverses actions se déroulent afin d’envoyer des données d’un ordinateur à l’autre :

  • un canal de communication est créé (objet frag.np ou frag.tcp), accompagné d’un nom de canal ou d’une adresse IP unique;
  • des options relatives à la transmission de l’objet sont disponibles (par exemple : la taille du fragment, des renseignements sur le poste, etc.);
  • une connexion est établie avec le poste;
  • un processus d’authentification se déroule entre l’hôte et l’autre poste :
    • une liaison a lieu lorsque l’hôte envoie la valeur « magic » « A110EAD1EAF5FA11 » et s’attend à recevoir « C001DA42DEAD2DA4 » de l’autre poste,
    • une commande « WHO » est envoyée à l’autre poste. Elle envoie un identifiant universellement unique à la victime et s’attend à recevoir le même;
  • si l’authentification réussit, l’hôte envoie des données à l’ordinateur ciblé.

Toutes ces communications sont chiffrées à l’aide de l’algorithme CAST-128.

À noter que cette fonction de communication de poste à poste est aussi présente dans la bibliothèque de liens dynamiques de communication.

Modules d’extension

Le maliciel prend également en charge des modules d’extension supplémentaires qui y ajoutent des fonctions.

Dans le fichier de configuration, on trouve une section nommée « PLUGINS ». Il n’existe peut-être pas lorsque le chargeur verse le fichier de configuration à partir de ses ressources, mais le maliciel peut mettre le fichier à jour. La section « PLUGINS » contient une ligne écrite comme suit :

  • %plugin_name%=%enabled%|%mode%[:%username%:%password%]|%file_path%

%file_path% peut soit être le chemin vers un fichier PE ou vers un fichier contenant une ligne de commande à exécuter. %enabled% est une chaîne qui indique si le module d’extension doit être exécuté. Si c’est le cas, sa valeur est « enabled ».

L’attribut %mode% dicte le contexte dans lequel il faut exécuter le fichier PE ou la ligne de commande. Sa valeur peut être :

  • 1 = exécution à l’aide du droit d’accès dans le contexte du processus actuel par la fonction CreateProcess();
  • 2 = exécution en tant qu’utilisateur désigné dans la configuration (attributs :%username%:%password%), le jeton de cet utilisateur est récupéré à l’aide de la fonction LogonUserAs();
  • 3 = la tâche s’exécute dans le contexte de sécurité de l’utilisateur représenté par le jeton « explorer.exe » (le jeton du processus « explorer.exe » est copié et transmis à l’aide de la fonction CreateProcessAsUser());
  • 4 = identique à la valeur 3, à l’exception que les variables d’environnement de l’utilisateur représenté par le jeton « explorer.exe » sont récupérées, puis transmises à la fonction CreateProcessAsUser().

S’il s’agit d’un fichier PE :

  • le fichier est chargé dans la mémoire du processus du maliciel;
  • le maliciel analyse le module pour déterminer s’il s’agit d’une bibliothèque de liens dynamiques;
  • si le module est une bibliothèque de liens dynamiques qui exporte une fonction « ModStart » (versions 3.77 et ultérieures) ou « ModuleStart » (versions antérieures de Carbon), un nouveau fil est créé afin d’exécuter cette fonction.
  • si le module n’est pas une bibliothèque de liens dynamiques, mais plutôt un fichier PE valide, il est exécuté depuis le point d’entrée.

Insertion de la bibliothèque de communication dans les processus éloignés

La bibliothèque utilisée pour communiquer avec le serveur de commande et de contrôle est insérée dans les processus éloignés. Pour savoir où verser cette bibliothèque de liens dynamiques, le maliciel analyse le fichier de configuration. La section « [NAME] » contient un champ appelé « iproc » qui contient une liste de processus qui peuvent légitimement communiquer sur Internet.

Exemple :

[NAME]

[NAME] iproc = iexplore.exe,outlook.exe,msimn.exe,firefox.exe,opera.exe,chrome.exeL’insertion du processus se déroule de façon très traditionnelle :

  • les fonctions « CreateToolHelp32Snapshot », « Module32FirstW » et « Module32NextW » sont activées pour récupérer l’adresse de base du module « kernel32.dll »;
  • L’EAT de module est analysé afin de récupérer l’adresse de la fonction « LoadLibraryW »;
  • le privilège « SeDebugPrivilege » est activé pour le processus courant;
  • de l’espace de mémoire est libéré dans le processus éloigné, afin d’y inscrire le chemin d’accès de la bibliothèque;
  • la fonction NtCreateThreadEx ou CreateRemoteThread (s’il n’est pas possible de récupérer l’adresse de la première fonction) est appelée afin d’exécuter la fonction LoadLibraryW, qui permettra de charger la bibliothèque de liens dynamiques dans la mémoire du processus éloigné*.

Bibliothèque de communication

L’analyse suivante est fondée sur la version 4.x de msximl. Il se peut que cette composante ait changé dans les dernières versions.

Extraction de la configuration

Outre le code se trouvant dans le fil « Configuration fetching » de l’orchestrateur (qui est semblable), le maliciel récupère un champ nommé « sethttp1 » de la section [TRANSPORT].

Si cette valeur est réglée, les connexions futures se feront à l’aide du protocole HTTP 1.1.

Exécution des tâches

Le maliciel récupère les tâches à partir du serveur de commande et de contrôle.

Les tâches que la bibliothèque de communication doit exécuter se trouvent dans le fichier « b9s3coff.ax » (dans les versions 3.7x) ou « cifrado.xml » (dans les versions 3.8x).

Chaque ligne est écrite de la façon suivante :

  • task_id | task_filepath | task_config_filepath | task_result_filepath | task_log_filepath

Le logiciel déchiffre le fichier de tâche et sa configuration (CAST-128), puis il exécute la tâche. Certaines options sont récupérées à partir du fichier de configuration de Carbon : « time2task » règle un délai d’exécution de tâche (1 heure, par défaut), tandis que « task_min » et « task_max » servent à configurer un délai déterminé au hasard entre l’exécution des tâches dans la liste de tâches (ce délai sera établi entre les valeurs données pour « task_min » et « task_max »). Ces paramètres proviennent de la section [TIME].

Si la tâche est un fichier de bibliothèque de liens dynamiques valide, elle est chargée dans la mémoire du processus en cours et un nouveau fil est créé afin d’exécuter la fonction « start ». Sinon, il s’agit probablement d’une commande à exécuter. Dans ce cas, une analyse du fichier de configuration a lieu. Au même titre que le fichier de configuration de Carbon, le fichier de configuration des tâches est conçu comme un fichier Windows « inf » et devrait contenir une section [CONFIG] comportant les paramètres suivants :

  • [CONFIG]
    • NAME (« cmd.exe » par défaut)
    • ARG
    • RESULT (« stdout » par défaut)
    • COMPRESSION (« yes » par défaut)
    • DELETE (« no » par défaut)

La commande et ses arguments sont exécutés à l’aide de la fonction CreateProcess() et les résultats sont enregistrés dans le fichier %task_result_filepath% si l’option RESULT n’est pas réglée à « stdout ». Aussi, les erreurs ou les renseignements supplémentaires sont enregistrés dans le fichier de journal de la tâche.

Si l’option RESULT n’est pas réglée à « stdout » :

  • le fichier de tâche produit est supprimé et le résultat de la tâche est inscrit dans le fichier de tâche de journal;
  • la ligne « task_id | “1” | task_log_filepath | object_id » est ajoutée à la fin du fichier « C_56743.NLS » (versions 3.7x) ou « dsntype.gif » (versions 3.8x).

Sinon :

  • le résultat de la tâche est inscrit dans le fichier de résultat de la tâche et les erreurs ou les renseignements supplémentaires dans le fichier de journal de la tâche.
  • la ligne « task_id | “2” | task_log_filepath | task_result_filepath | object_id » (versions 3.7x) ou « dsntype.gif » (versions 3.8x).

Dans les deux cas, la ligne inscrite dans le fichier « C_56743.NLS » est également ajoutée dans le champ « run_task » du fichier de configuration de Carbon. Il pourrait s’agir d’une façon pour les auteurs du maliciel de savoir quelle est la dernière tâche exécutée avant l’envoi du fichier de configuration au serveur de commande et de contrôle (voir Sauvegarde du fichier de configuration).

Actualisation du fichier de journal

Le fichier est sauvegardé et envoyé au serveur de commande et de contrôle de façon périodique (par défaut, cette opération a lieu toutes les deux heures).

Comme la sauvegarde de la mise à jour, cette action a seulement lieu à des moments précis de la rotation.
En effet, l’actualisation du fichier de journal se fait seulement lorsque l’heure locale se trouve dans une plage définie dans le fichier de configuration.

Les champs « wh_min » et « wh_max » sont récupérés à partir de la section [TIME] du fichier de configuration (par défaut : 8 et 20). Le fil exécutera le code seulement si l’heure se situe entre les valeurs %wh_min% et %wh_max%.

Si le champ « timestop » de la section [TIME] (qui ressemble à ceci : « wDay:wMonth:wYear:wHour:wMinute) contient une valeur, le fil exécutera seulement le code après le moment indiqué.

Les attributs « lastsend » et « logperiod » de la section [LOG] servent à désigner un délai de sauvegarde et d’envoi du journal au serveur de commande et de contrôle (toutes les deux heures, par défaut).

Un fichier temporaire qui comporte un nom généré au hasard commençant par « ~D » est créé dans le fichier « 208 » (versions 3.7x) ou « 1033 » (versions 3.8x). Dans ce nouveau fichier, on trouve le contenu copié du fichier de journal. Ce fichier est ensuite compressé par Bzip2, puis chiffré (CAST-128).

Une nouvelle ligne se trouve à la fin du fichier « C_56743.NLS » (versions 3.7x) ou « dsntype.gif » (versions 3.8x) :

  • « 10|1|%s|%s »
    • Premier champ : un identifiant qui indique que le fichier est un fichier de journal
    • Deuxième champ : 1 (fichier à envoyer au serveur de commande et de contrôle)
    • Troisième champ : le chemin d’accès au fichier temporaire
    • Quatrième champ : l’identifiant universellement unique de la victime

Finalement, l’heure est inscrite dans l’attribut « lastsend » et le fichier de journal original est supprimé.

Communication avec le serveur de commande et de contrôle.

Le code de ce fil sert à récupérer de nouvelles tâches du serveur de commande et de contrôle, à envoyer de nouveaux fichiers aux serveurs (les fichiers répertoriés dans le fichier « C_56743.NLS » ou « dsntype.gif ») et à envoyer les nouvelles tâches à l’orchestrateur.

Première requête

Une adresse de serveur de commande et de contrôle est choisie au hasard parmi celles qui se trouvent dans la section « CW_INET ». Si le port et le chemin d’accès à la ressource HTTP ne sont pas mentionnés, les sélections par défaut seront le port 80 et « /javascript/view.php ».

Un agent utilisateur est configuré comme suit :

  • le maliciel récupère la version d’Internet Explorer à l’aide de la clé de registre : « HKLM\Software\Microsoft\Internet Explorer\Version », puis elle la concatène à la chaîne « Mozilla/4.0 (compatible; MSIE %d.0; »
    • Exemple : « Mozilla/4.0 (compatible; MSIE 8.0.6001.18702.0; »;
  • le logiciel concatène la chaîne précédente aux valeurs de version majeure ou mineure du système d’exploitation (à l’aide de la fonction GetVersionExA())
    • « Mozilla/4.0 (compatible; MSIE 8.0.6001.18702.0; Windows NT 5.1; Trident/4.0 »
  • il énumère les clés de valeurs dans « HKLM\Software\Microsoft\Windows\CurrentVersion\Internet Settings\5.0\User Agent\Post Platform », concatène chaque valeur à la chaîne précédente, puis ajoute une parenthèse fermante.
    • Exemple : « Mozilla/4.0 (compatible; MSIE 8.0.6001.18702.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729; .NET4.0C; .NET4.0E; Media Center PC 6.0; SLCC2) »

La valeur « trans_timemax » de la section [TIME] est récupérée. Elle sert à régler le délai des requêtes sur Internet (à l’aide de la fonction InternetSetOption()). Par défaut, sa valeur est de 10 minutes.

Pour vérifier si l’hôte est actif, le maliciel lance une première requête GET sur la page racine du serveur de commande et de contrôle. Si aucune analyse de paquet n’est en cours dans le système, le logiciel lance une nouvelle requête au serveur de commande et de contrôle pour vérifier si de nouvelles tâches sont disponibles. Un témoin « PHPSESSID  », dont la valeur correspond à l’identifiant universellement unique de la victime, est ajouté à la requête. Un en-tête nommé « Referer » est également ajouté et configuré dans l’URL du serveur de commande et de contrôle.

La réponse à laquelle le maliciel s’attend à recevoir de sa requête GET ressemble à ceci :

  • <input name=”%name%” value=”%data_in_b64%”>

Si le champ « value » contient une valeur, une nouvelle tâche est disponible.

Envoi des données au serveur

Si le fichier « C_56743.NLS » ou « dsntype.gif » n’est pas vide, il faut envoyer des données au serveur de commande et de contrôle. Le fichier est analysé et la dernière ligne est récupérée. Il contient des détails sur les données à envoyer. Un grand objet binaire de données et chacun des champs suivants sont chiffrés en CAST-128 :

  • id | val | tmp_filesize | tmp_content | [OPTIONAL (if val == 2) tmp2_filesize | tmp2_content] | len_object_id | object_id
    • id = le type de données à envoyer au serveur de commande et de contrôle. Les valeurs peuvent être :
      • 10 : sauvegarde de journal,
      • 11 : fichier de configuration,
      • 20 : une clé de chiffrement,
      • autres valeurs : un identifiant est associé à une tâche. Il peut s’agir du résultat d’une tâche ou un journal d’erreur, si l’exécution de la tâche a échoué;
    • val = 1 s’il y a un seul fichier à envoyer, 2 s’il y en a deux;
    • object_id = l’identifiant universellement unique de la victime;

Si le champ « dtc » de la section [CRYPTO] du fichier de configuration est réglé à 0, l’ensemble de ces grands objets binaires est chiffré en base64 et envoyé au serveur de commande et de contrôle à l’aide d’une requête POST.

Sinon, on utilise une autre couche de chiffrement. Dans ce cas, une signature est apposée à grand objet binaire de données, qui est chiffré à l’aide d’une clé triple DES. Puisque cette clé est générée au hasard et que le serveur en a besoin pour déchiffrer les données, elle est chiffrée à l’aide de la clé publique du serveur. La clé de serveur est récupérée à partir du champ « publicc » de la section [CRYPTO] du fichier de configuration.

Ce nouveau grand fichier binaire (encrypted_key | signature_data | encrypted data) est chiffré en base64 et envoyé au serveur de commande et de contrôle au moyen d’une requête POST.

Afin d’éviter d’être détecté en raison de la taille des données envoyées dans une requête, le maliciel peut diviser le grand objet binaire en plusieurs paquets. Une option qui se trouve dans le fichier de configuration (« post_frag » dans la section [TRANSPORT]) définit si le grand objet binaire sera fragmenté ou envoyé en une seule requête POST.

Si cette option est réglée à « yes », ce grand objet binaire est divisé en plusieurs fragments d’une taille particulière. Cette taille est déterminée par un autre champ du fichier de configuration : « post_frag_size ».

La requête comportera un en-tête supplémentaire :

  • « Content-Range: bytes %u-%u/%u; id=%u\r\n”, i, i+(fragment_size-1), data_size, task_id »

Si l’option http11 est configurée, un autre en-tête est également ajouté :

  • « Expect: 100-continue\r\n »

Chaque fois qu’un fragment est envoyé, la taille des fragments et une estampille temporelle sont inscrits dans les champs « post_frag_size » et « pfslastset » du fichier de configuration (section [CW_INET_RESULTS]).

Acquisition de nouvelles tâches

De nouvelles tâches sont récupérées du serveur de commande et de contrôle en analysant la page html. Le maliciel recherche la balise html <input> dans la page, où se trouvera un attribut « value » contenant un grand objet binaire chiffré en base64. Une fois décodé, le grand objet binaire contient ce qui suit :

  • un bloc de 128 octets qui contient une structure « PUBLICKEYSTRUC » suivie d’une clé de chiffrement (probablement une clé triple DES);
  • des données de signature (128 octets) servant à vérifier l’intégrité du prochain bloc;
  • un bloc de données chiffrées qui contient la tâche.

Le maliciel utilise une clé RSA privée (récupérée depuis le champ « keypair » de la section [CRYPTO] du fichier de configuration) afin de déchiffrer le premier bloc, puis utilise la clé nouvellement déchiffrée afin de déchiffrer le troisième bloc. Ce bloc de données pourrait être :

  • une tâche à exécuter [6]
    • les données sont déchiffrées et stockées dans quelques fichiers temporaires, la tâche (une commande ou un fichier PE) et un fichier de configuration dans le dossier « Nls ». Aussi, les fichiers générés (le fichier qui contient les résultats des tâches et le fichier de journal) sont enregistrés dans le dossier « 0208 » (ou respectivement « 0409 » et « 1033 » pour les versions 3.8x)
    • task_id | task_filepath | task_config_filepath | task_result_filepath | task_log_filepath
    • cette ligne est ajoutée au début du fichier « b9s3coff.ax » (cifrado.xml dans les versions 3.8x)
  • une tâche que l’orchestrateur devra exécuter [7]
    • les données sont décodées et stockées dans quelques fichiers temporaires (la tâche, sa configuration, etc.) dans les dossiers « Nls » et « 0208 » (ou « 0409 » et « 1033 » dans les versions 3.8x);
    • selon le contenu des données, une des lignes suivantes sera ajoutée au début du fichier « a67ncode.ax » (encodebase.info pour dans les versions 3.8x) :
      • task_id | task_filepath | task_config_filepath | task_result_filepath | task_log_filepath
      • task_id | task_filepath | task_config_filepath | task_result_filepath | task_log_filepath | execution_mode | username | password
      • task_id | task_filepath | task_config_filepath | task_result_filepath | task_log_filepath | execution_mode
    • une nouvelle clé de serveur publique RSA
      • dans ce cas, la nouvelle clé chiffrée en base64 est inscrite dans le fichier de configuration (dans le champ « publicc »);
    • les données à envoyer à une instance de Carbon s’exécutant sur un autre ordinateur dans le même réseau
      • ces données peuvent contenir une adresse IP et un port particuliers, un canal de communication seulement ou un canal de communication avec un nom d’utilisateur et un mot de passe.

Vérification de la connexion Internet

Toutes les heures, le maliciel vérifie la connexion Internet. La première vérification se fait à l’aide de la fonction InternetAttemptConnect(). Si la vérification réussit, un autre test a lieu en lançant des requêtes HTTP GET vers les sites Web suivants :

  • google.com
  • yahoo.com
  • bing.com
  • microsoft.com
  • microsoft.com
  • com

En cas de perte de la connexion Internet, un événement avise les autres fils.

Sauvegarde du fichier de configuration

À l’instar du fichier de journal, le fichier de configuration est également sauvegardé et envoyé au serveur de commande et de contrôle périodiquement. Le fil exécute le code durant une plage horaire définie (entre 8 h et 20 h par défaut) [8].

La valeur « configlastsend » est récupérée à partir de la section [TIME] du fichier de configuration. Si le fichier de configuration a été envoyé il y a plus d’un mois, il est copié dans un fichier temporaire qui comporte un nom choisi au hasard commençant par « ~D » dans le fichier « 208 » (versions 3.7x) ou « 1033 » (versions 3.8x). Le fichier est ensuite chiffré à l’aide de l’algorithme CAST-128.

Afin d’envoyer au fil qui communique avec le serveur de commande et de contrôle l’information indiquant qu’un nouveau fichier est prêt à être envoyé au serveur, le maliciel ajoute la ligne suivante au fichier « C_56743.NLS » (versions 3.7x) ou « dsntype.gif » (pour les versions 3.8x) :

  • « 11|1|%s|%s »
    • Premier champ : un identifiant qui indique que le fichier est un fichier de configuration
    • Deuxième champ : 1 (fichier à envoyer au serveur de commande et de contrôle)
    • Troisième champ : le chemin d’accès au fichier temporaire
    • Quatrième champ : l’identifiant universellement unique de la victime

Finalement, l’heure est inscrite dans l’attribut « configlastsend ».

Autres remarques

Exécution de fonctions d’API

L’adresse de base des modules d’intérêt est récupérée en analysant le fichier PEB ou (si les modules ne sont pas chargés dans la mémoire du processus) en chargeant les fichiers nécessaires dans la mémoire et en analysant leurs en-têtes.

Une fois les adresses de base récupérées, le maliciel analyse de nouveau le fichier PEB et vérifie le champ « LoadCount » de la structure LDR_DATA_TABLE_ENTRY. Cette valeur sert de compte de référence afin d’assurer un suivi du chargement et du déchargement d’un module.

Si la valeur « LoadCount » est positive, le module EAT est analysé afin d’obtenir l’adresse de fonction nécessaire.

Chiffrement

Les noms du module et de la fonction sont chiffrés (du moins, à partir de la version 3.77; ce n’était pas le cas dans la version 3.71) de façon simple, soit un décalage logique de 1 bit de chaque caractère.

Les noms des processus sont également chiffrés en appliquant une relation OU EXCLUSIF à chaque caractère à l’aide de la clé 0x55 (dans les versions 3.7x, du moins, à partir de 3.77) et à l’aide de la clé 0x77 dans les versions 3.8x.

À quelques exceptions près, chaque fichier du répertoire courant est chiffré à l’aide de l’algorithme en mode à rebouclage par la sortie. Dans les versions 3.71 à 3.81, on utilise la même clé et le même motif d’initialisation :

  • clé = « \x12\x34\x56\x78\x9A\xBC\xDE\xF0\xFE\xFC\xBA\x98\x76\x54\x32\x10 »
  • Motif d’initialisation = « \x12\x34\x56\x78\x9A\xBC\xDE\xF0 »

Vérification de la présence d’une analyse de paquets

Avant de communiquer avec le serveur de commande et de contrôle ou avec d’autres ordinateurs, le maliciel s’assure qu’un des logiciels d’analyse de paquets fonctionne dans le système :

  • exe
  • exe
  • exe
  • exe
  • exe
  • exe
  • exe

Si aucun de ces processus n’est en cours d’exécution, aucune communication n’aura lieu.

Les indicateurs de compromission de Carbon sont aussi disponibles dans le dépôt d’archives GitHub d’ESET : https://github.com/eset/malware-ioc/tree/master/turla

Annexes

Règles de Yara

import “pe”

rule generic_carbon
{
strings:
$s1 = “ModStart”
$s2 = “ModuleStart”
$t1 = “STOP|OK”
$t2 = “STOP|KILL”
condition:
(uint16(0) == 0x5a4d) and (1 of ($s*)) and (1 of ($t*))
}

rule carbon_metadata
{
condition:
(pe.version_info[“InternalName”] contains “SERVICE.EXE” or
pe.version_info[“InternalName”] contains “MSIMGHLP.DLL” or
pe.version_info[“InternalName”] contains “MSXIML.DLL”)
and pe.version_info[“CompanyName”] contains “Microsoft Corporation”
}

Déchiffreur/chiffreur de fichiers de Carbon

carbon_tool.py

#!/usr/bin/env python2

from Crypto.Cipher import CAST
import sys
import argparse

def main():

parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument(“-e”, “–encrypt”, help=”encrypt carbon file”, required=False)
parser.add_argument(“-d”, “–decrypt”, help=”decrypt carbon file”, required=False)

try:
args = parser.parse_args()
except IOError as e:
parser.error(e)
return 0

if len(sys.argv) != 3:
parser.print_help()
return 0

clé = « \x12\x34\x56\x78\x9A\xBC\xDE\xF0\xFE\xFC\xBA\x98\x76\x54\x32\x10 »
iv = “\x12\x34\x56\x78\x9A\xBC\xDE\xF0”

cipher = CAST.new(key, CAST.MODE_OFB, iv)

if args.encrypt:
plaintext = open(args.encrypt, “rb”).read()
while len(plaintext) % 8 != 0:
plaintext += “\x00”
data = cipher.encrypt(plaintext)
open(args.encrypt + “_encrypted”, “wb”).write(data)
else:
ciphertext = open(args.decrypt, “rb”).read()
while len(ciphertext) % 8 != 0:
ciphertext += “\x00”
data = cipher.decrypt(ciphertext)
open(args.decrypt + “_decrypted”, “wb”).write(data)

if __name__ == “__main__”:
main()

Documentation à code source libre

Empreinte de Carbon

Tableau 2 – Hachages d’échantillons de Carbon

Víctima de un DNS Spoofing local Victim of local DNS spoofing
Víctima Victim
Servidor DNS DNS server
Atacante rol de DNS malicioso Attacker role of malicious DNS
Servidor malicioso Malicious server
Acceso a sítio malicioso Accesses malicious website
Consulta por www.ejemplo.com Looks up www.example.com
Respuesta Servidor malicioso Malicious server responds

Tableau 3 – Adresses de serveurs de commande et de contrôle (sites Web piratés utilisés comme premier niveau de serveurs mandataires)

Funcionamiento normal Normale Funktionsweise
Servidor DNS DNS Server
Víctima Opfer
Servidor web Web Server
Consulta por www.ejemplo.com www.example.com
Lookup
Respuesta Servidor web Antwort Web Server
Acceso a sítio legítimo Zugang zur legitimen Webseite

Notes

5. Deux heures par défaut, mais le temps d’attente dépend de la valeur du champ « logperiod » sous la section « LOG » du fichier de configuration.
6. Pour obtenir de plus amples renseignements, consultez la section « Exécution des tâches ».
7. Pour obtenir plus de renseignements, consultez la section « Orchestrateur / Exécution des tâches ».
8. Selon le fichier de configuration; pour de plus amples renseignements, consultez la section « Actualisation du fichier de journal ».