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
BeatRev — POC pour frustrer/déjouer les Analystes de Malwares | Kitploit
Outils/GitHubGitHub/octoberfest7/beatrev
Rétro-ingénierieAnalyse de MalwareApprentissage et ÉducationDéveloppement de Charges Utiles
GitHuboctoberfest7/beatrev

BeatRev

POC pour frustrer/déjouer les Analystes de Malwares

Voir le dépôt
154224il y a 4 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

BeatRev Version 2

Clause de non-responsabilité / Responsabilité

Le travail qui suit est une POC permettant à un logiciel malveillant de se « verrouiller » sur une victime particulière afin de contrecarrer les efforts des analystes de malware.

Je décline toute responsabilité en cas d'utilisation malveillante des idées ou du code contenus dans ce projet. Je fournis cette recherche pour continuer à former les professionnels de la sécurité informatique et offrir une formation supplémentaire/une matière à réflexion aux analystes de malware, ingénieurs en rétro-ingénierie et équipes bleues en général.

TLDR

La première fois que le malware s'exécute sur une victime, il chiffre AES la charge utile réelle (un RDLL) en utilisant des données environnementales de cette victime. Chaque fois que le malware est exécuté par la suite, il collecte ces mêmes informations environnementales, déchiffre AES la charge utile stockée sous forme de tableau d'octets dans le malware, et l'exécute. Si le déchiffrement échoue ou si la charge utile ne s'exécute pas, le malware se supprime. Protection contre les ingénieurs en rétro-ingénierie et les analystes de malware.

Mis à jour le 6 juin 2022

image

Je n'avais pas l'impression d'avoir terminé ce projet, alors j'y suis retourné et j'ai effectué une réécriture assez conséquente. La recherche originale et le savoir-faire technique peuvent être trouvés ici.

Les changements majeurs sont les suivants :

  1. J'ai publié tout le code source
  2. J'ai intégré le ReflectiveDLL de Stephen Fewer dans le projet pour remplacer Stage2
  3. J'ai formaté certains tableaux d'octets de ce projet en format chaîne et je les analyse avec UuidFromStringA. Ce dépôt a été utilisé comme modèle. Cela a été fait pour réduire l'entropie de Stage0 et Stage1
  4. Stage0 a reçu une quantité assez importante de mesures d'évasion antivirale. Merci à Cerbersec pour son Projet Ares pour l'inspiration
  5. L'application de construction pour produire Stage0 a été incluse

Il y a pas mal de choses différentes qui pourraient être extraites du code source de ce projet pour être utilisées ailleurs. Espérons que cela sera utile à quelqu'un.

Problèmes de la version originale et atténuations

Il y avait quelques lacunes dans la version originale de BeatRev que j'ai décidé d'essayer de corriger.

Stage2 était auparavant un exécutable autonome stocké sous forme de flux de données alternatif (ADS) de Stage1. Pour réaliser le chiffrement AES par victime puis le déchiffrement et l'exécution, chaque fois que Stage1 était exécuté, il lisait l'ADS, le déchiffrait, le réécrivait dans l'ADS, appelait CreateProcess, puis rechiffrait Stage2 et le réécrivait sur le disque dans l'ADS. Cela représentait beaucoup d'opérations d'E/S et l'appel CreateProcess n'était bien sûr pas idéal.

Je suis tombé sur les recherches de Steven Fewer concernant les DLL réflexives et cela semblait bien convenir. Stage2 est maintenant un RDLL ; notre malware/lanceur de shellcode/ce que nous voulons protéger peut être porté au format RDLL et stocké sous forme de tableau d'octets dans Stage1, qui est ensuite déchiffré à l'exécution et exécuté par Stage1. Cela supprime toutes les opérations d'E/S et l'appel CreateProcess de la version 1 et constitue un changement bienvenu.

