Cyril François

Déballage de l'ICEDID

Un tutoriel complet sur les outils open source d'Elastic Security Labs

14 minutes de lectureOutils
Décompresser ICEDID

Préambule

ICEDID est une famille de logiciels malveillants découverte àl'adresse 2017 par les chercheurs d'IBM X-force. Elle est associée au vol d'identifiants de connexion, d'informations bancaires et d'autres informations personnelles. L'ICEDID a toujours été une famille prépondérante, mais elle a connu une croissance encore plus importante depuis l'interruption temporaire d' EMOTET au début de l'année 2021. L'ICEDID a été associé à la distribution de plusieurs familles de logiciels malveillants, dont DarkVNC et COBALT STRIKE. Des rapports réguliers sur le secteur, y compris des publications de recherche comme celle-ci, contribuent à atténuer cette menace.

L'ICEDID est connu pour emballer ses charges utiles en utilisant des formats de fichiers et un système de cryptage personnalisés. Suite à notre dernière recherche ICEDID qui couvre la chaîne d'exécution de la variante GZip.

Dans ce tutoriel, nous présenterons ces outils en décompressant un échantillon récent d'ICEDID, en commençant par télécharger une copie du faux binaire GZip :

L'analyse des logiciels malveillants peut être dangereuse pour les systèmes et ne doit être effectuée que par des professionnels expérimentés dans un environnement contrôlé, comme une machine virtuelle isolée ou un bac à sable d'analyse. Les logiciels malveillants peuvent être conçus pour échapper à la détection et infecter d'autres systèmes. Il est donc important de prendre toutes les précautions nécessaires et d'utiliser des outils spécialisés pour vous protéger et protéger vos systèmes.

54d064799115f302a66220b3d0920c1158608a5ba76277666c4ac532b53e855f

Configuration de l'environnement

Pour ce tutoriel, nous utilisons Windows 10 et Python 3.10.

Elastic Security Labs publie une série d'outils pour automatiser le processus de décompression et aider les analystes et la communauté à répondre à l'ICEDID.

ScriptDescriptionCompatibilité
decrypt_file.pyDécryptage du fichier crypté ICEDIDWindows et autres (non testé)
gzip_variant/extract_gzip.pyExtraction de charges utiles à partir du faux fichier GZip d'ICEDIDWindows et autres (non testé)
gzip_variant/extract_payload_from_core.pyExtraire et décrypter les charges utiles du noyau binaire reconstruit de l'ICEDID.Windows et autres (non testé)
gzip_variant/load_core.pyChargement et exécution d'un binaire PE personnaliséWindows uniquement
gzip_variant/read_configuration.pyLire le fichier de configuration ICEDID contenu dans le faux GZipWindows et autres (non testé)
rebuild_pe.pyReconstruire un PE à partir d'un fichier PE personnalisé ICEDIDWindows et autres (non testé)

Pour utiliser les outils, clonez le référentiel Elastic Security Lab et installez le module nightMARE.

git clone https://github.com/elastic/labs-releases
cd labs-release
pip install .\nightMARE\

Tous les outils de ce tutoriel utilisent le module nightMARE, cette bibliothèque implémente les différents algorithmes dont nous avons besoin pour décompresser les différentes charges utiles intégrées dans l'ICEDID. Nous publions nightMARE parce qu'il est nécessaire à l'analyse de l'ICEDID, mais restez à l'écoute - d'autres informations seront publiées au fur et à mesure du développement et de la maturation de ce cadre.

Décompression du faux GZip

Le faux GZip de l'ICEDID est un fichier qui se fait passer pour un fichier GZip valide formaté en encapsulant les données réelles dans un en-tête et un pied de page GZip.

Les octets magiques GZip apparaissent en rouge.
L'en-tête GZip est affiché en vert.
La valeur du nom de fichier fictif est bleue.

Après l'en-tête GZip se trouve la véritable structure de données, que nous décrivons ci-dessous.

Nous utiliserons le script labs-releases\tools\icedid\gzip-variant\extract_gzip.py pour décompresser ce GZip frauduleux.

usage: extract_gzip.py [--help] input output

positional arguments:
  input       Input file
  output      Output directory

options:
  -h, --help  show this help message and exit

Nous allons utiliser extract_gzip.py sur l'échantillon ICEDID lié ci-dessus et stocker le contenu dans un dossier que nous avons créé appelé " extract " (vous pouvez utiliser n'importe quel dossier de sortie existant).

python extract_gzip.py 54d064799115f302a66220b3d0920c1158608a5ba76277666c4ac532b53e855f extract

============================================================
Fake Gzip
============================================================
is_dll: True
core: UponBetter/license.dat (354282 bytes)
stage_2: lake_x32.tmp (292352 bytes)

extract\configuration.bin
extract\license.dat
extract\lake_x32.tmp

Ce script renvoie trois fichiers individuels composés de

  • Le fichier de configuration crypté : configuration.bin
  • Le binaire central crypté : license.dat
  • Le chargeur de persistance : lake_x32.tmp

Décryptage du noyau binaire et des fichiers de configuration

