Kardon

Analyse de malware

Publié le


Introduction

Il s'agit là de mon tout premier article sur l'analyse d'un malware. Le sample analysé est le programme Kardon. Dans cette analyse nous verrons toutes les fonctionnalités du programme malveillant à travers l'analyse statique.


Collecte d'informations


CFF Explorer

On commence tout d'abord à récupérer quelques informations avec CFF Explorer. On s'aperçoit que l'exécutable est un type PE et un programme 32 bits codé en C++.
Image
Il est possible de regarder quelles sont les librairies importées :
Image


Strings

On peut déduire certaines fonctionnalités du programme avant même de faire de l'analyse statique avec IDA en regardant les strings. Par exemple, ici on suppose que le programme fait des vérifications pour connaître l'OS de la cible :
Image
Ici on suppose qu'il check si il se trouve dans une machine virtuelle :
Image
Ici on sait que le progamme envoi des données via une requête POST :
Image
On suppose ici que le programme semble vouloir se rendre persistant car on trouve le chemin où l'on place les clés de registre des programmes se lançant au démarrage du système :
Image
Ici on trouve ce qui semble être le site contacté par le programme et il semble pointer sur la page /kardon/gate.php, peut-être que c'est sur cette page que la requête POST est envoyée.
Image
Enfin, dans les strings du programme on voit un tas d'autres informations comme des fonctions utilisées, par exemple ici on trouve des fonctions relative à la création et l'ajout de valeur d'une clé de registe.
Image


Analyse statique

Lorsqu'on ouvre le programme avec IDA on se retrouve dans la fonction start du code et chacune des fonctions présentes ici ont l'air de jouer un rôle de mise en route, donc rien de vraiment intéressant. Cependant tout à la fin de cette fonction start se trouve une fonction qui a l'air de lancer tout le reste du programme nous allons donc la renommer "main".
Image
Nous voici à présent dans le main (sub_402247):
Image
On observe plusieurs choses à commencer par le premier call vers la fonction sub_401A43, ensuite nous entrons dans ce qui semble être une boucle infini dans la fonction loc_40224C. Dans cette fonction il y a deux CALL pour les fonctions sub_401C4A et sub_401DD2 puis à la fin de la boucle nous avons un appel à la fonction sleep avant de relancer la boucle.
Commençons par analyser la fonction sub_401A43 que nous avons renommé en Init :
Image
On va découper en plusieurs parties cette grande fonction et nous allons commencer par la partie ci-dessus. Cette partie comporte un appel à destination de la fonction sub_40148B et un JUMP conditionnel en fonction de la valeur du registre AL.
D'ailleurs on remarque que nous allons avoir 3 autres JUMPs conditionnels de ce genre et ces 4 JUMPs peuvent nous emmener dans la fonction loc_401BD3 qui fait un appel à la fonction ExitProcess.
Image
On suppose donc que si chacune des conditions ne sont pas respectées alors le programme s'arrête. Il devient donc intéressant de regarder chacune des fonctions qui sont appelées et observer comment nous pouvons obtenir la valeur 0 dans le registre AL (nous pouvons aussi très bien modifier notre registre à la main ou rajouter une instruction xor al, al juste avant la vérification test al, al) puisque nos 4 JUMPs conditionnels sont de type JNZ, ça veut dire que si la valeur de retour n'est pas égal à 0 alors on jump dans la fonction loc_401BD3 que nous allons maintenant appeler exitFunction.
Voici une partie de la première fonction :
Image
Cette fonction va servir à détecter si le malware a été exécuté dans un environnement virtuel. La fonction qui suit fait appel à la fonction cpuid qui a pour objectif de requéter le système à propos du CPU pour que le programme puisse comprendre sur quel type d'architecture il tourne et savoir si il s'agit d'un environnement virtualisé.
Image
Fonction intéressante (toujours des protections):
Image
La fonction ci-dessus aura pour rôle de charger un ensemble de DLLs dans le but de se renseigner sur le comportement de la machine hôte. Les choix des DLLs ne sont pas anodins puisqu'elles représentent pour chacune d'entre-elles un composant d'un outil permettant d'analyser un malware.
Par exemple, on y retrouve des DLLs liées à des Sandboxes et des anti-virus (comme AVG et Avast dans notre cas).
Voici la dernière fonction de la série :
Image
Cette dernière fonction aura pour rôle de charger le module kernel32.dll et si il y parvient, alors il tentera de trouver l'adresse de la fonction wine_get_unix_file_name. Ce module permettra au programme de savoir si il a été exécuté sous Wine qui est un programme permettant de lancer Windows à travers un système Linux.
Image
Cette fonction fait suite aux différentes fonctions vu juste avant.
Nous arrivons ici si tout s'est bien déroulé. Dans cette fonction nous y voyons plusieurs choses qui nous sautent aux yeux
à savoir :

  • - Le nom de domaine kardon[.]ddns[.]net
  • - La page /kardon/gate.php
  • - Un appel à la fonction getInformations

