Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
Inline-Execute-PE — Exécuter des exécutables Windows non gérés dans les Beacons CobaltStrike | Kitploit
Outils/GitHubGitHub/octoberfest7/inline-execute-pe
Escalade de Privilèges
GitHuboctoberfest7/inline-execute-pe

Inline-Execute-PE

Exécuter des exécutables Windows non gérés dans les Beacons CobaltStrike

Voir le dépôt
723103il y a 3 ansVérifié par Kitploit

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

Inline-Execute-PE

AVERTISSEMENT :

Ce projet est complexe et ne pas comprendre son fonctionnement ni le tester correctement peut entraîner le crash des Beacons et la perte d'accès !

Je vous encourage vivement à lire toute la documentation jusqu'à la section « Design Considerations and Commentary » !

Introduction

Inline-Execute-PE est un ensemble de fichiers objet Beacon (BOF) et d'un script Aggressor pour CobaltStrike qui permet aux opérateurs de charger des exécutables Windows non managés dans la mémoire du Beacon et de les exécuter, en récupérant la sortie et en l'affichant dans la console Beacon.

Cela permet aux opérateurs d'utiliser de nombreux outils tiers (Mimikatz, Dsquery, outils Sysinternals, etc.) sans avoir à les écrire sur le disque, à les reformater en code indépendant de la position à l'aide d'un outil comme Donut, ou à créer un nouveau processus pour les exécuter.

Ces exécutables sont mappés dans la mémoire du Beacon afin de pouvoir être exécutés à plusieurs reprises sans avoir à les envoyer sur le réseau, à allouer de la nouvelle mémoire et à créer un nouveau processus conhost.exe à chaque fois.

Les exécutables chargés dans les Beacons sont accessibles et peuvent être exécutés par tous les clients CobaltStrike connectés au serveur d'équipe CobaltStrike.

Inline-Execute-PE a été conçu autour des Beacons x64 et des exécutables Windows x64 C ou C++ compilés avec Mingw ou Visual Studio. Ce projet ne prend pas en charge les exécutables x86 ni les exécutables x64 écrits dans un autre langage ou compilés avec un autre compilateur.

Configuration

Clonez le dépôt et exécutez éventuellement make pour recompiler les BOF.

Chargez Inline-Execute-PE.cna dans le client CobaltStrike. Assurez-vous que le répertoire à partir duquel CobaltStrike s'exécute est inscriptible par votre utilisateur ; Inline-Execute-PE y crée un fichier texte (petable.txt) afin de garantir la disponibilité des données nécessaires au fonctionnement d'Inline-Execute-PE.

Commandes

Inline-Execute-PE comprend 3 commandes orientées cible qui exécutent des BOF, et 3 commandes internes qui manipulent la structure de données du projet :

Commandes orientées cible :

  1. peload
  2. perun
  3. peunload

Structure de données interne :

  1. petable
  2. peconfig
  3. pebroadcast

peload

peload est le point de départ d'Inline-Execute-PE. Cette commande est utilisée pour charger un PE dans la mémoire du Beacon. Elle effectue les actions principales suivantes :

  1. Envoie le PE spécifié sur le réseau vers le Beacon OU envoie le nom du PE à lire depuis le disque sur la machine cible
  2. Crée une structure dans la mémoire du Beacon pour contenir divers pointeurs et handles nécessaires à Inline-Execute-PE tout au long de son cycle de vie
  3. Alloue de la mémoire dans le Beacon et y écrit le PE avec une protection RW
  4. Chiffre le PE en mémoire par XOR en utilisant une clé spécifiée par l'utilisateur
  5. Alloue un autre bloc de mémoire et y copie le PE chiffré par XOR. Cela est nécessaire pour pouvoir « restaurer » le PE pour les exécutions ultérieures
  6. Crée un processus fils conhost.exe sous le Beacon afin d'initialiser stdin/stdout/stderr
  7. Redirige stdout et stderr vers un tube anonyme afin que la sortie du PE puisse être capturée

perun