Stage1 n'avait aucune véritable mesure d'évasion antivirale programmée ; c'était intentionnel, car c'est un travail supplémentaire et ce n'était pas vraiment le but de cette recherche. Lors de la réécriture, j'ai relevé le défi supplémentaire et ajouté du hachage d'API pour supprimer les fonctions de la table d'adresses d'importation de Stage1. Cela a aidé pour la détection et Stage1 a un taux de détection de 4/66 sur VirusTotal. J'étais à l'aise pour télécharger Stage1 étant donné qu'il est déjà lié à la machine d'origine sur laquelle il a été exécuté et que la signature du fichier change constamment en raison du chiffrement AES qui se produit.

J'ai récemment commencé à prêter attention à l'entropie comme moyen de détecter les malwares ; pour essayer de réduire l'entropie très élevée qu'un gros blob binaire chiffré AES donne à un exécutable, j'ai cherché à intégrer du shellcode stocké sous forme d'UUID. Comme le binaire est stocké sous forme de chaîne, l'entropie globale de l'exécutable est plus faible. Grâce à cette technique, l'entropie de Stage0 est maintenant d'environ 6,8 et celle de Stage1 d'environ 4,5 (sur une échelle maximale de 8).

Enfin, c'est une tâche énorme d'intégrer et de produire un Stage0 complet en raison de toutes les pièces qui doivent être manipulées. Pour faciliter cela, j'ai créé une application de construction qui prend un fichier modèle Stage0.c, un stub Stage1, un stub Stage2 et un fichier shellcode brut (cela a été construit autour de Stage2 étant un lanceur de shellcode contenant du shellcode CobaltStrike) et produit une charge utile Stage0 compilée pour être utilisée sur la cible.

Détails techniques

Le code DLL réflexive de Stephen Fewer contient des instructions spécifiques au compilateur Visual Studio ; je suis sûr qu'il est possible de porter la technique sur MingW mais je n'ai pas les compétences pour le faire. Le principal problème ici est que le shellcode CobaltStrike (sans état fait ~265K) doit être placé à l'intérieur du RDLL et être compilé. Pour contourner cela et l'intégrer harmonieusement au reste du processus, j'ai écrit mon RDLL Stage2 pour contenir un bloc de mémoire variable globale de la taille du shellcode CS ; ce bloc de mémoire d'environ 265K contient un petit espace réservé qui peut être localisé dans le binaire compilé. Le code dans src/Stage2 a déjà cela ajouté.

Une fois compilé, ce Stage2stub est transféré sur kali où un patch binaire peut être effectué pour insérer le vrai shellcode CS à l'endroit de la mémoire qui lui appartient. Cela produit le Stage2 complet.

Pour éviter le fiasco des E/S et de CreateProcess décrit précédemment, le Stage2 complet doit également être patché dans le Stage1 compilé par Stage0 ; cela est nécessaire pour permettre à Stage2 d'être chiffré une fois sur la cible en plus d'empêcher Stage2 d'être stocké séparément sur le disque. Le même concept décrit précédemment pour Stage2 est réalisé par Stage0 sur la cible afin d'assembler la charge utile finale de Stage1. Il est à noter que la fonction memmem est utilisée pour localiser l'espace réservé dans chaque stub ; cette fonction n'est pas disponible sur Windows, donc une implémentation personnalisée a été utilisée. Merci à Foxik384 pour son code.

Pour effectuer un patch binaire, nous devons allouer la mémoire nécessaire à l'avance ; cela a un effet cumulatif, car Stage1 doit maintenant être suffisamment grand pour contenir également Stage2. Avec l'étape supplémentaire de conversion de Stage2 en chaîne UUID, Stage2 gonfle en taille tout comme Stage1 pour le contenir. Un RDLL Stage2 avec une taille compilée d'environ 290K donne une charge utile Stage0 d'environ 1,38M et une charge utile Stage1 d'environ 700K.

L'application de construction ne supporte que la création d'exécutables x64. Cependant, avec un peu plus de travail, en théorie, vous pourriez faire de Stage0 une DLL, ainsi que Stage1, et faire exister tout le cycle de vie comme un détournement de DLL au lieu d'un exécutable autonome.

Instructions

