Le blog de ChapsVision CyberGov

Extraction de configuration d’un malware .NET obfusqué : le cas de DCRat

Bienvenue dans le deuxième volet de notre série d’articles consacrés aux malwares .NET ! La première partie, disponible ici, explore quelques-unes des caractéristiques de la plateforme .NET, ainsi que les défis inhérents à l’analyse d’un malware écrit en C# ou VB.NET.

Dans cet article, nous vous proposons l’analyse d’un échantillon provenant de MalwareBazaar, identifié par le hash suivant :

815fb4e7a5b3004533fcfd5960b6ab6eb1d772cfeae43d74445603419d359dcb

L’objectif est de comprendre les activités de ce malware en nous concentrant sur deux aspects cruciaux :

  • Sa configuration interne
  • Ses indicateurs de compromission (IOC)
 

La configuration englobe tous les éléments qui orchestrent le comportement du malware une fois déployé sur une machine cible. Il est fréquent d’y trouver des IOC, tels que :

  • Les adresses des serveurs C2 (Command & Control) vers lesquels il exfiltre les données
  • Des identifiants de campagne
  • Le mutex du malware
 

Au cours de cette analyse, nous mettrons en avant les étapes nécessaires à la découverte de ces informations et vous proposerons un script permettant d’automatiser le processus d’extraction, sans avoir à exécuter le malware.

1. Obtention des éléments de base

La première étape consiste à déterminer le type du fichier. Une simple commande file révèle qu’il s’agit bien d’un exécutable 32-bits développé en .NET :
Fig.1 : sortie de la commande file

Ensuite, un recours aux commandes strings et strings -el n’est pas à négliger, car il permet d’avoir une idée générale des chaînes de caractères présentes au sein de l’exécutable :

Fig.2 : Sorties des commandes strings et strings -el

S’il n’y a pas encore d’informations exploitables en termes de configuration (pas d’IP ou d’URL visibles, pas de hash spécifique non plus), quelques indices apparaissent néanmoins :

  • La présence de chaînes de caractères obfusquées 
  • Les chaînes {1111-2222-xxxx-xxxx} indiquant une utilisation probable de .NET Reactor, un obfuscateur prisé tant par les acteurs malveillants que par les entreprises légitimes
 

Nous pouvons utiliser dnSpy, un décompilateur open-source, afin d’explorer le code en détail et confirmer nos doutes :

Fig.3 : Point d’entrée de l’échantillon, vu dans dnSpy

Le code est effectivement peu clair : les noms de plusieurs bibliothèques de fonctions (précédées par le mot-clef using) ont été altérés, tout comme ceux de la majorité des classes, méthodes et variables ; le flot de contrôle (ou CFG, pour Control Flow Graph) comprend des instructions goto et des switch inutiles et plusieurs conditions mortes {while (false) … } qui ne servent qu’à polluer l’ensemble.

En outre, on peut voir que « Akvwhmi2QHAgCb03kQ », aperçu grâce à strings -el, correspond à une ressource utilisée par le programme, c’est-à-dire une annexe contenant généralement des éléments permettant au programme de fonctionner, tels que du texte, des images, ou encore des fichiers audios.

2. Tentative de désobfuscation

Pour contrer ces mécanismes de protection et obtenir un binaire plus lisible, il est possible d’utiliser de4dot, un désobfuscateur écrit en C#, dont le fonctionnement repose sur deux axes majeurs :

  • la détection du type d’obfuscateur utilisé et l’application d’algorithmes spécifiques à cet obfuscateur. Si l’obfuscateur n’est pas connu, ou si une nouvelle version d’un obfuscateur est en vigueur, il est possible de les rajouter soi-même grâce à des templates 
  • le traitement et la manipulation du code IL (Intermediate Language, l’assembleur qui sous-tend tout projet .NET), représenté par les blocs, une classe d’objets représentant les blocs d’instructions IL qu’il peut alors analyser, émuler et réécrire pour produire un exécutable plus propre
Dans notre cas, de4dot détecte effectivement .NET Reactor et peut créer une copie débarrassée d’une grande partie de l’obfuscation :

Fig.4 : Désobfuscation réussie par de4dot

Réitérer la commande strings -el sur le nouvel exécutable montre des résultats bien plus intéressants, car car la commande révèle alors un arsenal de fonctionnalités malveillantes potentiellement utilisées par le malware (la liste n’est pas exhaustive) :