perun est la deuxième étape d'Inline-Execute-PE. Elle effectue les actions principales suivantes :

  1. Envoie les arguments de ligne de commande sur le réseau vers le Beacon
  2. Déchiffre le PE en mémoire par XOR
  3. Corrige la table d'importation du PE, en hookant certaines API liées aux arguments de ligne de commande et à la sortie des processus
  4. Change la protection mémoire du PE en RWX
  5. Exécute le PE dans son propre thread
  6. Capture la sortie du PE et la renvoie à CobaltStrike
  7. Rétablit la protection mémoire du PE en RW
  8. Écrase le PE en mémoire avec la copie chiffrée par XOR effectuée lors de peload

peunload

peunload est appelé pour supprimer le PE de la mémoire du Beacon lorsque l'opérateur en a terminé ou souhaite charger un autre PE. Elle effectue les actions principales suivantes :

  1. Ferme les handles et les pointeurs de fichier créés lors de peload
  2. Termine le processus conhost.exe créé lors de peload
  3. Remet à zéro puis libère les deux copies du PE en mémoire
  4. Tente de décharger les éventuelles DLL chargées par le PE dans le processus Beacon (optionnel)

petable

petable est utilisé pour afficher des informations sur tous les PE actuellement chargés dans les Beacons.

Chaque client CobaltStrike a son propre petable ; Inline-Execute-PE fait de gros efforts pour assurer la synchronisation de ses données entre tous les clients CobaltStrike connectés, afin que les PE puissent être utilisés par tous les opérateurs. Pour plus d'informations, voir « Design Considerations and Commentary ».

image

peconfig

peconfig est utilisé pour configurer les options relatives au fonctionnement d'Inline-Execute-PE. Les deux options actuellement modifiables sont :

  1. Timeout. Cela détermine combien de temps perun attendra la fin de l'exécution du PE avant de le terminer. Cela existe comme mesure de sécurité au cas où des arguments incorrects sont donnés à un PE qui l'empêcheraient de revenir/terminer son exécution. Ce paramètre est de 60 secondes par défaut mais peut être modifié pour prendre en charge des PE de plus longue durée.
  2. UnloadLibraries. Cette option contrôle si peunload essaiera de libérer les DLL du processus Beacon qui ont été chargées par le PE. Elle est définie sur TRUE par défaut. Certains PE causent des problèmes lorsque les DLL sont déchargées du processus Beacon et peuvent provoquer un crash du Beacon, auquel cas il est préférable de laisser toutes les DLL chargées par le PE dans le processus Beacon. Cela a été observé lors de l'utilisation de powershell.exe (peut-être en raison du chargement du CLR .Net dans le processus Beacon).

pebroadcast

pebroadcast peut être utilisé pour diffuser manuellement le contenu du petable d'un client à tous les autres clients CobaltStrike connectés.

Tous les autres clients CobaltStrike mettront à jour leur petable avec les données diffusées. Cela ne devrait jamais vraiment être nécessaire, mais la fonctionnalité existe au cas où.

Utilisation

Utilisez peload pour charger un PE dans la mémoire du Beacon
image

Sinon, s'il y a un PE sur la machine cible que vous souhaitez utiliser sans créer de nouveau processus, fournissez le chemin et l'option --local
image

Appelez perun en passant les arguments au PE chargé
image

Les guillemets doubles dans les arguments doivent être échappés avec des barres obliques inverses
image

Si vous avez identifié qu'un PE cause des problèmes lors de la tentative de libération des DLL pendant le déchargement, utilisez peconfig pour définir unloadlibraries sur false
image

Une fois que vous avez fini d'utiliser un PE, appelez peunload pour le nettoyer du Beacon
image

Un autre PE peut maintenant être chargé dans le Beacon
image

Délai d'attente perun

Vous devez être prudent avec les arguments de ligne de commande que vous passez au PE ; certains PE planteront carrément si des arguments incorrects sont donnés, tandis que d'autres s'exécuteront indéfiniment, empêchant le Beacon de rappeler alors que le processus est toujours en cours.

Cela peut être observé avec Mimikatz.exe lorsque 'exit' n'est pas spécifié à la fin de la liste des arguments
image

...

image