Ces instructions vous permettront d'utiliser cette POC.

  1. Compile Builder using gcc -o builder src/Builder/BeatRevV2Builder.c
  2. Modifiez la variable sc_length dans src/Stage2/dll/src/ReflectiveDLL.c pour qu'elle corresponde à la longueur du fichier shellcode brut utilisé avec le builder (j'ai inclus fakesc.bin comme exemple)
  3. Compilez Stage2 (dans Visual Studio, le projet ReflectiveDLL utilise des instructions spécifiques au compilateur VS)
  4. Déplacez le stage2stub.dll compilé sur kali, modifiez src/Stage1/newstage1.c et définissez stage2size comme la taille de stage2stub
  5. Compile stage1stub using x86_64-w64-mingw32-gcc newstage1.c -o stage1stub.exe -s -DUNICODE -Os -L /usr/x86_64-w64-mingw32/lib -l:librpcrt4.a
  6. Run builder using syntax: ./builder src/Stage0/newstage0_exe.c x64 stage1stub.exe stage2stub.dll shellcode.bin
  7. Le builder produira dropper.exe. Il s'agit d'une charge utile Stage0 formatée et compilée pour être utilisée sur la cible.

Version originale de BeatRev

Introduction

Il y a environ 6 mois, il m'est venu à l'esprit que, bien que j'avais appris et fait beaucoup de choses concernant l'évasion des antivirus/EDR avec les malwares, j'avais passé très peu de temps à essayer d'éviter ou de vaincre la rétro-ingénierie/l'analyse de malware. Cela pour quelques bonnes raisons :

  1. Je ne sais rien de l'analyse de malware ou de la rétro-ingénierie
  2. Lorsqu'il s'agit de travaux d'équipe rouge légaux et sanctionnés, il n'y a pas vraiment besoin d'essayer de contrecarrer ou de vaincre un ingénieur en rétro-ingénierie car l'activité aurait dû être déconflictée bien avant d'atteindre ce stade.

Néanmoins, c'était une expérience de pensée intéressante et j'avais quelques collègues qui connaissent l'analyse de malware avec qui je pouvais échanger des idées. Cela semblait un défi d'une tout autre ampleur par rapport à l'évasion AV/EDR et j'ai décidé de m'y attaquer.

Prémisses

Mon hypothèse initiale était que le malware, la première fois qu'il était exécuté, se « verrouillerait » en quelque sorte sur cette machine victime ; toute tentative ultérieure de l'exécuter évaluerait quelque chose dans l'environnement cible et le comparerait à une correspondance dans le malware. Si ces deux facteurs correspondent, il s'exécute comme prévu. S'ils ne correspondent pas (comme dans le cas où l'échantillon aurait été transféré dans un bac à sable d'analyste de malware), le malware se supprime (encore une fois en s'appuyant fortement sur le travail de LloydLabs et son delete-self-poc).

Cette « clé » doit être quelque chose d'« unique » à l'ordinateur victime. Idéalement, ce sera une combinaison de plusieurs éléments d'information, puis davantage obscurcie. Par exemple, nous pourrions collecter le nom d'hôte de l'ordinateur ainsi que la quantité de RAM installée ; ces deux valeurs peuvent ensuite être concaténées (par exemple Client018192MB) puis hachées à l'aide d'une fonction définie par l'utilisateur pour produire un nombre (par exemple 5343823956).

Il existe des tonnes de choix quant aux informations à collecter, mais il faut réfléchir aux valeurs qu'un équipier bleu pourrait facilement usurper ; une adresse MAC, par exemple, peut sembler un identifiant « unique » attrayant pour une victime, mais les adresses MAC peuvent facilement être définies manuellement pour permettre à un ingénieur en rétro-ingénierie de faire correspondre son bac à sable à la victime d'origine. Idéalement, les valeurs choisies et énumérées seront difficiles à reproduire par un ingénieur en rétro-ingénierie dans son environnement.