La configuration et le noyau binaire que nous avons extraits sont cryptés à l'aide du schéma de cryptage personnalisé de l'ICEDID. Nous pouvons les décrypter avec le script labs-releases\tools\icedid\decrypt_file.py.

usage: decompress_file.py [--help] input output

positional arguments:
  input       Input file
  output      Output file

options:
  -h, --help  show this help message and exit

Comme illustré ici (notez que les fichiers décryptés peuvent être écrits vers n'importe quelle destination valide) :

python .\decrypt_file.py .\extract\license.dat .\extract\license.dat.decrypted

python .\decrypt_file.py .\extract\configuration.bin .\extract\configuration.bin.decrypted

Le binaire de base et la configuration sont maintenant prêts à être traités par des outils supplémentaires. Les données de la configuration décryptée sont présentées dans la capture d'écran suivante :

Lecture de la configuration

Le format du fichier de configuration est présenté ci-dessous.

La configuration peut être lue en utilisant le script labs-releases\tools\icedid\gzip-variant\read_configuration.py.

usage: read_configuration.py [--help] input

positional arguments:
  input       Input file

options:
  -h, --help  show this help message and exit

Nous allons utiliser le script read_configuration.py pour lire le fichier configuration.bin.decrypted que nous avons collecté à l'étape précédente.

python .\gzip-variant\read_configuration.py .\extract\configuration.bin.decrypted

============================================================
Configuration
============================================================
botnet_id: 0x3B7D6BA4
auth_var: 0x00000038
uri: /news/
domains:
        alishaskainz.com
        villageskaier.com

Cette configuration contient deux domaines C2 :

  • alishaskainz[.]com
  • villageskaier[.]com

Pour cet exemple, l'URI de balisage utilisé par l'ICEDID est " /news/ ".

Reconstruction du binaire de base pour l'analyse statique

ICEDID utilise un format PE personnalisé pour obscurcir ses charges utiles, ce qui permet de déjouer les outils d'analyse statique ou dynamique qui s'attendent à traiter un exécutable Windows normal. Le format du fichier PE personnalisé est décrit ci-dessous.

Si nous voulons analyser le noyau binaire, par exemple avec IDA Pro, nous devons le reconstruire en un PE valide. Nous utilisons le script labs-releases\tools\icedid\rebuild_pe.py.

usage: rebuild_pe.py [--help] [-o OFFSET] input output

positional arguments:
  input                 Input file
  output                Output reconstructed PE

options:
  -h, --help            show this help message and exit
  -o OFFSET, --offset OFFSET
                        Offset to real data, skip possible garbage

Cependant, lorsque nous essayons d'utiliser rebuild_pe.py sur le binaire de base décrypté, license.dat.decrypted , nous recevons le message d'erreur suivant :

python .\rebuild_pe.py .\extract\license.dat.decrypted .\extract\core.bin
Traceback (most recent call last):
  File "rebuild_pe.py", line 32, in <module>
    main()
  File "rebuild_pe.py", line 28, in main
    custom_pe.CustomPE(data).to_pe().write(args.output)
  File "nightmare\malware\icedid\custom_pe.py", line 86, in __init__
    raise RuntimeError("Failed to parse custom pe")
RuntimeError: Failed to parse custom pe

La subtilité ici est que les données personnalisées du PE ne commencent pas toujours au début du fichier. Dans ce cas, par exemple, si nous ouvrons le fichier dans un éditeur hexadécimal comme HxD, nous pouvons observer un certain nombre d'octets parasites avant les données réelles.

Nos recherches nous ont appris que la taille des déchets est de 129 octets.

En gardant cela à l'esprit, nous pouvons ignorer les octets inutiles et reconstruire le noyau binaire à l'aide du script rebuild_pe.py en utilisant le paramètre "-o 129". Cette fois-ci, heureusement, nous ne recevons pas de message d'erreur. core.bin sera enregistré dans le répertoire de sortie, extract dans notre exemple.

python .\rebuild_pe.py .\extract\license.dat.decrypted .\extract\core.bin -o 129

L'objet PE reconstruit n' est pas directement exécutable, mais vous pouvez l'analyser statiquement à l'aide du désassembleur de votre choix.

Nous avons attribué des noms personnalisés aux sections binaires reconstruites ( .mare{0,1,2,...} ).

Nous tenons à remercier Hasherezade pour son travail dont nous nous sommes inspirés pour créer cet outil.

Exécution du binaire principal (Windows uniquement)

Le noyau binaire ne peut être exécuté sans un chargeur personnalisé qui comprend le format PE personnalisé de l'ICEDID ainsi que le prototype de la fonction du point d'entrée.

D'après nos recherches, nous savons que le point d'entrée attend une structure que nous appelons structure contextuelle, qui contient le noyau de l'ICEDID et les chemins du chargeur de persistance avec sa configuration chiffrée. La structure du contexte est décrite ci-dessous.

Pour exécuter nativement le binaire core, nous utilisons le script labs-releases\toolsiced\idgzip-variant\load_core.py, mais avant de l'utiliser, nous devons créer le fichier context.json qui contiendra toutes les informations nécessaires à ce script pour construire cette structure.

Pour cet exemple, nous copions les informations contenues dans le faux gzip et nous utilisons le chemin vers le fichier de configuration crypté. Nous avons inclus un exemple à gzip_variant/context.json.example.

Veuillez noter que les valeurs "field_0" et "stage_2_export" doivent être trouvées en inversant l'échantillon.

Nous utilisons ici des valeurs issues de nos recherches antérieures, mais nous ne garantissons pas que l'échantillon fonctionnera à 100 %. Par exemple, dans cet exemple, nous ne savons pas si l'export ordinal #1 est le point d'entrée réel du chargeur de persistance.

Nous reproduisons également le comportement de la première étape en créant le répertoire UponBetter et en y déplaçant le fichier license.dat.

Nous exécutons le script labs-releases\tools\icedid\gzip_variant\load_core.py en utilisant le binaire décrypté: license.dat.decrypted , le fichier context.json.

AVERTISSEMENT : Le binaire va être chargé/exécuté nativement par ce script, Elastic Security Labs n'est pas responsable des dommages éventuels causés à votre système. Veuillez n'exécuter que dans un environnement sûr.

usage: load_core.py [--help] [-o OFFSET] core_path ctx_path

positional arguments:
  core_path             Core custom PE
  ctx_path              Path to json file defining core's context

options:
  -h, --help            show this help message and exit
  -o OFFSET, --offset OFFSET
                        Offset to real data, skip possible garbage

Comme nous avons le même problème d'octets inutiles que dans la section précédente, nous utilisons le paramètre "-o 129" pour ignorer les octets inutiles.

python .\gzip-variant\load_core.py .\extract\license.dat.decrypted .\gzip-variant\context.example.json -o 129

============================================================
Core Loader
============================================================
Base address: 0x180000000
Entrypoint: 0x180001390

Press a key to call entrypoint...

Lorsqu'il est lancé, le script attend l'entrée de l'utilisateur avant d'appeler le point d'entrée. Nous pouvons facilement attacher un débogueur au processus Python et placer un point d'arrêt sur le point d'entrée du noyau ICEDID (dans cet exemple 0x180001390 ).

Une fois la touche enfoncée, nous atteignons le point d'entrée.

Si nous laissons le binaire s'exécuter, nous constatons que des fils ICEDID sont créés (comme indiqué dans la capture d'écran suivante).