Inline-Execute-PE terminera le thread du PE en cours d'exécution après que le délai d'attente spécifié a été atteint. Cela permet au Beacon de reprendre les communications normales (le Beacon ne rappelle pas tant que le BOF perun n'a pas terminé son exécution). Bien que les commandes CobaltStrike normales et autres BOF puissent encore être utilisés dans ce Beacon, Inline-Execute-PE est maintenant désactivé ; lorsqu'un PE en cours d'exécution est terminé de cette manière, cela semble casser stdout et stderr dans le processus Beacon, et les PE chargés par la suite ne fonctionnent pas correctement.

Le PE peut (et devrait) toujours être déchargé de la mémoire du Beacon, cependant regarder petable montrera que ce Beacon ne peut plus avoir de PE supplémentaires chargés. image

Il est impératif de tester les PE que vous souhaitez exécuter avec Inline-Execute-PE, et d'être prudent lorsque vous donnez des arguments de ligne de commande à perun. Certains PE sont plus indulgents que d'autres.

Astuces, trucs et observations

Voici, dans le désordre, quelques observations faites lors des tests et du développement concernant certains PE que les utilisateurs pourraient vouloir charger dans le Beacon.

  1. L'utilisation de peunload sur Powershell.exe fera généralement planter Beacon lorsque UnloadLibraries est TRUE ; je pense que cela est lié au chargement du CLR par Powershell.exe.
  2. Cmd.exe plantera Beacon sauf si '/c' est utilisé comme premier argument. Ex. : 'perun /c cd' est OK, 'perun cd' ne l'est pas.
  3. Mimikatz.exe plantera Beacon s'il a été chargé, utilisé, déchargé, puis rechargé SI UnloadLibraries était TRUE lors du premier peunload.
  4. Certains PE sont programmés pour afficher leur menu d'aide lorsqu'ils se terminent ; ceux-ci ne seront pas affichés car les appels à ExitProcess et exit() et autres sont hookés et redirigés vers ExitThread afin que le PE ne provoque pas la sortie de notre processus Beacon.
  5. Certains PE ne sont pas très bons pour libérer de la mémoire lorsqu'ils ont terminé et comptent sur le fait que la mémoire soit libérée lorsque le processus se termine ; parce que le PE s'exécute à l'intérieur du processus Beacon (donc le processus ne se termine pas lorsque le PE a fini), le Beacon peut avoir tendance à gonfler à mesure que davantage de PE sont chargés et exécutés à l'intérieur. Observez cela lors des tests à l'aide de quelque chose comme Process Explorer et soyez-en conscient pendant les opérations.
  6. Psexec de Sysinternals ne semble pas fonctionner ; bien qu'il s'exécute, il se plaint que le handle vers la machine distante est invalide. En pratique, si l'on voulait utiliser quelque chose comme psexec, il serait probablement préférable de le faire via le proxy socks de CobaltStrike et une version psexec sur une machine d'attaque.
  7. Créer un nouveau beacon à utiliser avec Inline-Execute-PE n'est probablement pas une mauvaise idée, surtout lorsque vous commencez à comprendre comment différents PE interagissent et fonctionnent au sein du framework. Deux, c'est un, un, c'est zéro.
  8. S'il y a un LOLBIN que vous souhaitez utiliser sans la télémétrie de la création d'un nouveau processus, utilisez l'option --local avec peload et lisez-le depuis le disque sur le système cible. Cela peut également être utile pour éviter les problèmes de version.

IOC et AV/EDR

Les IOC associés à Inline-Execute-PE incluent, sans s'y limiter :

  1. Allocation de mémoire à l'aide de VirtualAlloc
  2. Changement des protections mémoire sur la mémoire allouée entre RW et RWX
  3. Création d'un processus fils conhost.exe
  4. Chargement de DLL nécessaires au PE mappé
  5. Toute action effectuée par le PE lui-même ; par exemple, Mimikatz touchant LSASS

AV/EDR

Je n'ai pas effectué de test complet contre un EDR pendant le développement, en partie par paresse et en partie par manque de disponibilité d'un environnement de test. Il a cependant été testé contre la dernière version à jour de Windows Defender (qui est, selon mon expérience, un assez bon produit antivirus).

Mimikatz.exe est probablement le PE le plus suspect et le plus connu qui vient à l'esprit comme candidat à l'utilisation avec Inline-Execute-PE. J'ai constaté que la capacité de Windows Defender à détecter Mimikatz s'exécutant via Inline-Execute-PE dépendait du processus dans lequel Beacon s'exécutait.

Un beacon s'exécutant dans un exécutable autonome (pensez à beacon.exe avec artifact kit pour qu'il puisse s'exécuter et fonctionner normalement au-delà de Defender) sera détecté lors de l'utilisation de Mimikatz.exe avec Inline-Execute-PE.

Un beacon s'exécutant dans un processus Windows (injecté dans Explorer.exe, notepad.exe, etc., ou DLL sideloadée dans un processus légitime) ne sera PAS détecté lors de l'utilisation de Mimikatz.exe avec Inline-Execute-PE.

En ce qui concerne les EDR qui effectuent du hooking en espace utilisateur, comme je l'ai dit, je n'ai pas testé mais j'ai les réflexions générales suivantes :

Étant donné que le PE s'exécute à l'intérieur du processus Beacon, dans lequel vous avez probablement déjà déhooké/rafraîchi NTDLL, je pense que vous ne devriez pas avoir trop de problèmes avec les appels API effectués par le PE qui seraient signalés. Les mêmes problèmes concernant ce que le PE fait réellement (toucher des processus, modifier des clés de registre, etc.) s'appliquent toujours.

Considérations de conception et commentaires

Il y a quelques mois, je suis tombé sur RunPE-In-Memory et j'ai eu l'idée d'essayer de le convertir en BOF pour CobaltStrike. Le chemin qui a suivi a été beaucoup plus complexe et a pris beaucoup plus de temps que prévu. Ce projet a été particulièrement difficile car il ne s'agit pas d'un outil autonome en soi, mais d'un outil utilisé pour exécuter d'autres outils. Cela nécessite une grande flexibilité et des efforts pour assurer la compatibilité avec un large éventail de PE et toutes les différentes façons dont ces PE peuvent accomplir la même tâche (obtenir des arguments, se terminer, etc.).

Au départ, Inline-Execute-PE était conçu comme un BOF tout-en-un, chargé de charger, exécuter et libérer un PE dans un Beacon. Environ 3 semaines après le début du projet, alors que j'avais une POC terminée à ~75 %, j'ai trouvé Pezor qui était sorti il y a environ 1,5 an et faisait déjà presque tout ce que j'essayais de faire ; la différence majeure étant que Pezor appelait Donut en coulisse pour transformer le PE en shellcode, plutôt que de mapper manuellement le PE original en mémoire.

Cette découverte a été la bienvenue d'un côté et décevante de l'autre ; c'était phénoménal d'avoir un projet mature duquel s'inspirer et qui m'a aidé sur certains points bloquants dans mon code, mais décourageant car j'avais effectivement réinventé la roue sans le savoir. Après avoir lu sur Pezor et réfléchi à sa conception, à certaines questions liées au tradecraft et aux besoins opérationnels de mon organisation, j'ai modifié le cours d'Inline-Execute-PE pour en arriver à ce que vous voyez aujourd'hui. Cette décision a été motivée par plusieurs facteurs qui seront discutés ci-dessous, ainsi que certains choix de conception plus curieux qui ont pu soulever des sourcils chez ceux qui ont lu jusqu'ici.

Inline-Execute-Pe vs Pezor

En examinant mon expérience opérationnelle, j'ai rencontré de multiples cas et outils où j'avais besoin d'exécuter l'outil à plusieurs reprises ; avec Pezor, un opérateur doit envoyer à plusieurs reprises le PE sur le réseau, créer un conhost.exe, allouer de la nouvelle mémoire dans Beacon, etc., ce qui m'a semblé potentiellement indésirable du point de vue AV/EDR. Ce raisonnement m'a conduit à l'idée de « charger » un PE dans Beacon, de la même manière que l'on peut charger un .PS1 dans Beacon pour une utilisation répétée. Le conhost.exe est créé lorsque le PE est chargé pour la première fois et persiste tant que le PE est chargé en mémoire ; de même, de la mémoire est allouée pour le PE une fois lors de son premier chargement, et bien sûr vous évitez d'avoir à envoyer le PE sur le réseau à chaque fois que vous souhaitez l'utiliser. Le modèle adopté par Inline-Execute-PE n'est pas sans défauts, que j'ai essayé de résoudre avec plus ou moins de succès.

Deux copies du PE

Un choix de conception qui devrait sauter aux yeux est le fait qu'Inline-Execute-PE mappe le PE dans Beacon DEUX FOIS. Ce n'est certainement pas souhaitable ni un choix que j'ai fait volontairement, mais il est né de la nécessité. Comme mentionné précédemment, Inline-Execute-PE doit hooker plusieurs fonctions liées aux arguments de ligne de commande dans le PE. Parce que le PE mappé s'exécute à l'intérieur du processus Beacon, le PE tentera d'utiliser les arguments de ligne de commande spécifiés dans la section PROCESS_PARAMETERS du PEB ; pour contourner cela, lorsque le PE appelle l'une des diverses fonctions qui récupèrent les arguments de ligne de commande, nous devons diriger le PE vers nos propres fonctions personnalisées où nous pouvons fournir les arguments souhaités tels qu'ils sont passés depuis CobaltStrike via perun.

Cela fonctionne bien, mais pendant le développement, j'ai remarqué quelque chose d'étrange avec plusieurs PE différents. La première fois que le PE était exécuté, la fonction personnalisée que nous avions fournie à l'IAT du PE était appelée correctement, mais toutes les fois suivantes où le PE était exécuté avec des arguments différents, le PE n'appelait pas la fonction personnalisée et ne recevait donc pas les arguments passés depuis CobaltStrike. Je ne suis pas sûr de ce qui se passe réellement sous le capot, mais je suis amené à croire qu'après avoir été exécuté une fois, le PE copie les arguments de ligne de commande quelque part en mémoire, et lors des exécutions suivantes, il regarde d'abord cet emplacement mémoire avant d'appeler les fonctions hookées pour récupérer les arguments de ligne de commande comme il l'a fait la première fois. J'ai corroboré cette théorie en récupérant l'emplacement mémoire où résidait un pointeur vers un autre pointeur vers le tableau de pointeurs contenant les arguments, et en modifiant manuellement cet emplacement mémoire pour contenir le pointeur approprié à chaque exécution. Cela a fonctionné pour les fonctions __getmainargs et __wgetmainargs, mais d'autres PE appellent des fonctions alternatives comme __p___argv et __p___argc pour lesquelles cette méthode n'a pas fonctionné.

Afin de pouvoir « réinitialiser » le PE dans un état où il appellerait réellement les fonctions hookées pour récupérer les arguments, j'ai eu recours à la création d'une deuxième copie du PE en mémoire pendant peload. Cette copie est également chiffrée par XOR et reste avec des protections RX pendant toute la durée de vie d'Inline-Execute-PE, servant simplement à écraser la copie du PE qui est réellement exécutée via perun. Comme mentionné, ce n'est pas une solution parfaite, mais c'est une solution globale qui couvre tous les PE sans avoir à se perdre dans les détails en essayant de trouver une solution pour tous les différents PE existants et les différentes API qu'ils utilisent.

Conhost.exe

Alors que l'un des principaux arguments de vente d'Inline-Execute-PE est que vous pouvez exécuter des outils sans créer de nouveaux processus, c'est un coup dur de devoir... créer un nouveau processus (conhost.exe) pour y parvenir. Cette exigence vient du fait que les flux standard (stdin/stdout/stderr) ne sont pas initialisés dans les programmes Windows à moins qu'une console ne soit présente. Dans notre cas, nous n'avons pas du tout besoin de la console ; les flux standard sont redirigés vers un tube anonyme et capturés de cette manière, mais sans le conhost, les flux ne sont pas initialisés et ne peuvent pas être redirigés.

Inline-Execute-PE aborde le problème conhost de la même manière que Pezor : il appelle AllocConsole puis immédiatement après la cache de la vue en utilisant ShowWindow. Sur une VM Windows 11 avec 8 Go de RAM, je ne vois jamais la fenêtre de la console clignoter puis disparaître, mais les résultats peuvent varier selon le système cible.

J'ai parlé à un développeur qui travaille sur un C2 commercial très avancé qui a récemment sorti un équivalent natif (ok, une version beaucoup plus avancée) d'Inline-Execute-PE, et il m'a dit qu'ils avaient réussi à éviter de créer un conhost.exe en « faisant croire à Windows qu'il avait une console ». Avec cette information, j'ai passé environ une semaine à parcourir Internet à la recherche de documentation sur la façon dont les programmes Windows interagissent avec conhost, en essayant de tracer les appels API associés aux fonctions d'écriture et à la console dans WinDBG, et même en examinant le code source de Windows Terminal qui est étonnamment disponible sur Github. Bien que j'aie beaucoup appris sur le PEB et les choses liées aux flux standard, je suis ressorti de cette recherche les mains vides. Je soupçonne que la voie à suivre pourrait impliquer de patcher certaines fonctions liées à la console dans kernel32, mais je n'en sais rien. Honnêtement, je suis assez déçu de ne pas avoir trouvé de solution ici, mais étant autodidacte et seulement quelques années dans ma carrière, c'est probablement à prévoir.### Timeout et sauvetage du PE Tous ceux qui ont déjà essayé d'écrire un BOF savent que malgré tous les avantages qu'ils apportent, un grand danger réside dans le fait qu'une erreur ou un crash dans votre BOF peut et va tuer votre Beacon. Le danger est amplifié dans ce projet par la nature du contrôle que les utilisateurs ont sur les données transmises à Inline-Execute-PE et par le peu de mesures de sécurité que je, en tant que développeur, peux facilement ou fiabillement mettre en place. Les utilisateurs pourraient par exemple faire crasher leur Beacon en chargeant un PE x86 dans un Beacon x64, ou bien plus couramment en passant des arguments incorrects au PE mappé, comme je l'ai mentionné plus tôt. Bien que je ne puisse pas empêcher les utilisateurs de planter leurs Beacon avec de mauvais arguments pour leurs PE, je peux essayer de sauver leur Beacon en cas de PE qui tourne indéfiniment, comme dans le cas de Mimikatz lorsque 'exit' n'est pas spécifié.

Idéalement, je pourrais arrêter l'exécution du PE, permettant au Beacon de reprendre ses fonctions normales, puis laisser immédiatement l'utilisateur réessayer avec les arguments (espérons-le) corrects cette fois-ci. En pratique, j'ai constaté que la terminaison du PE semble casser les FILE* associés à stdout/stderr, et même décharger complètement le PE puis le recharger à nouveau ne résout pas ce problème ; ils sont cassés à l'échelle du processus.

Pour terminer un PE qui continue de s'exécuter au-delà de l'option 'timeout', TerminateThread est appelée sur le handle retourné par CreateThread. Cela ne permet pas au thread de se terminer proprement, donc il est logique que certaines choses puissent casser. J'ai essayé d'atténuer cela en implémentant le détournement de thread, avec pour objectif de suspendre le thread du PE et de rediriger son exécution vers l'API ExitThread(). L'espoir était que si c'était le thread qui démarrait les procédures de sortie (par opposition à être terminé de force de l'extérieur), cela pourrait permettre à stdout/stderr de continuer à fonctionner, mais j'ai finalement eu le même problème (ainsi que l'incapacité de suspendre le thread du PE dans le cas de Mimikatz).