Pour le moment les deux variables domainName et pageName ne sont pas exploitées, il faudra attendre un peu plus loins dans le programme.Pour l'instant nous allons découvrir la fonction getInformations :
Image
Dans cette première partie de la fonction getInformations nous avons 3 appels qui vont nous permettre de déterminer
plusieurs informations :

  • - checkIf64bits : cette fonction va faire appel à GetProcAddress pour tenter de résoudre l'adresse du module IsWow64Process. Ce module contient les exécutables contenus dans le dossier \Windows\system32 mais ici ces programmes sont compilés en 64 bits. Cette fonction va nous permettre d'identifier le type d'architecture (x86 ou x64).
  • - getSystemInfo : cette fonction renvoi des informations sur le système.
  • -
  • - getComputerNameA : cette fonction renvoi le nom de la machine.

Image
Dans cette partie là de la même fonction on retrouve un appel à une fonction sub_4012A6 qui
va récupérer les informations du token de sécurité pour déterminer les droits de l'utilisateur en cours et savoir si il s'agit de l'admin ou pas.
L'appel à la fonction GetVolumeInformationA va permettre de récupérer un ensemble d'informations au sujet du volume « C:\\ ».
Image
Cette enchainement va permettre de faire deux vérifications sur la librairie "kernel32.dll" via deux fonctions qui sont GetFileVersionInfoSizeA et GetFileVersionInfoA. Si le résultat retourné n'est pas celui attendu alors un JUMP vers la fin de la fonction est effectué.
Image
A la suite nous avons plusieurs vérifications pour trouver le système d'exploitation de la machine hôte.
Pour récapituler, dans cette fonction getInformations nous avons des méthodes pour :

  • - Récupérer l'architecture du système hôte
  • - Récupérer le nom de l'utilisateur en cours
  • - Récupérer le nom de la machine hôte
  • - Récupérer des informations sur le système hôte
  • - Connaître le niveau de droit de l'utilisateur (savoir si il s'agit d'un administrateur ou pas)
  • - Obtenir des détails sur les volumes disques
  • - Connaître le système d'exploitation de l'hôte


Image
Dans cette fonction on va vérifier si l'utilisateur en cours est administrateur et en fonction du retour un moyen de persistance va être établi.
Par exemple ici nous avons :
Image
Ici la méthode de persistance va dépendre des droits d'exécutions du malware, si le programme a été exécuté avec des droits administrateurs alors on ira à gauche sinon on ira à droite. Seul l'administrateur peut écrire dans HKEY_LOCAL_MACHINE. Ici on se placera dans cette racine dans le chemin SOFTWARE\Microsoft\Windows\CurrentVersion\Run si nous voulons rendre le programme persistant pour tous les utilisateurs de la machine et que le programme soit exécuté avec des privilèges plus haut à chaque nouvelle session. En utilisant la racine HKEY_CURRENT_USER le programme sera persistant uniquement pour l'utilisateur en cours et sera exécuté avec des droits simples.
Image
Nous voici sur la fin de la fonction Init, ici le programme va se charger de se reloger ailleurs via la fonction MoveFileExA et va ensuite se rendre persistant en ajoutant la valeur de registre Microst Update à la clé de registre SOFTWARE\Microsoft\Windows\CurrentVersion\Run via la fonction RegSetValueExA.
On remarque ici que la valeur de registre a pour nom Microsoft Update dans le but de se faire passer pour une action légitime de la part du système lui-même.
Nous voici à nouveau dans le main pour analyser la suite de notre malware:
Image
Nous allons analyser la fonction sub_401C4A que nous renommerons firstCommunication puisqu'il s'agira d'une première connexion
avec le serveur de l'attaquant.
Image
Dans cette fonction firstCommunication nous observons que plusieurs valeurs sont mises en argument dans le formatage d'une chaîne de caractères qui sera push en tant que variable aIdSosSPvSIpSCn. On remarque également que le nombre de valeur est de 7, nous pouvons faire un lien avec les 7 valeurs qui ont été récupérées dans la fonction getInformations vu un peu plus haut. On peut donc supposer que les valeurs envoyées sont :

  • - L'architecture du système hôte
  • - Le nom de l'utilisateur en cours
  • - Le nom de la machine hôte
  • - Des informations sur le système hôte
  • - Le niveau de droit de l'utilisateur (savoir si il s'agit d'un administrateur ou pas)
  • - Des détails sur les volumes disques
  • - Le système d'exploitation de l'hôte

