
CobaltWhispers is an aggressor script that utilizes a collection of Beacon Object Files (BOF) for Cobalt Strike to perform process injection, persistence and more, leveraging direct syscalls (SysWhispers2) to bypass EDR/AV
Auteur : @Cerbersec
CobaltWhispers est un script aggressor qui utilise une collection de Beacon Object Files pour Cobalt Strike afin d'effectuer de l'injection de processus, de la persistance et plus encore, en tirant parti des appels système directs pour contourner les EDR/AV.
CobaltWhispers est propulsé par SysWhispers2 et InlineWhispers2
CobaltWhispers est basé sur StayKit et sur les travaux de Hasherezade et Forrest Orr.
CobaltWhispers a été réalisé dans le cadre d'un stage au sein de la Red Team de NVISO Security. Les articles de blog associés sont disponibles ici (injection de processus) et ici (kernel karnage).
CobaltWhispers nécessite plusieurs outils pour être compilé :
apt install mingw-w64apt install makeChaque projet nécessite 3 fichiers générés par SysWhispers2 / InlineWhispers2 pour fonctionner :
Ces fichiers peuvent être générés conformément à la documentation d'InlineWhispers2, cependant cette méthode n'est pas optimale car beaucoup de code inutile sera inclus :
git clone https://github.com/Sh0ckFR/InlineWhispers2 && cd InlineWhispers2
cd SysWhispers2/ && python3 syswhispers.py --preset all -o syscalls_all && cd ..
python3 InlineWhispers2.py
À la place, utilisez SysWhispers2 pour générer les fichiers de sortie uniquement pour les API nécessaires, puis fournissez-les manuellement (ou via un script) à InlineWhispers2 qui les convertira dans le format approprié. Consultez le makefile inclus pour plus d'informations ou utilisez les fichiers inclus à vos risques et périls.
| Type de charge utile | Cible | Fiabilité (0-5) | Admin requis | Remarques |
|---|---|---|---|---|
| - | - | 5 | Non | Hérite des autorisations du processus parent |
Démarre un nouveau processus suspendu avec Code Integrity Guard (CIG) activé pour bloquer les binaires signés non Microsoft. Usurpe le processus parent spécifié. Le PID est renvoyé.
Processus parent : Le nom du processus à définir comme parent
Emplacement de l'exécutable : Chemin complet de l'exécutable sur le disque utilisé pour démarrer le nouveau processus
| Type de charge utile | Cible | Fiabilité (0-5) | Admin requis | Remarques |
|---|---|---|---|---|
| Shellcode/Raw | PID | 5 | Non | - |
Injecte une charge utile dans un processus distant via NtCreateThreadEx
PID du processus : L'identifiant du processus distant
Emplacement de la charge utile : Emplacement de la charge utile sous forme binaire sur le disque (Conditionnel | Facultatif)
Charge utile b64 : Shellcode brut au format chaîne encodée en base64 (Conditionnel | Facultatif)
Listener : Listener pour lequel générer la charge utile (Conditionnel)
Un listener doit être spécifié pour générer une charge utile Beacon. Si une charge utile manuelle est souhaitée, elle doit être fournie via un chemin vers le binaire brut sur le disque, ou un shellcode encodé en base64.
| Type de charge utile | Cible | Fiabilité (0-5) | Admin requis | Remarques |
|---|---|---|---|---|
| Shellcode/Raw | PID | 2 | Non | Peut potentiellement faire planter le processus cible |
Injecte une charge utile dans un processus distant via NtQueueApcThread
PID du processus : L'identifiant du processus distant
Threads : Nombre de threads auxquels ajouter un appel APC
Emplacement de la charge utile : Emplacement de la charge utile sous forme binaire sur le disque (Conditionnel | Facultatif)
Charge utile b64 : Shellcode brut au format chaîne encodée en base64 (Conditionnel | Facultatif)
Listener : Listener pour lequel générer la charge utile (Conditionnel)
Un listener doit être spécifié pour générer une charge utile Beacon. Si une charge utile manuelle est souhaitée, elle doit être fournie via un chemin vers le binaire brut sur le disque, ou un shellcode encodé en base64.
| Type de charge utile | Cible | Fiabilité (0-5) | Admin requis | Remarques |
|---|---|---|---|---|
| Shellcode/Raw | Processus de substitution | 5 | Non | - |
Injecte une charge utile dans un processus de substitution via NtMapViewOfSection
Processus parent : Le nom du processus à définir comme parent
Emplacement de l'exécutable : L'emplacement sur disque de l'exécutable à utiliser pour démarrer un nouveau processus
Emplacement de la charge utile : Emplacement de la charge utile sous forme binaire sur le disque (Conditionnel | Facultatif)
Charge utile b64 : Shellcode brut au format chaîne encodée en base64 (Conditionnel | Facultatif)
Listener : Listener pour lequel générer la charge utile (Conditionnel)
Un listener doit être spécifié pour générer une charge utile Beacon. Si une charge utile manuelle est souhaitée, elle doit être fournie via un chemin vers le binaire brut sur le disque, ou un shellcode encodé en base64.
| Type de charge utile | Cible | Fiabilité (0-5) | Admin requis | Remarques |
|---|---|---|---|---|
| PE | Processus de substitution | 5 | Non | Requiert une charge utile PE x64 |
Injecte une charge utile dans un processus de substitution en utilisant des sections transactionnelles et des vues mappées. Le point d'entrée distant et le PEB sont mis à jour, sans sections mémoire anormales ni permissions mémoire anormales. Voir ici pour plus d'informations.
Processus parent : Le nom du processus à définir comme parent
Emplacement de l'exécutable : L'emplacement sur disque de l'exécutable à utiliser pour démarrer un nouveau processus
Emplacement de la charge utile : Emplacement de la charge utile PE x64 sur le disque (Conditionnel | Facultatif)
Charge utile b64 : Charge utile PE x64 au format chaîne encodée en base64 (Conditionnel | Facultatif)
Listener : Listener pour lequel générer la charge utile (Conditionnel)
Un listener doit être spécifié pour générer une charge utile Beacon. Si une charge utile manuelle est souhaitée, elle doit être fournie via un chemin vers le PE x64 sur le disque, ou un PE x64 encodé en base64.
ACTUELLEMENT NON IMPLÉMENTÉ
| Type de charge utile | Cible | Fiabilité (0-5) | Admin requis | Remarques |
|---|---|---|---|---|
| Shellcode indépendant de la position (PIC) | Processus de substitution | 5 | Oui | Des permissions élevées sont requises pour ouvrir les DLL système avec des permissions d'écriture |
Injecte une charge utile dans un processus de substitution en utilisant des sections transactionnelles combinées au DLL hollowing. Voir ici pour plus d'informations.
Processus parent : Le nom du processus à définir comme parent
Emplacement de l'exécutable : L'emplacement sur disque de l'exécutable à utiliser pour démarrer un nouveau processus
Emplacement de la charge utile : Emplacement de la charge utile sous forme binaire sur le disque (Conditionnel | Facultatif)
Charge utile b64 : Shellcode brut au format chaîne encodée en base64 (Conditionnel | Facultatif)
Listener : Listener pour lequel générer la charge utile (Conditionnel)
Un listener doit être spécifié pour générer une charge utile Beacon. Si une charge utile manuelle est souhaitée, elle doit être fournie via un chemin vers le binaire brut sur le disque, ou un shellcode encodé en base64.
Crée ou modifie une clé de registre à l'emplacement spécifié.
Nom de la clé : Nom de la valeur
Commande : Commande à exécuter lorsque la clé de registre est utilisée
Clé de registre : Emplacement où la clé de registre sera créée
Masquée : Ajoute un octet nul au début du nom de la clé ; génère des erreurs dans regedit
Nettoyage : Supprime la clé créée
Le nettoyage nécessite le nom de la clé et la clé de registre (emplacement).
Crée ou modifie une clé de registre à l'emplacement spécifié.
Nom de la clé : Nom de la valeur
Commande : Commande à exécuter lorsque la clé de registre est utilisée
Clé de registre : Emplacement où la clé de registre sera créée
Masquée : Ajoute un octet nul au début du nom de la clé ; génère des erreurs dans regedit
Nettoyage : Supprime la clé créée
Le nettoyage nécessite le nom de la clé et la clé de registre (emplacement).
UserInit : définit automatiquement 'Nom de la clé' et 'Clé de registre'.
Crée ou modifie une clé de registre à l'emplacement spécifié.
Nom de la clé : Nom de la valeur
Commande : Commande à exécuter lorsque la clé de registre est utilisée
Clé de registre : Emplacement où la clé de registre sera créée
Masquée : Ajoute un octet nul au début du nom de la clé ; génère des erreurs dans regedit
Nettoyage : Supprime la clé créée
Le nettoyage nécessite le nom de la clé et la clé de registre (emplacement).
Crée ou modifie une clé de registre à l'emplacement spécifié.
Nom de la clé : Nom de la valeur
Commande : Commande à exécuter lorsque la clé de registre est utilisée
Clé de registre : Emplacement où la clé de registre sera créée
Masquée : Ajoute un octet nul au début du nom de la clé ; génère des erreurs dans regedit
Nettoyage : Supprime la clé créée
Le nettoyage nécessite le nom de la clé et la clé de registre (emplacement).
UserInitMprLogonScript : définit automatiquement 'Nom de la clé' et 'Clé de registre'.
Détourne le gestionnaire COM d'une tâche planifiée. Crée une clé de registre à HKCU:\Software\Classes\CLSID\\InprocServer32 qui pointe vers une DLL.
Identifiant de classe : Le CLSID qui correspond au CLSID du gestionnaire COM de la tâche
Chemin de la DLL : Chemin vers la DLL qui doit être chargée
Nettoyage : Supprime la clé créée
| Fiabilité (0-5) | Admin requis | Remarques |
|---|---|---|
| 4 | Oui | Peut potentiellement provoquer un BSOD sur le système cible |
Charge un pilote signé vulnérable avec lecture/écriture arbitraire de la mémoire du noyau (NalDrv/iqvm64.sys). Modifie le drapeau g_CiEnabled de ntoskrnl.exe ou g_CiOptions de CI.dll pour désactiver le contrôle de signature des pilotes (DSE).
Charge un pilote non signé (Interceptor/Interceptor.sys), puis restaure les valeurs des drapeaux DSE. Le pilote signé et le pilote non signé sont tous deux écrits sur le disque.
| Pilote | Somme de contrôle MD5 |
|---|---|
| iqvm64.sys | 1898ceda3247213c084f43637ef163b3 |
| Interceptor.sys | 508c8943359717cfa0c77b61ebea2118 |
Emplacement du pilote vulnérable : Emplacement du pilote signé vulnérable sous forme binaire sur le disque
Emplacement du pilote malveillant : Emplacement du pilote non signé malveillant sous forme binaire sur le disque
Nom du pilote vulnérable : nom utilisé pour créer la clé de registre '\Registry\Machine\System\CurrentControlSet\Services\'
Nom du périphérique du pilote vulnérable : nom utilisé pour contacter le pilote '\DosDevices\'
Nom du pilote malveillant : nom utilisé pour créer la clé de registre '\Registry\Machine\System\CurrentControlSet\Services\'
Nom du périphérique du pilote malveillant : nom utilisé pour contacter le pilote '\DosDevices\'
Chemin cible : chemin temporaire pour écrire les fichiers du pilote vulnérable et du pilote malveillant
| Fiabilité (0-5) | Admin requis | Remarques |
|---|---|---|
| 5 | Oui | - |
Décharge un pilote sur la cible en utilisant la clé de registre fournie et supprime le binaire du disque à l'emplacement spécifié.
Clé de registre du pilote : clé de registre utilisée pour décharger le pilote '\Registry\Machine\System\CurrentControlSet\Services\'
Chemin d'installation du pilote : emplacement du pilote sur le disque
| Fiabilité (0-5) | Admin requis | Remarques |
|---|---|---|
| 4 | Non | Peut potentiellement provoquer un BSOD sur le système cible |
Information : Interroge le pilote Interceptor
Hook : Hooke les fonctions principales du pilote cible (IRP)
Unhook : Restaure les fonctions principales du pilote cible
Patch : Patche les callbacks du noyau cible
Restore : Restaure les callbacks du noyau cible
Vendeurs : affiche les vendeurs pris en charge
Modules : interroge tous les pilotes chargés
Modules hookés : affiche tous les pilotes hookés
Callbacks : interroge tous les callbacks enregistrés
Index : hooke un pilote par index (voir : informations - modules)
Nom : hooke un pilote par nom de périphérique (\Device\Name)
Valeurs : liste d'index séparés par des virgules (conditionnel)
Nom : nom de périphérique du pilote cible (conditionnel)
Les valeurs sont requises lorsque 'Index' est sélectionné. Le nom est requis lorsque 'Nom' est sélectionné.
Index : unhooke un pilote par index (voir : informations - modules hookés)
Tout : unhooke tous les pilotes hookés
Valeurs : liste d'index séparés par des virgules (conditionnel)
Les valeurs sont requises lorsque 'Index' est sélectionné.
Vendeur : patche tous les callbacks associés au(x) module(s) du vendeur
Module : patche tous les callbacks associés au(x) module(s)
Processus : patche le(s) callback(s) de processus
Thread : patche le(s) callback(s) de thread
Image : patche le(s) callback(s) d'image
Registre : patche le(s) callback(s) de registre
Objet processus : patche le(s) callback(s) d'objet processus
Objet thread : patche le(s) callback(s) d'objet thread
Valeurs : liste d'index séparés par des virgules (voir : informations - callbacks) (conditionnel)
Nom : liste de noms de modules séparés par des virgules ou nom d'un seul vendeur (voir : informations - vendeurs) (conditionnel)
Les valeurs sont requises lorsque 'processus', 'thread', 'image', 'registre', 'objet processus' ou 'objet thread' est sélectionné. Le nom est requis lorsque 'vendeur' ou 'module' est sélectionné.
Vendeur : restaure tous les callbacks associés au(x) module(s) du vendeur
Module : restaure tous les callbacks associés au(x) module(s)
Processus : restaure le(s) callback(s) de processus
Thread : restaure le(s) callback(s) de thread
Image : restaure le(s) callback(s) d'image
Registre : restaure le(s) callback(s) de registre
Objet processus : restaure le(s) callback(s) d'objet processus
Objet thread : restaure le(s) callback(s) d'objet thread
Tout : restaure tous les callbacks
Valeurs : liste d'index séparés par des virgules (voir : informations - callbacks) (conditionnel)
Nom : liste de noms de modules séparés par des virgules ou nom d'un seul vendeur (voir : informations - vendeurs) (conditionnel)
Les valeurs sont requises lorsque 'processus', 'thread', 'image', 'registre', 'objet processus' ou 'objet thread' est sélectionné. Le nom est requis lorsque 'vendeur' ou 'module' est sélectionné.