1) Collecte d’informations

  • Données système (configuration matérielle, antivirus)
  • Identifiants de services populaires (Telegram, Discord, Steam)
  • Données de navigation (cookies)
  • Contenu du presse-papier
Fig. 5 : Exemple d’éléments indiquant une collecte d’informations

2) Surveillance active

  • Enregistrement des frappes (keylogging)
  • Captures d’écran
  • Enregistrement audio via microphone

Fig. 6 : Exemples d’éléments indiquant un monitoring d’activités

3) Contrôle et persistance

  • Exécution de commandes PowerShell et CMD
  • Planification de tâches automatisées
  • Modification du registre système
  • Communication avec le C2 via requêtes HTTP POST
Fig. 7 : Exemples de tentatives de persistance

3. Identification du malware : DCRat

La présence d’un en-tête encodé en base64 nous donne le nom de cette famille de malware :

Fig. 8 : En-tête « DarkCrystalRAT »

Nous savons désormais qu’il s’agit de DCRat, ou Dark Crystal RAT, un cheval de Troie d’accès à distance (Remote Access Trojan) originaire de Russie, connu pour être l’une des familles de malwares les moins chères du marché (le premier prix d’achat commence aux alentours de 10euros). Présent depuis 2018, ce malware a notamment été aperçu au début du conflit ukraino-russe, en outil de déstabilisation des forces ukrainiennes. Comme il existe une littérature abondante à son sujet, le but ici ne sera pas de dresser une liste complète de ses fonctionnalités.
Notons cependant que DCRat reste une menace active et continue à évoluer, tant dans ses méthodes de diffusion que ses méthodes d’obfuscation.

4. Automatisation de l’extraction des IOC

D’où viennent ces nouvelles chaînes de caractères ?

Afin de protéger l’échantillon de l’analyse statique, .NET Reactor a chiffré toutes les chaînes de caractères présentes dans le code source : celles-ci sont d’abord agrégées au sein de l’une des ressources au format [ taille de la chaîne (4 octets) ][ valeur de la chaîne ], puis chaque bloc de 4 octets est XORé avec un entier généré dynamiquement. Cet entier s’obtient grâce à trois éléments distincts :

  • Une clé initiale
  • Un vecteur d’initialisation (IV)
  • Une valeur obtenue pendant l’exécution
La clé et l’IV sont présents en dur dans le code, mais sont modifiés avant leur utilisation finale. La dernière valeur, quant à elle, dépend de la clé modifiée mais aussi des instructions de calculs, uniques à chaque échantillon, lancées au moment de l’exécution :
Fig. 9 : Chiffrement des ressources par .Net Reactor

Une fois la ressource chiffrée intégralement, toutes les références aux chaînes dans le code sont remplacées par des appels à une fonction de déchiffrement, qui ne les restaure qu’au moment de l’exécution :

Fig. 10 : Fonction utilisant la ressource avant désobfuscation

Fig. 11 : Fonction utilisant la ressource après désobfuscation
Mais certaines chaînes demeurent chiffrées, et si elles ne nécessitent, dans le meilleur des cas, qu’une simple conversion depuis la base64, d’autres semblent être le produit de quelques étapes de chiffrement additionnelles.

Que faire des dernières chaînes encore obfusquées ?

Il est nécessaire d’identifier, d’isoler et d’analyser l’utilisation de ces chaînes au sein du code.

Trois chaînes spécifiques ont été sélectionnées en raison de leur taille considérable et de leur passage à-travers un nombre important de fonctions :

Fig. 12 : chaîne 1 (tronquée, car extrêmement longue)
Fig. 13 : chaîne 2
Fig. 14 : chaîne 3
A première vue, ces trois chaînes issues de l’une des ressources et commençant toutes par « H4sIAA » ont été converties en base-64, mais cela ne suffit pas pour obtenir un résultat lisible. Nous avons enregistré le code source en C# afin de mieux analyser leur contexte dans VSCode :
Fig. 15 : extrait du code source, avec utilisation des classes suspectes