Incapable d'atténuer ce problème, j'ai finalement choisi d'empêcher simplement les utilisateurs de continuer à exécuter le PE ou de charger d'autres PE dans le Beacon affecté (ce qui entraînerait un crash). C'est un autre cas où Inline-Execute-PE n'atteint pas le niveau que j'aurais souhaité, mais je me suis contenté du fait que l'Opérateur aurait au moins encore son Beacon et pourrait l'utiliser pour des fonctionnalités normales.

Structure de données d'Inline-Execute-PE

L'un des défis de ce projet était d'assurer la disponibilité des PE chargés dans les Beacons à tous les Clients CobaltStrike connectés au Team Server. Les données d'Inline-Execute-PE sont stockées dans des structures créées par Inline-Execute-PE.cna, qui doivent être chargées dans chaque Client souhaitant utiliser l'outil ; par conséquent, ces structures de données résident dans chaque Client, et non sur le Team Server. Si ces données vivaient dans un seul emplacement central (TS), il serait trivial de les récupérer depuis chaque Client et tout cela ne serait pas un problème ; si l'équipe CobaltStrike intégrait formellement une capacité comme Inline-Execute-PE dans CobaltStrike, je suis certain que ce serait la direction qu'ils prendraient. Mais comme il s'agit d'un ajout communautaire, nous faisons avec ce que nous avons.