Avec un peu de magie d'auto-suppression, le malware pourrait se lire dans un tampon, localiser une variable d'espace réservé et la remplacer par ce nombre, se supprimer, puis écrire le malware modifié sur le disque au même endroit. Combiné avec une instruction if/else dans Main, la prochaine fois que le malware s'exécutera, il détectera qu'il a été exécuté précédemment, puis collectera à nouveau le nom d'hôte et la quantité de RAM pour produire le nombre haché. Cela serait ensuite évalué par rapport au nombre stocké dans le malware lors de la première exécution (5343823956). S'il correspond (comme c'est le cas si le malware s'exécute sur la même machine qu'à l'origine), il s'exécute comme prévu, mais si une valeur différente est renvoyée, il appellera à nouveau la fonction d'auto-suppression pour se retirer du disque et protéger l'auteur de l'analyste de malware.

Cela semblait une bonne idée en théorie jusqu'à ce que je parle avec un collègue qui a une réelle expérience en analyse de malware et en rétro-ingénierie. On m'a dit qu'un ingénieur en rétro-ingénierie serait capable d'observer l'instruction conditionnelle dans le malware (si ValeurPremiereExécution != GetHostnameAndRAM()), et comme la valeur attendue est codée en dur d'un côté de l'instruction conditionnelle, il suffirait de modifier les registres pour contenir la valeur attendue, contournant ainsi complètement tout le mécanisme de protection.

Cette nouvelle connaissance a complètement déraillé l'expérience de pensée et comme je n'avais de toute façon pas vraiment d'utilité pour une telle capacité, c'est là que le projet s'est arrêté pendant environ 6 mois.

Aperçu

Ce projet a refait surface quelques fois au cours des 6 mois intermédiaires, mais à chaque fois ce n'était guère plus qu'une pensée passagère, car je n'avais acquis aucune nouvelle connaissance en rétro-ingénierie/analyse de malware et je n'avais toujours pas besoin d'une telle capacité. Il y a quelques jours, l'idée est revenue et bien qu'aucun de ces facteurs n'ait vraiment changé, je suppose que j'avais un peu plus de connaissances en poche et je n'ai pas pu laisser tomber l'idée cette fois.

Avec le problème susmentionné concernant les valeurs codées en dur à l'esprit, j'ai finalement décidé d'opter pour une conception multi-étapes. Je les appellerai Stage0, Stage1 et Stage2.

Stage0 : Configuration. Exécuté lors de l'infection initiale et supprimé ensuite

Stage1 : Exécuteur. Exécuté chaque fois que le malware s'exécute par la suite

Stage2 : Charge utile. Le malware que vous souhaitez protéger. Génère un processus et injecte un shellcode pour renvoyer un Beacon.

Cycle de vie

Stage0

Stage0 est l'exécutable frais livré à la cible par l'attaquant. Il contient Stage1 et Stage2 sous forme de tableaux d'octets chiffrés AES ; cela est fait pour protéger le malware en transit, ou si un défenseur mettait la main sur une copie de Stage0 (ce qui ne devrait pas arriver). La clé AES et l'IV sont contenus dans Stage0, donc en réalité cela ne protégera pas Stage1 ou Stage2 d'un équipier bleu compétent.

Stage0 effectue les actions suivantes :

  1. Évasion de bac à sable.
  2. Se supprime du disque. Il est toujours en cours d'exécution en mémoire.
  3. Déchiffre Stage1 à l'aide de la clé AES/IV stockée et écrit sur le disque à la place de Stage0.
  4. Collecte le nom du processeur et l'ID produit Microsoft.
  5. Hache cette valeur puis la remplit pour correspondre à une longueur de clé AES de 16 octets. Cette valeur inversée sert d'IV AES.
  6. Déchiffre Stage2 à l'aide de la clé AES/IV stockée.
  7. Chiffre Stage2 à l'aide de la nouvelle clé AES/IV spécifique à la victime.
  8. Écrit Stage2 sur le disque en tant que flux de données alternatif de Stage1.