Class95 et Class104 sont omniprésentes et modifient, entre autres, ces trois chaînes.
En les examinant de plus près, on leur découvre plusieurs fonctions internes :

  • Conversion depuis la base-64 (Class95.smethod_5)
  • Décompression (grâce à GZip) (Class95.smethod_6)
  • Inversion des caractères (Class104.smethod_5)
  • Application d’un dictionnaire (Class95.WhHkltotnc), dont les clés-valeurs semblent dériver de l’une des chaînes chiffrées

Les chaînes 1 et 3 nécessitent justement un dictionnaire pour être lisibles, à la différence de la chaîne 2.
En appliquant les opérations trouvées dans le code sur la chaîne 2 dans CyberChef (pour un résultat plus visuel), voici ce que l’on obtient :

Fig. 16 : opérations de déchiffrement effectuées dans CyberChef sur la chaîne 2

Ces éléments peuvent être divisés en trois parties distinctes, toutes au format JSON :

  • Un dictionnaire SCRT à utiliser pour déchiffrer chaîne 3
  • Un dictionnaire PCRT pour déchiffrer chaîne 1
  • Des éléments de configuration du malware, notamment le nom de son mutex, « DCR_MUTEX-vmlP5VtILfN63WggN4aM », ainsi que certaines des fonctionnalités activées (récupération des cookies et des mots de passe, captures d’écran, etc.)

Un simple script python a permis de déchiffrer rapidement le contenu des deux chaînes restantes en appliquant les mêmes étapes que pour chaîne 2, tout en rajoutant le dictionnaire correspondant :

  • chaîne 1 correspond aux plugins optionnels accompagnés de leurs configurations
Fig. 17 : Chaîne 1 dévoile les plugins (clé « 0 ») et leurs configurations (clé « 1 »)
  • chaîne 3 correspond aux serveurs distants
Fig. 18 : Chaîne 3 dévoile les URLs contactés

Notons également que la configuration des plugins et la dernière partie des URLs étaient toutes deux à convertir depuis la base-64 et à inverser, pour obtenir un résultat exploitable – une énième couche d’obfuscation qui trahit la volonté de complexifier encore plus une détection automatisée.

Automatisation et mise à l’échelle de l’extraction

Au cours de nos recherches, nous sommes tombés sur plusieurs échantillons DCRat partageant la même structure : obfusqués par .NET Reactor et contenant trois chaînes de caractères commençant par « H4sIAA », après désobfuscation. Nous avons choisi de créer une règle YARA fondée sur les chaînes de caractères au format wide char présentes dans le binaire avant désobfuscation. Vient ensuite la création d’un script permettant deux choses : désobfusquer les binaires validés par la règle, puis extraire les configurations de tous les binaires désobfusqués avec succès. C# a été utilisé afin d’intégrer quelques-unes des fonctionnalités de de4dot (notamment l’émulation de code IL) :

Fig. 19 : extrait du script C# permettant d’extraire la configuration en statique

Le script produit de bons résultats pour tous les exécutables validés par la règle YARA, récupérés sur VirusTotal et MalwareBazaar :

Fig. 20 : nombre de matchs obtenus sur VT avec la règle YARA
Fig. 21 : extrait de la sortie du script après traitement de plusieurs échantillons

La longueur de chaîne 1 étant due à la présence de plugins, il était préférable de les extraire et de n’afficher que leur hash en SHA-256.

Dernières améliorations

Un détail a cependant attiré notre attention. Pour la chaîne 3, lorsqu’ils ne sont pas accessibles immédiatement sous la forme « H1 / H2 », les C2 sont stockés en ligne grâce à l’application PasteBin, au format [C2_chiffré. Dictionnaire_chiffré], obfusqués avec les mêmes techniques vues précédemment, c’est-à-dire inversion des caractères, conversion depuis la base64 et utilisation d’un dictionnaire :

Fig. 22 : exemple d’une configuration stockée sur PasteBin

En outre, puisque qu’aucun URL obtenu n’est identique et que les noms semblent avoir été générés aléatoirement grâce à un DGA (Domain Generator Algorithm), il a semblé pertinent de retrouver les adresses IP contactées, afin de préparer le terrain pour une meilleure contextualisation des données. En effet, il est plus facile de regrouper les échantillons selon l’utilisation d’une même adresse IP, plutôt qu’en collectionnant un grand nombre d’URL différents :

Fig. 23 : extrait de sortie du script intégrant les adresses IP trouvées