Décompression et reconstruction des charges utiles à partir du noyau binaire reconstruit

Pour extraire les charges utiles qui sont intégrées dans le binaire central, nous utiliserons le script labs-releases\tools\icedid\gzip-variant\extract_payloads_from_core.py.

usage: extract_payloads_from_core.py [--help] input output

positional arguments:
  input       Input file
  output      Output directory

options:
  -h, --help  show this help message and exit

Nous utiliserons ce script sur le binaire de base reconstruit.

python .\gzip-variant\extract_payloads_from_core.py .\extract\core.bin core_extract

core_extract\browser_hook_payload_0.cpe
core_extract\browser_hook_payload_1.cpe

À partir de là, nous obtenons deux binaires correspondant aux charges utiles de l'ICEDID pour les capacités d'accrochage du navigateur web, mais ils sont toujours dans leur format PE personnalisé.

D'après nos recherches, nous savons que browser_hook_payload_0.cpe est la version x64 du browser hook payload et que browser_hook_payload_1.cpe est la version x86.

Pour les reconstruire, nous utilisons à nouveau le script rebuild_pe.py, mais cette fois-ci, il n'y a pas d'octets inutiles à ignorer.

python .\rebuild_pe.py .\core_extract\browser_hook_payload_0.cpe .\core_extract\browser_hook_payload_0.bin

python .\rebuild_pe.py .\core_extract\browser_hook_payload_1.cpe .\core_extract\browser_hook_payload_1.bin

Nous avons maintenant deux binaires PE ( browser_hook_payload_0.bin et browser_hook_payload_1.bin ) que nous pouvons analyser plus en détail.

Les lecteurs attentifs remarqueront que nous avons sauté le déballage du serveur VNC à partir du binaire de base, une décision que nous avons prise intentionnellement. Nous le publierons avec d'autres outils dans les prochaines recherches, alors restez à l'écoute !

Conclusion

Dans ce tutoriel, nous avons abordé le déballage de la variante GZip de l'ICEDID, en commençant par l'extraction du faux binaire GZip, suivie de la reconstruction du binaire principal et du déballage de ses charges utiles.

L'ICEDID est en constante évolution, et nous allons continuer à suivre les changements majeurs et à mettre à jour nos outils en même temps que notre recherche. N'hésitez pas à ouvrir un dossier ou à nous envoyer un message si quelque chose est cassé ou ne fonctionne pas comme prévu.

Elastic Security Labs est une équipe de chercheurs et d'ingénieurs en sécurité dévoués qui s'efforcent de perturber les adversaires en publiant des logiques de détection détaillées, des protections et des recherches appliquées sur les menaces.

Suivez-nous sur @elasticseclabs etvisitez notre portail de recherche pour plus de ressources et de recherches.

Références

Les éléments suivants ont été référencés tout au long de la recherche ci-dessus :

Partager cet article