À la conclusion de cette séquence d'événements, Stage0 se termine. Comme il a été supprimé du disque à l'étape 2 et n'est plus en cours d'exécution en mémoire, Stage0 a effectivement disparu ; Sans connaissance préalable de cette technique, le reste du cycle de vie du malware sera beaucoup plus déroutant qu'il ne l'est déjà.

À l'étape 4, le nom du processeur et l'ID produit Microsoft sont collectés ; l'ID produit est récupéré dans le Registre, et cette valeur peut être modifiée manuellement, ce qui offre une opportunité facile pour un équipier bleu de faire correspondre son bac à sable à l'environnement cible. Selon les informations environnementales collectées, cela peut devenir plus facile ou plus difficile.

Stage1

Stage1 a été déposé par Stage0 et existe au même endroit exact que Stage0 (y compris le nom). Stage2 est stocké en tant qu'ADS de Stage1. Lorsque l'attaquant/la persistance exécute ensuite le malware, il exécute Stage1.

Stage1 effectue les actions suivantes :

  1. Évasion de bac à sable.
  2. Collecte le nom du processeur et l'ID produit Microsoft.
  3. Hache cette valeur puis la remplit pour correspondre à une longueur de clé AES de 16 octets. Cette valeur inversée sert d'IV AES.
  4. Lit Stage2 depuis l'ADS de Stage1 en mémoire.
  5. Déchiffre Stage2 à l'aide de la clé AES/IV spécifique à la victime.
  6. Vérifie les deux premiers octets du tampon déchiffré de Stage2 ; si ce n'est pas MZ (déchiffrement échoué), supprime Stage1/Stage2, quitte.
  7. Écrit Stage2 déchiffré sur le disque en tant qu'ADS de Stage1
  8. Appelle CreateProcess sur Stage2. Si cela échoue (déchiffrement échoué), supprime Stage1/Stage2, quitte.
  9. Attend 5 secondes pour permettre à Stage2 de s'exécuter et de se terminer afin qu'il puisse être écrasé.
  10. Chiffre Stage2 à l'aide de la clé AES/IV spécifique à la victime
  11. Écrit Stage2 chiffré sur le disque en tant qu'ADS de Stage1.

Notez que Stage2 DOIT se terminer pour pouvoir être écrasé ; l'astuce d'auto-suppression ne semble pas fonctionner sur les fichiers qui sont déjà des ADS, car la technique d'auto-suppression repose sur le renommage du flux de données principal de l'exécutable. Stage2 sera idéalement un exécutable d'injection ou de génération+injection.

Il y a deux points où Stage1 peut détecter qu'il n'est pas exécuté depuis la même victime et se supprimer/supprimer Stage2 pour protéger l'acteur malveillant. Le premier est la vérification de l'en-tête exécutable après avoir déchiffré Stage2 en utilisant les informations environnementales collectées ; en théorie, cette étape pourrait être contournée par un ingénieur en rétro-ingénierie, mais c'est une première bonne vérification. Le deuxième point de protection est le résultat de l'appel CreateProcess - s'il échoue parce que Stage2 n'a pas été correctement déchiffré, le malware est similairement supprimé. Le résultat de cet appel pourrait également être modifié pour empêcher la suppression par l'ingénieur en rétro-ingénierie, mais cela ne change pas le fait que Stage2 est chiffré et inaccessible.

Stage2

Stage2 est le cœur de la chaîne de malware ; C'est un lanceur de shellcode/pièce de malware à part entière. En le chiffrant et en le protégeant de la manière dont nous l'avons fait, les actions du malware final sont beaucoup mieux obscurcies et protégées des ingénieurs en rétro-ingénierie et des analystes de malware. Pendant le développement, j'ai utilisé l'un de mes lanceurs de shellcode existants contenant du shellcode CobaltStrike, mais cela pourrait être n'importe quoi que l'attaquant souhaite exécuter et protéger.

Impact, atténuation et travaux futurs

Alors, qu'est-ce qui est réellement accompli avec un tel cycle de vie de malware ? Il y a quelques particularités intéressantes à mentionner.