Comment organiser et mettre en relation tous les IOC obtenus ?

Il est très facile de customiser la sortie du script pour mieux l’intégrer dans un logiciel interne. On peut sélectionner les serveurs, les IP, les mutexes ou les hash, selon les besoins, puis transformer la sortie en JSON.
Dans cet exemple, nous avons regroupé les IOC au sein d’un JSON au format STIX (Structured Threat Information eXpression) :

Fig. 24 : mise en image d’un fichier STIX dans l’outil STIX Visualizer

Puisque notre objectif reste avant tout la valorisation et la mise en contexte d’informations critiques, il est important de savoir adapter le type et le format des informations obtenues afin de créer une vision globale, essentielle à toute investigation cyber. La récupération des IOC de plusieurs malwares peut rapidement mener à un faisceau d’indices permettant l’identification d’acteurs malveillants, de zones géographiques ou de secteurs industriels ciblés par la menace.

Conclusion

Cette analyse nous a permis de :

  • Comprendre les techniques d’obfuscation utilisées par DCRat
  • Identifier des éléments de configuration critiques (serveurs C2, mutex, modules additionnels)
  • Automatiser le processus d’extraction pour traiter un grand volume d’échantillons

La création d’un script d’automatisation montre l’importance cruciale de la mise à l’échelle et de l’intégration des capacités d’analyse dans des systèmes globaux afin de traiter efficacement les menaces émergentes. L’adoption de formats standardisés tels que STIX pour la gestion des IOC permet non seulement une caractérisation précise, mais aussi une coopération renforcée au sein de la communauté de la cybersécurité.

Face à des menaces en constante évolution, comme l’illustre l’exemple de DCRat qui s’est transformé à de nombreuses reprises, il est essentiel d’adopter une approche combinant rigueur méthodologique et innovation technique. Chaque IOC découvert, chaque configuration extraite et chaque outil perfectionné représente une information précieuse qui vient enrichir notre base de connaissances sur les tactiques, techniques et procédures (TTP) employées par les acteurs malveillants.

En consolidant systématiquement ces informations, l’équipe CTI de Chapsvision cherche à améliorer la capacité collective à détecter, analyser et atténuer proactivement les menaces, tout en se préparant aux évolutions futures des techniques utilisées par les cybercriminels.

Règle YARA :

				
					rule dcrat_dotnetReactObfuscated {
    meta:
        description = "Détecte les configurations DCRat obfusquées avec .Net Reactor"
        author = "Chapsvision-CyberGov"
        hash = "de04994b9650e7f00f8f264ade023d530d292ab03ad672e0101d8e32b886d575"
        hash = "3fa6ddcabcb03763ef1887117e16ebdf0553a1cc2a16b58bdecaba0735d4e60a"
        hash = "0ade415868175c73d51330fb85ddcb58654ccd18254066fc1f9861482f649adb"
        hash = "5d3aa443debb15bdf756b94980e0a6bcbef950edd72941905f70eded5238590c"
        hash = "156a45b0743164c9fa027d10bcfc1f1a6ec3673cadf8c4b82f996e1bd12f95ed"
 
    strings:
        $s1 = "System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" wide
        $s2 = "GetDelegateForFunctionPointer" wide
        $s3 = "file:///" wide
        $s4 = "{11111-22222-20001-00001}" wide
        $s5 = "{11111-22222-20001-00002}" wide
        $s6 = "{11111-22222-30001-00001}" wide
        $s7 = "{11111-22222-30001-00002}" wide
        $s8 = "{11111-22222-40001-00001}" wide
        $s9 = "{11111-22222-40001-00002}" wide
        $s10 = "040904B0" wide
        $s11 = "FileVersion" wide
        $s12 = "5.15.2.0" wide
        $s13 = "dclib" wide
        $s14 = "H4sIAAA" wide
 
    condition:
        uint16(0) == 0x5A4D and
        uint32(uint32(0x3C)) == 0x00004550 and
        (
            all of ($s1, $s2, $s3, $s4, $s5, $s6, $s7, $s8, $s9, $s10, $s11, $s12)
            or
            $s13 and
            #s14 == 3
        )
}
				
			

Fig.25 : Règle YARA utilisée pour détecter les échantillons DCRat obfusqués par .NET Reactor

IOC :

(Re)découvrez notre précédent article :