Il y a quelques scénarios différents dont nous devons nous préoccuper pour garantir que chaque Client CobaltStrike dispose des données les plus récentes et précises concernant les PE chargés dans les Beacons :

  1. Nouveaux Clients se connectant au TS et ayant besoin de la petable actuelle
  2. Cas où un seul Client est connecté au TS et redémarre CobaltStrike (perdant ainsi la petable stockée dans la mémoire du Client)
  3. Client A effectuant une modification des données d'Inline-Execute-PE qui doit être communiquée au Client B

Une approche à plusieurs volets a été adoptée pour répondre à ces scénarios. Pour gérer le cas où un seul Client CobaltStrike est connecté au TS (et est donc la seule entité à disposer des données de la petable), chaque fois que le Client modifie la petable (peload, peconfig, peunload, etc.), il écrit également le contenu de sa petable dans un fichier texte local situé dans le répertoire CobaltStrike. Si le Client se ferme/redémarre, ou lorsque Inline-Execute-PE.cna est rechargé, il tentera d'abord de lire le fichier local petable.txt afin de peupler sa petable en mémoire.

Lorsque plusieurs Clients sont connectés à un TS et qu'un nouveau Client rejoint (comme indiqué dans le Journal des événements), chaque Client récupère une liste de tous les utilisateurs connectés au TS et la trie par ordre alphabétique. Le Client qui est le premier sur cette liste est sélectionné comme Client « Broadcast », et après avoir attendu 5 secondes (pour permettre au nouveau Client de s'initialiser et de lire son fichier local petable.txt), il enverra des messages (Actions) dans le Journal des événements pour chaque entrée de sa petable. Tous les clients (hormis celui qui diffuse) liront ces messages et mettront à jour leurs petables avec les informations diffusées ; cela inclut la mise à jour des entrées existantes ainsi que l'ajout de toutes les entrées supplémentaires que leurs petables respectives ne contiennent pas.

Les opérations normales impliquant Inline-Execute-PE reposent également sur l'envoi de messages dans le Journal des événements. Lorsque le Client A exécute peload, un message est diffusé contenant toutes les informations pertinentes de la petable ; TOUS les clients mettent à jour leurs petables respectives en analysant ces messages diffusés du Journal des événements à l'aide du hook « on Event_Action ». Des modifications sont également apportées aux données d'Inline-Execute-PE lorsque peload et peunload terminent l'exécution de leurs BOF ; ces modifications sont communiquées en retour par Beacon (par exemple, après avoir exécuté peload, Beacon rappelle avec l'emplacement mémoire de la structure pMemAddrs) et sont donc visibles par tous les Clients connectés, qui mettent à jour leurs petables respectives à l'aide du hook « on Beacon_Output ».

Ces efforts distincts combinés permettent à Inline-Execute-PE de synchroniser efficacement et fiablement les données critiques entre plusieurs Clients.

Crédits

Ce projet n'aurait pas été possible sans les projets et ressources suivants qui ont été largement référencés et dont sont issues les parties centrales de ce projet. Un grand merci aux auteurs pour leur code et leur vision.

  1. RunPE-In-Memory
  2. Pezor
  3. Beaucoup de StackOverflow
Télécharger l’outil