Les flux de données alternatifs sont une fonctionnalité unique aux systèmes de fichiers NTFS ; cela signifie que la plupart des moyens de transférer le malware après l'infection initiale supprimeront et perdront Stage2 car il s'agit d'un ADS de Stage1. Des précautions particulières devraient être prises pour transférer l'échantillon afin de préserver Stage2, car sans lui, de nombreux ingénieurs en rétro-ingénierie et analystes de malware seront très confus quant à ce qui se passe. Les archives RAR peuvent préserver les ADS et des outils comme 7Z et Peazip peuvent extraire les fichiers et leurs ADS.

Comme mentionné précédemment, au moment où un malware utilisant ce cycle de vie atteint un équipier bleu, il devrait être au stade Stage1 ; Stage0 est passé et a disparu, et Stage2 est déjà chiffré avec les informations environnementales collectées par Stage0. Ne pas savoir que Stage0 a même existé ajoutera une incertitude considérable à la compréhension du cycle de vie et au déchiffrement de Stage2.

En théorie (car encore une fois je n'ai pas d'expérience en rétro-ingénierie), Stage1 devrait pouvoir être rétro-conçu (après que l'équipe bleue ait passé en revue quelques copies car il se supprime constamment) et les informations que Stage1 collecte depuis le système cible devraient pouvoir être identifiées. Avec une réponse bien orchestrée, l'équipe bleue devrait pouvoir identifier la victime dont provient le malware, aller collecter ces informations et les injecter dans le programme afin qu'elles puissent être transformées de manière appropriée en la clé AES/IV qui déchiffre Stage2. Il y a beaucoup de « si » cependant, liés à la compétence relative de l'ingénieur en rétro-ingénierie ainsi qu'à la disponibilité de la machine victime pour que ces informations soient récupérées.

La liste blanche d'applications frustrerait considérablement ce cycle de vie. Stage0/Stage1 pourraient peut-être être chargés latéralement en tant que DLL, mais je soupçonne que Stage2 en tant qu'ADS poserait quelques problèmes. Je n'ai pas d'environnement pour tester les malwares contre l'AWL et je ne me suis pas non plus donné la peine de porter tout cela au format DLL, donc je ne peux pas dire. Je suis sûr qu'il existe des moyens créatifs pour contourner ces problèmes.

Je suis également assez confiant qu'il existe des moyens plus intelligents d'exécuter Stage2 que de le déposer sur le disque et d'appeler CreateProcess ; soit mapper manuellement l'exécutable, soit utiliser un outil comme Donut pour le transformer en shellcode semblent être des idées raisonnables.

Code et binaire

Pendant le développement, j'ai créé une application Builder dans laquelle Stage1 et Stage2 peuvent être introduits pour produire un Stage0 fonctionnel ; cela ne sera pas fourni, mais je fournirai la plupart du code source pour Stage1 car c'est la pièce qui serait la plus visible pour un équipier bleu. Stage0 sera exclu comme exercice pour le lecteur, et Stage2 est l'exécutable autonome que vous souhaitez exécuter et protéger. Cette POC peut être davantage étudiée à l'effort et à la discrétion des lecteurs capables.I will be providing a compiled copy of this malware as Dropper64.exe. Dropper64.exe is compiled for x64. Dropper64.exe is Stage0; it contains Stage1 and Stage2. On execution, Stage1 and Stage2 will drop to disk but will NOT automatically execute, you must run Dropper64.exe(now Stage1) again. Stage2 is an x64 version of calc.exe. I am including this for any Blue Teamers who want to take a look at this, but keep in mind in an incident response scenario 99% of the time you will be getting Stage1/Stage2, Stage0 will be gone.

Conclusion

This was an interesting pet project that ate up a long weekend. I'm sure it would be a lot more advanced/more complete if I had experience in a debugger and disassembler, but you do the best with what you have. I am eager to hear from Blue Teamers and other Malware Devs what they think. I am sure I have over-complicatedly re-invented the wheel here given what actual APT's are doing, but I learned a few things along the way. Thank you for reading!

Télécharger l’outil