Charges utiles et balises malveillantes : types de charges utiles malveillantes
Dans le article de blog précédent, nous avons expliqué comment les charges utiles facilitent les communications malveillantes et comment un attaquant peut prendre le contrôle d'un système après avoir exécuté avec succès les charges utiles et les balises. Nous avons utilisé un canal de communication reverse_tcp facilité par la charge utile Meterpreter (issue du Metasploit Framework).
Cet article se concentrera sur une meilleure compréhension des différents types de charges utiles et sur des exemples de techniques de manipulation de la mémoire qu'elles peuvent utiliser.
Malware est devenu de plus en plus sophistiqué en termes de composition et d'exécution, en particulier par rapport à l'époque des virus plus simples, comme le Creeper programme au début des années 70. Pour les acteurs de la menace motivés principalement par des objectifs clandestins, il est généralement prioritaire de rester dans l'ombre pour persister dans un réseau sans être détectés pendant une période prolongée. Par conséquent, ils utiliseront des techniques correspondantes telles que les leurres, le codage, l'obfuscation, le cryptage et le mimétisme pour atteindre le niveau de sécurité opérationnelle souhaité.
Plusieurs formats exécutables sont à la disposition des acteurs de la menace. Le choix de l'attaquant dépend des vecteurs d'attaque initiaux et des actions post-exploitation ultérieures. Voici quelques-unes des Métasploit Formats exécutables et de transformation du Framework.
Comme le montre première partie, la balise ou charge utile est l'implant situé sur une machine ou un réseau victime qui permet à un attaquant d'entrer puis de prendre pied. Il s'agit d'un élément important de l'arsenal des malwares et du cycle de vie global des attaques, car il permet à l'auteur de la menace d'accéder directement à ses activités malveillantes pour poursuivre ses activités malveillantes.
En ce qui concerne la catégorisation générale proprement dite, une charge utile peut être « échelonnée » ou « non échelonnée ». Un acteur de la menace peut choisir l'un plutôt que l'autre en fonction de plusieurs facteurs, dont le principal peut être des considérations de sécurité opérationnelle.
Que sont les charges utiles échelonnées ?
Les charges utiles par étapes décomposent les différentes phases d'une attaque, en utilisant souvent plusieurs phases de charge utile qu'une seule charge utile aurait autrement exécutées. Ces charges utiles sont généralement décomposées en un exécutable « stager » (charge utile initiale ou balise) et un exécutable « stage » (charge utile principale).
Un stager est un petit exécutable qui constitue une charge utile initiale. Il s'agit d'un morceau de code relativement petit qui est exécuté pour préparer une charge utile beaucoup plus grande et plus performante, connue sous le nom de charge utile d'étape. Cela signifie que « le metteur en scène prépare le terrain ». Un stager fait généralement partie d'un code d'exploit lorsque l'entrée initiale exploite une vulnérabilité. Ici, le code d'exploit exploitera avec succès la vulnérabilité cible, puis exécutera le code du stager (charge utile). Le metteur en scène entre alors en action.
La tâche principale du stager est de s'exécuter correctement sans être détecté, de recontacter l'infrastructure de l'attaquant pour télécharger la charge utile principale souhaitée, puis de configurer le système pour exécuter cette charge utile. L'étape téléchargée ou la charge utile principale plus importante peut être constituée d'une ou de plusieurs charges utiles en fonction de la capacité requise par l'attaquant. Une fois le stage téléchargé, le stager passe le contrôle d'exécution pour poursuivre l'activité malveillante.
Dans le cas d'un exploit de vulnérabilité, le programme d'exploitation initial fait quelque chose de similaire pour le stager comme le fait le stager pour la charge utile de l'étage principal, en termes d'allocation des ressources sur le système compromis. Il suivra un schéma similaire à celui-ci :
L'exemple ci-dessous montre une charge utile échelonnée sous forme d'exécutable Windows.
Les charges utiles échelonnées sont adaptées aux scénarios susceptibles de présenter des contraintes liées au système, telles que l'espace disque et mémoire, lors de la livraison et de l'exécution de la charge utile, comme dans le cas du shellcode utilisé pour exploiter une vulnérabilité de débordement de mémoire tampon.
Que sont les charges utiles échelonnées ?
À l'opposé des charges utiles échelonnées, il y a les charges utiles non échelonnées. Les charges utiles échelonnées sont autonomes et généralement beaucoup plus volumineuses que les charges utiles échelonnées. Ils combinent généralement toutes les fonctionnalités requises d'un attaquant dans un seul exécutable.
Ici, il n'est généralement pas nécessaire de disposer d'une charge utile initiale (stager) qui télécharge la charge utile principale (stager). Une fois la charge utile échelonnée exécutée, elle disposera de toutes les fonctionnalités nécessaires pour effectuer des actions malveillantes, telles que l'injection de mémoire, le rappel à l'infrastructure de l'attaquant et la fourniture d'un shell à l'attaquant.
L'exemple ci-dessous montre une charge utile TCP inverse de Meterpreter sans étapes en tant qu'exécutable Windows.
La décision concernant le type de charge utile à utiliser dans le cadre d'une campagne malveillante est connue sous le nom de « considérations de sécurité opérationnelle » pour cet acteur de la menace. Le type d'infrastructure d'attaquant correspondant à la campagne malveillante est en partie influencé par ces considérations.
Charges utiles échelonnées ou non
Les charges utiles échelonnées de Metasploit ont la barre oblique (/) après le mot Meterpreter. La capture d'écran ci-dessous montre des exemples de charges utiles Meterpreter par étapes sous Windows.
Les charges utiles échelonnées utilisent le symbole de soulignement (_) après le mot Meterpreter. La capture d'écran ci-dessous montre des exemples de charges utiles échelonnées de Windows Meterpreter.
Et l'exemple ci-dessous montre les deux catégories de charges utiles.
Les charges utiles Stageless sont autonomes et ne nécessitent pas l'étape supplémentaire d'envoi d'une étape (charge utile principale) à la machine victime une fois que le malware a effectué un rappel vers l'infrastructure de l'attaquant. Notez dans la capture d'écran ci-dessous qu'une fois le gestionnaire TCP inversé démarré, l'étape suivante consiste à ouvrir immédiatement une session Meterpreter Remote Shell sur la machine victime, sans avoir à envoyer de charge utile supplémentaire, telle qu'une étape.
Sur la capture d'écran ci-dessous, nous pouvons voir qu'il existe une étape supplémentaire qui consiste à envoyer le stage une fois que le stager a effectué un rappel à l'infrastructure de l'attaquant : « envoi du stage (175174) au 203.0.113.1 ».
Une autre différence entre le mode échelonné et le mode sans étage réside dans la taille des charges utiles. Dans la capture d'écran ci-dessous, la charge utile échelonnée (meeting_update_stageless.exe) est beaucoup plus importante à 245 Ko que la charge utile initiale par étapes (web1_meeting_update.exe) à 73 Ko.
Qu'est-ce que le shellcode ?
Le Shellcode est un code malveillant qui tente de détourner le flux normal d'un programme en cours d'exécution dans la mémoire de l'ordinateur. Il redirige ensuite le flux afin que le code malveillant soit exécuté, au lieu du programme normal, donnant à l'attaquant un shell ou un accès pratique. Il s'agit souvent de balises ou de charges utiles sous la forme d'un code de programmation de bas niveau ou d'un code machine associé à un exploit. Les exploits sont des éléments de code de bas niveau ou natifs qui permettent d'exploiter avec succès une vulnérabilité.
Les vulnérabilités exploitées impliquent souvent un dépassement de la mémoire tampon de la mémoire d'une application lorsque l'attaquant a dépassé la mémoire allouée pour rediriger le flux normal du programme. Un exploit réussi entraînera alors l'exécution d'une charge utile, qui est le malware.
Dans sa forme la plus pure, le Shellcode sera un code natif ou un code d'assemblage couramment utilisé dans les exploits liés à la mémoire.
L'exemple ci-dessous montre le shellcode Powershell (ps1).
Cet exemple particulier utilise un Bibliothèque de liens dynamiques Windows (DLL) injectée en mémoire via un chargeur réfléchissant. Le shellcode est généré sous forme alphanumérique. Une fois exécuté avec succès, il peut se reconnecter à l'attaquant via une session TCP DNS inversée générée à partir du Metasploit Framework.
Le choix du mécanisme de diffusion, du type d'exploit et du système cible vulnérable déterminent le choix de la balise ou de la charge utile liée à l'attaque. L'exploit est utilisé pour tirer parti d'une application vulnérable avant d'accéder au système d'exploitation sous-jacent. Dans ce cas, un code spécifique pour l'application correspondante peut être utilisé (par exemple, PHP ou ASP pour les applications frontales de serveur Web).
Caractéristiques du Shellcode
Certaines considérations et caractéristiques importantes doivent être prises en compte pour garantir une exécution réussie du Shellcode et maintenir une sécurité opérationnelle élevée.
Le code doit :
- Disposez de toutes les instructions nécessaires pour exécuter le shell souhaité tout en étant de taille relativement petite.
- Soyez « indépendant de la position » en mémoire : c'est crucial car il est souvent impossible de savoir à l'avance où il sera chargé dans la mémoire du processus vulnérable cible.
- Ne rien contenir qui puisse provoquer des erreurs potentielles ou provoquer le blocage de l'ensemble du processus, par exemple en raison de caractères nuls (0x00).
- Être capable de s'appuyer sur une allocation de mémoire existante à l'aide de certaines techniques d'injection : injection de code ou injection par réflexion.
À partir de ce moment, l'attaquant devra sélectionner le type d'exécutable post-exploit approprié à exécuter sur le système cible, tel que EXE ou DLL pour Windows, ELF pour Linux et APK pour Android. Là encore, les techniques de post-exploitation utilisant uniquement la mémoire sont préférées pour améliorer la sécurité opérationnelle.
Qu'est-ce que l'injection de code et l'injection de DLL ?
L'injection de DLL est le processus qui consiste à exécuter du code (DLL) dans le contexte d'un autre processus. Les charges utiles de Meterpreter utilisent des techniques d'injection de DLL pour des mécanismes de furtivité et d'évasion.
Sous Windows, une bibliothèque de liens dynamiques ou DLL (« bibliothèque partagée » sous Linux) est un morceau de code stocké sous forme de fichier de bibliothèque partagé. Cela signifie qu'il peut être utilisé par différents programmes informatiques au fur et à mesure de leurs besoins. Le système d'exploitation (dans ce cas, Windows) gère l'écriture et le chargement de la bibliothèque, ce qui se fait au moment de l'exécution. Un programme peut simplement appeler ou référencer le fichier DLL requis pour utiliser le code qu'il contient.
Ceci est utile pour les programmeurs car ils n'écrivent le code qu'une seule fois, le compilent et le stockent sous forme de bibliothèque partagée ou de DLL, puis l'utilisent chaque fois que nécessaire et pour plusieurs programmes.
La principale différence entre une DLL et un fichier EXE est qu'une DLL ne peut pas s'exécuter indépendamment. Il a besoin d'un programme tel qu'un EXE pour l'appeler ou le référencer, puis l'exécuter. L'exemple suivant montre les fichiers DLL d'un système d'exploitation Windows, qui sont généralement stockés dans le dossier C:\Windows \ WinSxS (WinSxS signifie Windows Side-by-Side).
Les fonctionnalités des DLL les rendent également très utiles pour les acteurs de la menace. L'injection de code au niveau de base implique une tentative par un processus (malveillant) d'attacher (ou d'obtenir un identifiant) à un processus distant (processus victime). Il alloue ensuite suffisamment de mémoire ou modifie les autorisations de page dans le processus victime pour exécuter un nouveau code tel qu'une DLL, puis copie (injecte) le code malveillant de la DLL dans l'espace mémoire du nouveau processus victime ou déjà en cours d'exécution.
Un nouveau thread, qui permet aux processus d'exécuter des tâches spécifiques, est ensuite démarré dans le processus victime pour exécuter les instructions contenues dans le code injecté ou la DLL.
Un thread partage le même espace mémoire que le processus qui l'a démarré, alors que les différents processus ont des espaces mémoire alloués distincts, en particulier dans les cas où ils ne partagent aucune variable. Ceci est imposé par le système d'exploitation. Cependant, les systèmes d'exploitation fournissent des mécanismes permettant aux processus de communiquer lorsque cela est nécessaire à l'aide de la communication interprocessus (IPC), tels que les tuyaux (nommés ou anonymes), les sockets, les sémaphores, la mémoire partagée et les files d'attente de messages.
Dans les systèmes d'exploitation Windows, l'injection de code implique l'utilisation d'API et de fonctions Windows légitimes à des fins malveillantes. Par exemple :
- Processus ouvert est utilisé pour maîtriser un processus,
- Allocex virtuel facilite alors l'allocation de suffisamment de mémoire dans ce processus distant ou,
- VirtualProtectex peut être utilisé pour modifier les autorisations de mémoire (page), puis
- Mémoire du processus d'écriture écrit le code malveillant, tel qu'une DLL, dans le processus victime.
- CreateRemoteThread, RTLCreateUserThread ou NTCreateThreadEx est utilisé pour créer un nouveau thread (c'est ainsi que les processus exécutent des tâches spécifiques) et exécuter la fonctionnalité malveillante, telle que le vol d'informations d'identification ou l'exécution d'un rançongiciel.
Le chargement d'une DLL dans Windows nécessite l'appel des fonctions LoadLibraryA ou LoadLibraryExa, qui font partie de libloaderapi.h. Ces fonctions, comme le dit Microsoft, « chargent le module spécifié dans l'espace d'adressage du processus appelant ». L'utilisation de LoadLibrary pour charger une DLL signifie que les DLL doivent être chargées à partir du disque.
Cependant, en utilisant la technique d'injection de DLL réfléchissante, une DLL peut être chargée directement depuis la mémoire, une fonctionnalité qui n'est pas actuellement proposée par LoadLibrary. Un acteur malveillant peut utiliser l'injection réflexive de DLL pour charger automatiquement son code malveillant entièrement en mémoire sans avoir à invoquer le chargeur Windows natif sur le disque. Ici, ils utilisent un chargeur personnalisé au lieu de Windows LoadLibrary.
Les attaquants peuvent également utiliser d'autres techniques d'injection et de manipulation des processus, telles que :
- Procédé de creusement — Où un logiciel malveillant lance le processus d'une victime dans un état suspendu. Il vide ensuite la mémoire pour faire de la place pour le nouveau code, modifie les autorisations de page, injecte du code malveillant et reprend le processus d'exécution du code malveillant injecté.
- Chargement latéral des DLL — Lorsqu'un programme Windows vulnérable légitime et souvent plus ancien (processus victime) est contraint de charger une DLL malveillante, qui est délibérément nommée comme une DLL légitime attendue par la victime et placée dans le même répertoire (côte à côte) que le programme vulnérable. Le processus du programme victime cherchera d'abord dans son dossier immédiat pour localiser la DLL malveillante renommée (usurpée d'identité). Cette technique tire parti de l'ordre de recherche des DLL utilisé par le chargeur Windows pour réussir.
Ces techniques tentent de donner l'impression que les activités malveillantes sont légitimes, évitant ainsi d'être détectées et de persister sur un système compromis.
À partir des techniques de manipulation des processus décrites dans première partie de cette série, nous pouvons voir ci-dessous que la migration du fichier malveillant web1_meeting_update.exe d'origine impliquait une injection de code.
Dans cet exemple, la charge utile malveillante a lancé (généré) un tout nouveau processus notepad.exe en tant que processus victime souhaité pour injecter du code. Le processus malveillant d'origine (PID 2472) est ensuite injecté ou migré vers le nouveau processus victime notepad.exe (PID 1768).
Notepad.exe est un processus Microsoft fiable, ce qui permet à l'attaquant de masquer le processus d'apparence malveillante d'origine en un processus plus fiable. Notepad.exe est un éditeur de texte Windows de base qui n'a pas besoin d'appeler (référencer) aucune API, fonction ou DLL Windows requise pour la connexion réseau. Dans notre exemple, le processus malveillant a exécuté.
Une analyse dynamique est nécessaire pour détecter l'injection qui se produit en mémoire. Cartographie des dépendances des applications est également nécessaire pour détecter les communications réseau suspectes de l'éditeur de texte, en l'occurrence le processus notepad.exe, établissant une connexion réseau.
Conclusion
Dans le prolongement de première partie Dans cette série de blogs, nous avons examiné certaines catégories et types de charges utiles qu'un acteur de la menace peut utiliser et les raisons pour lesquelles il peut décider d'utiliser un type plutôt qu'un autre.
La plupart des attaquants mettent tout en œuvre pour s'assurer que leur entrée initiale est réussie, qu'ils maintiennent leur persistance et qu'ils évitent d'être détectés. Nous avons constaté jusqu'à présent que la combinaison d'outils, de techniques et de procédures signifie qu'une combinaison tout aussi performante d'outils et de procédures de sécurité est nécessaire pour empêcher une attaque réussie, ou plus susceptible de supposer une violation et évitez qu'un cyberincident initial ne devienne une violation majeure.
Dans la dernière partie de cette série, nous aborderons d'autres techniques et capacités et, surtout, explorerons l'analyse et l'atténuation.