Listeners HTTP/HTTPS¶
HTTP et HTTPS sont les principaux transports C2 pour les opérations de Stentor. Ils fournissent une communication fiable à large bande passante qui se fond dans le trafic Web normal. HTTPS est la valeur par défaut recommandée pour tous les engagements ; HTTP ne doit être utilisé que dans des environnements de laboratoire contrôlés où la surcharge TLS n'est pas nécessaire.
Architecture¶
La chaîne de transport HTTP/HTTPS connecte l'implant sur la cible au backend Stentor via le relais :
sequenceDiagram
participant Implant as Implant (Windows)
participant Relay as Relay C2 Server (Kali)
participant Backend as Backend API Server
Implant->>Relay: HTTPS request (beacon check-in)
Relay->>Backend: WebSocket event (beacon registration)
Backend-->>Relay: WebSocket command (task queue)
Relay-->>Implant: HTTPS response (task payload)
Implant->>Relay: HTTPS request (task result)
Relay->>Backend: WebSocket event (result delivery) Le relais termine TLS et gère le protocole HTTP C2. Le backend gère l’état (registre de beacons, file d’attente des tâches) et l’interface utilisateur de l’opérateur. Toutes les interactions de l'opérateur transitent par l'API backend, qui envoie des commandes au relais via une connexion WebSocket persistante.
Création d'un listener HTTP/HTTPS¶
Les listeners sont créés via l'API REST et démarrent avec le statut stopped. Vous devez explicitement démarrer un listener avant qu'il n'accepte les connexions.
Créer un listener HTTPS¶
curl -s -X POST https://stentor.app/api/v1/listeners \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "HTTPS Primary",
"relay_id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
"type": "https",
"port": 8443,
"tls_auto_generate": true
}' | jq
Créer un listener HTTP¶
curl -s -X POST https://stentor.app/api/v1/listeners \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "HTTP Lab",
"relay_id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
"type": "http",
"port": 8080
}' | jq
HTTP n'est pas chiffré
Les listeners HTTP transmettent le trafic C2 en texte brut. Utilisez uniquement HTTP dans des environnements de laboratoire isolés où la surveillance du réseau n'est pas une préoccupation. Pour tous les engagements de production, utilisez HTTPS.
Démarrer, arrêter et redémarrer¶
Après avoir créé un listener, démarrez-le pour commencer à accepter les connexions :
Cycle de vie du listener
Les listeners nouvellement créés ont toujours le statut stopped. Le point de terminaison start passe à running. Si le relais rencontre une erreur liant le port, l'état passe à error avec des détails dans le champ error_message.
Options de configuration¶
Le tableau ci-dessous répertorie tous les champs pertinents pour les listeners HTTP et HTTPS. Les champs marqués obligatoire doivent être fournis lors de la création d'un listener.
| Champ | Type | Par défaut | Description |
|---|---|---|---|
name | chaîne | -- | Obligatoire. Nom d'affichage du listener. |
type | chaîne | -- | Obligatoire. "http" ou "https". |
relay_id | chaîne | -- | Obligatoire. UUID du relais qui hébergera cet listener. |
port | int | -- | Obligatoire. Port TCP auquel le relais se lie. |
bind_address | chaîne | "0.0.0.0" | Interface réseau à lier. Utilisez "127.0.0.1" pour vous limiter à localhost. |
beacon_port | int | null | Port séparé pour la génération de payload. Lorsqu'il est défini, port est le port de liaison de relais et beacon_port est intégré aux payloads générées. Voir Séparation des ports de beacon. |
tls_cert | chaîne | null | Certificat TLS codé PEM. Utilisé uniquement lorsque type est "https". |
tls_key | chaîne | null | Clé privée TLS codée en PEM. Utilisé uniquement lorsque type est "https". |
tls_auto_generate | bool | true | Générer automatiquement un certificat auto-signé si aucun tls_cert/tls_key n'est fourni. |
profile_name | chaîne | null | Nom de profil C2 malléable pour la personnalisation du trafic HTTP. |
profile_variant | chaîne | null | Variante de profil malléable (par exemple, "jquery", "amazon"). |
host_rotation | chaîne | null | Stratégie de rotation des hôtes : "round-robin", "random" ou "failover". |
max_retry_strategy | chaîne | null | Réessayez le comportement lorsque tous les hôtes échouent : "exit", "rotate" ou "sleep". |
c2_hosts | chaîne | null | Liste d'hôtes de rappel séparés par des virgules pour la rotation. |
proxy_type | chaîne | null | Protocole proxy : "http" ou "socks". |
proxy_host | chaîne | null | Nom d'hôte ou IP du serveur proxy. |
proxy_port | int | null | Port du serveur proxy. |
proxy_user | chaîne | null | Nom d'utilisateur d'authentification proxy. |
proxy_pass | chaîne | null | Mot de passe d'authentification proxy. Non renvoyé dans les réponses de l'API. |
front_domains | chaîne | null | Liste de domaines frontaux CDN séparés par des virgules pour le fronting de domaine. |
guardrails | JSON | null | Règles de filtrage des beacons. Voir Garde-corps. |
Gestion des certificats TLS¶
Les listeners HTTPS nécessitent un certificat TLS et une clé privée. Stentor propose deux options :
Certificats générés automatiquement (par défaut)¶
Lorsque tls_auto_generate est true (valeur par défaut) et qu'aucun tls_cert/tls_key n'est fourni, le relais génère un certificat auto-signé au démarrage. Il s’agit du moyen le plus rapide de faire fonctionner un listener HTTPS.
curl -s -X POST https://stentor.app/api/v1/listeners \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "HTTPS Auto-TLS",
"relay_id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
"type": "https",
"port": 443,
"tls_auto_generate": true
}' | jq
Certificats personnalisés¶
Pour les engagements de production, fournissez vos propres certificats (Let's Encrypt, autorité de certification interne ou certificats achetés). Réglez tls_auto_generate sur false et fournissez tls_cert et tls_key codés PEM :
curl -s -X POST https://stentor.app/api/v1/listeners \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "HTTPS Production",
"relay_id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
"type": "https",
"port": 443,
"tls_auto_generate": false,
"tls_cert": "-----BEGIN CERTIFICATE-----\nMIID...your cert...\n-----END CERTIFICATE-----",
"tls_key": "-----BEGIN PRIVATE KEY-----\nMIIE...your key...\n-----END PRIVATE KEY-----"
}' | jq
Utiliser des certificats légitimes pour la production
Les certificats auto-signés déclenchent des avertissements du navigateur et sont facilement détectés par la surveillance du réseau. Pour les engagements de production, utilisez Let's Encrypt (gratuit), les certificats de l'autorité de certification interne de votre organisation ou les certificats achetés correspondant à votre domaine de couverture.
Domain fronting¶
Le domain fronting exploite la différence entre le nom d'hôte DNS/TLS SNI et l'en-tête HTTP Host pour acheminer le trafic C2 via un CDN, le faisant apparaître comme un trafic légitime vers le domaine du fournisseur CDN.
Comment ça marche :
- L'implant se connecte à un serveur Edge CDN (par exemple,
cdn.cloudfront.net) via TLS - Le TLS SNI affiche le domaine CDN – trafic normal
- L'en-tête HTTP
Hostà l'intérieur du tunnel TLS contient le domaine C2 réel - Le CDN achemine la demande vers votre relais en fonction de l'en-tête
Host
Configuration :
Définissez le champ front_domains sur une liste de domaines frontaux CDN séparés par des virgules :
curl -s -X POST https://stentor.app/api/v1/listeners \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "HTTPS Fronted",
"relay_id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
"type": "https",
"port": 443,
"front_domains": "d1234567.cloudfront.net,cdn.azureedge.net"
}' | jq
Restrictions du fournisseur CDN
De nombreux fournisseurs de CDN (AWS CloudFront, Azure CDN, Google Cloud CDN) ont mis à jour leurs politiques pour empêcher le domain fronting. Testez votre configuration avant de vous y fier en production. Certains fournisseurs bloquent activement les requêtes pour lesquelles les en-têtes SNI et Host ne correspondent pas.
Configuration du proxy HTTP¶
Lorsque les implants fonctionnent derrière un proxy d'entreprise, configurez le listener avec des paramètres de proxy afin que les payloads générées incluent la configuration de proxy correcte :
curl -s -X POST https://stentor.app/api/v1/listeners \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "HTTPS via Proxy",
"relay_id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
"type": "https",
"port": 443,
"proxy_type": "http",
"proxy_host": "proxy.corp.local",
"proxy_port": 8080,
"proxy_user": "svc_account",
"proxy_pass": "proxy_password"
}' | jq
| Champ | Description |
|---|---|
proxy_type | "http" pour le proxy HTTP CONNECT, "socks" pour le proxy SOCKS⅘ |
proxy_host | Nom d'hôte ou IP du serveur proxy |
proxy_port | Port du serveur proxy |
proxy_user | Nom d'utilisateur pour l'authentification proxy (facultatif) |
proxy_pass | Mot de passe pour l'authentification proxy (facultatif, jamais renvoyé dans les réponses API) |
Paramètres de proxy dans les payloads
La configuration du proxy est intégrée aux payloads générées. L'implant utilise ces paramètres pour acheminer tout le trafic C2 via le proxy spécifié. Ceci est essentiel dans les environnements où l’accès direct à Internet est bloqué.
Rotation des hôtes¶
La rotation des hôtes permet aux beacons de parcourir plusieurs adresses de rappel, améliorant ainsi la résilience si un hôte est bloqué ou tombe en panne.
| Champ | Description |
|---|---|
c2_hosts | Liste d'hôtes de rappel séparés par des virgules (par exemple, "c2-1.example.com,c2-2.example.com,10.0.0.50") |
host_rotation | Stratégie pour les hôtes cyclistes : "round-robin" (séquentiel), "random" (sélection aléatoire), "failover" (suivant en cas d'échec) |
max_retry_strategy | Comportement lorsque tous les hôtes échouent : "exit" (terminer le beacon), "rotate" (cycle de redémarrage), "sleep" (veille prolongée puis réessayer) |
Exemple : listener HTTPS avec rotation des hôtes :
curl -s -X POST https://stentor.app/api/v1/listeners \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "HTTPS Resilient",
"relay_id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
"type": "https",
"port": 443,
"c2_hosts": "c2-primary.example.com,c2-backup.example.com,10.0.0.50",
"host_rotation": "failover",
"max_retry_strategy": "sleep"
}' | jq
Stratégie de basculement
Utilisez "failover" avec "sleep" pour une persistance à long terme. Le beacon essaie chaque hôte dans l'ordre et, si tous échouent, se met en veille pendant une période prolongée avant de redémarrer le cycle. Cela empêche les tentatives de connexion rapides qui pourraient alerter les défenseurs.
Séparation des ports de beacon¶
Le champ beacon_port sépare le port auquel le relais se lie (port) du port intégré dans les payloads générées (beacon_port). Ceci est essentiel lorsqu’un proxy inverse ou un équilibreur de charge se trouve devant le relais.
Cas d'utilisation : Un proxy inverse (nginx, HAProxy) écoute sur le port 443 et transfère le trafic vers le relais sur le port 8443. Sans beacon_port, les payloads indiqueraient aux implants de se connecter au port 8443, en contournant le proxy.
curl -s -X POST https://stentor.app/api/v1/listeners \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "HTTPS Behind Proxy",
"relay_id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
"type": "https",
"port": 8443,
"beacon_port": 443
}' | jq
| Champ | Objectif |
|---|---|
port | Où le processus de relais se lie (par exemple, 8443). Interne à l’hôte relais. |
beacon_port | Ce qui entre dans les payloads générées (par exemple, 443). Le port auquel les implants se connectent. |
Lorsque beacon_port n'est pas défini, port sert à la fois de port de liaison et de port de rappel de payload (comportement rétrocompatible).
Garde-corps¶
Les garde-corps sont des règles de filtrage de beacons par listener qui limitent les beacons acceptées par le listener. Les beacons qui ne correspondent pas aux modèles de garde-corps sont rejetées lors de l'enregistrement.
Schéma JSON :
{
"ip": "10.10.10.*",
"hostname": "DC*",
"username": "admin*",
"domain": "corp.local",
"server_name": "FILE*"
}
Tous les champs sont facultatifs. Les modèles génériques (*) sont pris en charge. Un beacon doit correspondre à tous les champs spécifiés pour être acceptée. Les champs non spécifiés ne sont pas vérifiés (acceptez n'importe quelle valeur).
Exemple : restreindre à un sous-réseau et un domaine spécifiques :
curl -s -X POST https://stentor.app/api/v1/listeners \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "HTTPS Scoped",
"relay_id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
"type": "https",
"port": 443,
"guardrails": {
"ip": "10.10.10.*",
"domain": "corp.local"
}
}' | jq
Tester les garde-corps avant la production
Des garde-corps trop restrictifs peuvent bloquer les beacons légitimes. Testez d'abord vos modèles dans un environnement de laboratoire. Un beacon rejetée par les garde-corps n'apparaîtra pas dans le cockpit et ne générera aucune alerte : elle est larguée silencieusement.
Hébergement de fichiers¶
Les listeners HTTP/HTTPS peuvent servir des fichiers arbitraires sur des URI personnalisés. Ceci est utile pour héberger des payloads, des scripts, des documents leurres ou des pages de destination directement sur le serveur C2.
Héberger un fichier¶
curl -s -X POST https://stentor.app/api/v1/listeners/$LISTENER_ID/host \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"uri": "/downloads/update.exe",
"content_type": "application/octet-stream",
"filename": "update.exe",
"data": "TVqQAAMAAAAEAAAA..."
}' | jq
| Champ | Type | Description |
|---|---|---|
uri | chaîne | Obligatoire. Chemin d'accès au fichier (doit commencer par /). |
content_type | chaîne | Tapez MIME. Détecté automatiquement à partir de l'extension filename en cas d'omission. |
filename | chaîne | Nom de fichier d'origine (utilisé pour la détection du type de contenu et Content-Disposition). |
data | chaîne | Obligatoire. Contenu du fichier codé en base64. |
Supprimer un fichier hébergé¶
curl -s -X DELETE "https://stentor.app/api/v1/listeners/$LISTENER_ID/host?uri=/downloads/update.exe" \
-H "Authorization: Bearer $TOKEN" | jq
Restrictions d'URI
Les URI des fichiers hébergés ne peuvent pas commencer par /api/ ou /c2/ : ces préfixes sont réservés aux routes du protocole C2. Les fichiers sont servis en priorité sur le gestionnaire C2, de sorte que les URI hébergés sont prioritaires pour les chemins correspondants.
Intégration de profils malléables¶
Les champs profile_name et profile_variant attachent un profil C2 malléable au listener, personnalisant tous les indicateurs de trafic HTTP, y compris les URI, les en-têtes, les paramètres, l'encodage du corps et les chaînes User-Agent. Cela transforme le trafic des beacons pour imiter les applications Web légitimes (requêtes jQuery CDN, achats sur Amazon, mises à jour de Microsoft Office, etc.).
curl -s -X POST https://stentor.app/api/v1/listeners \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "HTTPS jQuery Profile",
"relay_id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
"type": "https",
"port": 443,
"profile_name": "jquery",
"profile_variant": "jquery"
}' | jq
Pour une documentation complète sur la syntaxe des profils malléables, les transformations de trafic et les profils disponibles, consultez la page Profils malléables.