Depuis le début de l'analyse de cette fonction nous parlons de connexion et de valeurs envoyées mais nous n'avons toujours pas vu de requête ou de tentative de connexion. Mais nous y arrivons enfin, juste après à l'appel de la fonction sub_401CC7.
Observons les arguments qui sont push dans cette fonction :
Image
Ici EAX contiendra la taille de la valeur de la variable vu ci-dessus contenant les 7 informations qui seront envoyées. Nous pouvons le savoir grâce à la fonction sub_40226B appelée juste avant qui va copier la variable aIdSosSPvSIpSCn
contenant les informations qui nous intéresse dans un buffer grâce à la fonction wvsprintfA.

Sur le papier la fonction est représentée comme tel :
Image

Et dans notre cas nous avons :
Image
La fonction wvsprintfA retourne un nombre entier (int) comme valeur, il s'agit de la taille du buffer et c'est cette valeur qui sera copiée dans EAX et qui sera finalement push dans la fonction sub_401CC7.D'ailleurs, nous avons également deux variables que nous connaissons très bien qui seront push à l'appel de cette fonction. Ces variables sont :

  • - domaineName : contient la valeur --> "kardon[.]ddns[.]net"
  • - pageName : contient la valeur --> "/kardon/gate.php"

Nous allons maintenant analyser cette fameuse fonction dont voici un premier bout :
Image
Ici on a l'information que l'on va faire des requêtes réseaux puisque ce petit bout de code permet l'initialisation de la DLL Winsock. Cette DLL permet l'envoi et la réception des paquets de données sur des réseaux TCP/IP.
Image
Ensuite nous observons plusieurs choses, tout d'abord la valeur contenu dans domainName va être push dans la fonction gethostbyname pour récupérer des informations comme l'adresse IP et si la valeur de la variable est déjà une adresse IP alors la fonction inet_ntoa va être appelée pour convertir l'adresse IP en ascii exploitable. L'objectif est d'avoir le même type de retour à la sortie de la fonction sub_401A0E. Le retour que nous venons d'obtenir sera push> dans la fonction inet_addr qui va nous permettre de récupérer l'adresse IP compatible avec la structure IN_ADDR. Ensuite un call de la fonction connect se produit.
Voici la partie qui nous intéresse enfin :
Image
Nous savons à présent que des requêtes POST sont envoyées à destination de : hxxp[:]//kardon[.]ddns[.]net/kardon/gate.php et les valeurs envoyées sont les 7 valeurs dont nous avons déjà parlé plus haut.
A la suite de ça nous avons plusieurs valeurs de retour possible en fonction du résultat et en fonction de ce retour nous avons ces différentes suites de codes :
Image
Ici nous avons trois possibilités :

  • - Echec à l'initiation de WSAStartup : retourne la valeur "rqf" (request failed ? maybe ? idk.)
  • - Echec à l'envoi des données : retourne la valeur "rqf"
  • - Succès : ferme la socket et retourne une valeur récupérée par le serveur attaquant (ici on aura compris qu'il s'agit d'un C&C)

Nous voici encore une fois dans le main pour passer à la dernière fonction de ce C&C :
Image
On renomme la dernière fonction sub_401DD2 en CommandAndControl et voici son contenu :
Image
Avant d'attaquer le plus intéressant nous avons le traitement de la donnée qui a été retournée par la précédente fonction et si cette valeur correspond à "notask" ou "rqf" alors un JUMP vers la fonction de retour sera effectué. On rappel qu'à la sortie de cette dernière fonction, la fonction sleep est appelée pour mettre le programme en pause pendant 60s puis revient à l'appel de la fonction firstCommunication (il s'agit là d'un programme qui tourne en boucle).
Dans le cas où la valeur de retour ne serait ni égal à "notask" ni égal à "rqf" le programme va vérifier 3 autres valeurs différentes pour des contextes différents :

  • - Si la valeur vaut 1 on exécutera la fonction qui lui est associée.
  • - Sinon si la valeur vaut 2 on exécutera la fonction qui lui est associée.
  • - Sinon si la valeur vaut 3 on exécutera la fonction qui lui est associée.
  • - Sinon le programme fera un JUMP dans la fonction de retour pour revenir au main

Dans le cas où la valeur est 1 nous avons :
Image
Ici nous avons deux fonctions intéressantes qui sont sub_4015B3 que nous allons renommer downloadInPathAndExec et sub_401CC7.Voici downloadInPathAndExec :
Image
Cette fonction fait 3 choses :

  • - Stocker le chemin du dossier temporaire dans une variable
  • - Télécharger un fichier externe (sûrement un programme malveillant) et le placer dans le dossier temporaire %TEMP%, si on regarde bien avant l'appel à la fonction GetTempPathA on voit l'instruction PUSH EAX, il s'agit là du buffer et on remarque qu'avant l'appel de la fonction URLDownloadToFileA il y a ces instructions : PUSH EAX et PUSH EBP+ARG_0. Ici EAX contient la valeur du buffer c'est-à-dire qu'il contient la valeur de %TEMP% et ici EBP+ARG_0 contient sûrement le nom de l'exécutable. Hypothétiquement c'est comme si nous avions PUSH %TEMP%/ProgramName.
  • - Exécuter le programme téléchargé dans le %TEMP%.

Ensuite la deuxième fonction sub_401CC7 que nous avons renommé sendDataAndRecvWithServer est une fonction qui permet de communiquer avec le serveur attaquant.Nous l'avons déjà analyser plus haut et elle est appelée à ces différents endroits :
Image
Une nouvelle requête est envoyée au serveur attaquant et le programme va vérifier si le retour vaut 2 ou 3. Si la valeur de retour vaut 2 alors on ira à gauche sinon on ira à droite :
Image
Dans le cas où nous allons à gauche (donc si valeur de retour = 2), le programme va appeler la fonction downloadInPathAndExec pour télécharger un programme malveillant dans %TEMP% et l'exécuter. Ensuite le programme fera appel à la fonction sub_4021BE que nous avons renommé goPersistance.
Dans cette fonction on retrouve ceci :
Image
Si le programme a été lancé par l'administrateur alors on ira à gauche sinon on ira à droite. Ce programme permet d'ajouter un moyen de persistance et d'ajouter la clé "Microsoft Update" dans le registre SOFTWARE\Microsoft\Windows\CurrentVersion\Run. Rappelons-nous que cette clé existe déjà et pourtant l'opération est de nouveau exécutée. Nous pouvons supposer que le progamme malveillant qui est téléchargé, pour le cas où la valeur de retour vaut 2, est simplement une mise à jour du programme actuel. De retour à la fonction précédente, si nous regardons à droite pour le cas où la valeur de retour vaut 3, nous avons simplement un appel de la fonction goPersistance.
Dans les deux situations, si la valeur de retour vaut soit 2 soit 3 à la fin nous aurons ceci :
Image
Ce bout de code va faire ce que le programme a déjà fait avant, c'est-à-dire qu'il va envoyer des informations mais cette fois-ci il va en plus quitter le programme juste après.


Conclusion

Comme nous l'avons bien détaillé au-dessus, ce C&C fait plusieurs choses :

  • - Vérifications sur le système hôte pour trouver des traces de programme "anti-malware" (VM, SandBox, AV, etc...)
  • - Déclaration des données permettant la communication (nom de domaine, page)
  • - Récupération d'un ensemble d'informations pour être envoyées au serveur de contrôle, les informations permettent d'établir un profil. Les voici :
    • - L'architecture du système hôte
    • - Le nom de l'utilisateur en cours
    • - Le nom de la machine hôte
    • - Des informations sur le système hôte
    • - Le niveau de droit de l'utilisateur (savoir si il s'agit d'un administrateur ou pas)
    • - Des détails sur les volumes disques
    • - Le système d'exploitation de l'hôte
  • - Mise en persistance du C&C
  • - Premier échange de données avec le serveur de contrôle et récupération d'une valeur de retour qui peut être :
    • - 1
    • - 2
    • - 3
    • - notask
    • - rqf (retourné par le programme si une erreur est constatée lors de la communication avec le serveur)
  • - En fonction de la valeur de retour nous avons plusieurs scénarios possibles :
    • - 1 : télécharge un programme malveillant, l'exécute et renvoi une requête au serveur de contrôle.
    • - 2 : télécharge une mise à jour du programme actuel, le rend persistant de nouveau, renvoi une requête au serveur de contrôle et quitte le programme.
    • - 3 : rend de nouveau le programme en cours persistant, renvoi une requête au serveur de contrôle et quitte le programme.
    • - notask : fait un retour dans le main.
    • - rqf : fait un retour dans le main.
    • - valeur quelconque : fait un retour dans le main.



Il faut savoir qu'à chaque action une requête est envoyée au serveur de contrôle, ce qui permet à l'attaquant d'obtenir le profil de la machine corrompue. Le fait de toujours récupérer le profil permet d'adapter son comportement et apporter une mise à jour au C&C actuellement sur la machine corrompue. A chaque fois que le programme va relancer une persistance il va simplement écraser celle qui existe déjà et avant ça le programme vérifie si l'exécuteur possède les droits administrateurs dans le but de pouvoir se rendre persistant à un niveau plus haut (sur HKEY_LOCAL_MACHINE). Cette élévation de privilège permettra à l'attaquant d'envoyer de plus gros programmes qui seront alors exécuté en tant qu'administrateur car si le C&C est exécuté avec les droits admin alors il pourra exécuter avec des droits admin au moment où il fera appel à la fonction WinExec observée plus haut dans l'analyse.