Gestion des relais¶
Les relais constituent le pont entre le serveur Stentor et les environnements cibles. Ils fonctionnent sur une infrastructure d'attaque (generalement Kali Linux) et hebergent des listeners C2, generent des payloads, traitent les enregistrements d'implants et acheminent le trafic via WebSocket vers le serveur. Ce guide couvre la creation, le deploiement, l'enregistrement, la surveillance et le depannage des agents de relais.
Architecture¶
Le relais se situe entre le backend Stentor et le reseau cible. Il maintient une connexion WebSocket persistante au serveur pour l'envoi des commandes et execute les listeners C2 locaux auxquels les implants se connectent.
graph LR
subgraph Backend
A[Stentor Server<br/>:8082]
end
subgraph Relay["Relay (Kali)"]
B[WebSocket Client]
C[C2 Listener<br/>HTTP/HTTPS]
D[DNS C2 Server]
E[SMB Pipe Server]
F[Payload Generator]
end
subgraph Target["Target Network"]
G[Implant<br/>Windows]
end
A <-->|WebSocket| B
G -->|HTTPS| C
G -->|DNS queries| D
G -->|SMB named pipe| E
C -->|Events| B
B -->|Commands| C Flux de trafic :
- L'operateur emet une commande via l'interface utilisateur ou l'API de Stentor.
- Le backend envoie une commande WebSocket au relais (par exemple,
queue_task,start_listener,generate_payload). - Le relais execute la commande localement : demarre un listener, met en file d'attente une tache pour un beacon ou genere un binaire de payload.
- Lorsqu'un implant s'enregistre aupres d'un listener heberge par un relais, le relais renvoie un evenement WebSocket au backend (par exemple,
beacon_new,beacon_checkin,task_complete). - Le backend met a jour sa base de donnees et envoie des mises a jour en temps reel a l'interface utilisateur de l'operateur via le CockpitHub WebSocket.
Construire le relais¶
Construisez le binaire de relais a partir de la racine du projet. Le relais est un seul binaire Go statique sans dependances externes.
# From the Stentor project root
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build \
-ldflags="-s -w -X main.Version=1.1.0" \
-o binaries/stentor-relay \
./relay/cmd/relay/
Drapeaux de build expliques :
| Drapeau | Objectif |
|---|---|
GOOS=linux | Compilation croisee pour Linux (le relais fonctionne sur Kali) |
GOARCH=amd64 | Cibler l'architecture x86 64 bits |
CGO_ENABLED=0 | Binaire statique sans dependances de la bibliotheque C |
-s -w | Supprimer les informations de debogage et les symboles DWARF (binaire plus petit) |
-X main.Version=1.1.0 | Integrer la chaine de version pour l'identification |
Identification des versions
Le relais enregistre sa version au demarrage. Utilisez des chaines de version significatives pour suivre quelle version est deployee : Stentor Kali Relay Agent starting... Version: 1.1.0
Deploiement¶
Transfert vers l'hote relais¶
Le binaire de relais est generalement deploye via SCP via un hote de saut (Proxmox) vers la VM de relais Kali :
# Step 1: Dev machine -> Proxmox host
scp -o StrictHostKeyChecking=no binaries/stentor-relay \
root@<proxmox-host>:/tmp/stentor-relay
# Step 2: Proxmox host -> Kali relay
ssh root@<proxmox-host> 'scp -o StrictHostKeyChecking=no \
/tmp/stentor-relay root@<kali-ip>:/opt/stentor-relay/stentor-relay'
Exemple de deploiement en laboratoire
# Using the default lab infrastructure
scp binaries/stentor-relay root@<proxmox-ip>:/tmp/stentor-relay
ssh root@<proxmox-ip> 'sshpass -p "<relay-password>" scp -o StrictHostKeyChecking=no \
/tmp/stentor-relay [email protected]:/opt/stentor-relay/stentor-relay'
Configuration¶
Le relais est entierement configure via des variables d'environnement, generalement stockees dans /opt/stentor-relay/.env. Le relais les lit au demarrage via la directive systemd EnvironmentFile.
Variables obligatoires¶
| Variable | Description | Exemple |
|---|---|---|
BACKEND_URL | Point de terminaison WebSocket du serveur | wss://stentor.app/ws/relay |
RELAY_ID | UUID du relais (doit correspondre a l'enregistrement de la base de donnees) | aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee |
RELAY_SECRET | Secret partage pour l'authentification WebSocket | <random-string> |
Variables du listener C2¶
| Variable | Par defaut | Description |
|---|---|---|
C2_PORT | 443 | Port pour le listener HTTPS C2 par defaut |
C2_CERT_PATH | -- | Certificat TLS pour les listeners HTTPS |
C2_KEY_PATH | -- | Cle privee TLS pour les listeners HTTPS |
C2_STAGING_AUTH_TOKEN | -- | Jeton de porteur pour le point de terminaison intermediaire (vide = non authentifie) |
Variables de service facultatives¶
| Variable | Par defaut | Description |
|---|---|---|
LOG_LEVEL | info | Verbosite de la journalisation : debug, info, warn, error |
RECONNECT_INTERVAL_SECONDS | 5 | Delai entre les tentatives de reconnexion WebSocket |
HEARTBEAT_INTERVAL_SECONDS | 30 | Frequence de battement de coeur vers le backend |
SMTP_PORT | 25 | Port du serveur SMTP integre (0 = desactive) |
SMTP_EXTERNAL_HOST | -- | Relais SMTP externe pour le transfert |
SMTP_EXTERNAL_PORT | 587 | Port relais SMTP externe |
TRACKING_PORT | 80 | Port du serveur de suivi HTTP (0 = desactive) |
DNS_PORT | 0 | Port du serveur DNS C2 (0 = desactive) |
DNS_DOMAIN | -- | Suffixe de domaine pour les requetes DNS C2 (obligatoire si DNS_PORT > 0) |
DNS_TTL | 60 | TTL pour les reponses DNS C2 en secondes |
PROFILER_PORT | 0 | Port du serveur HTTP du profileur systeme (0 = desactive) |
HEALTH_PORT | 9090 | Port du point de terminaison de sante HTTP (0 = desactive) |
STATE_DIR | /var/lib/stentor-relay | Repertoire de persistance de l'etat des listeners |
Exigence DNS C2
Si DNS_PORT est defini sur une valeur non nulle, DNS_DOMAIN doit egalement etre configure. Le relais ne demarrera pas si le port DNS est active sans domaine.
Exemple de fichier .env :
# Required
BACKEND_URL=wss://stentor.app/ws/relay
RELAY_ID=aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
RELAY_SECRET=your-shared-secret-here
# C2 listener
C2_PORT=8443
C2_CERT_PATH=/opt/stentor-relay/certs/cert.pem
C2_KEY_PATH=/opt/stentor-relay/certs/key.pem
# Optional services
LOG_LEVEL=info
SMTP_PORT=0
TRACKING_PORT=0
DNS_PORT=0
PROFILER_PORT=0
Service systeme¶
Creez un service systemd pour un demarrage automatique et un redemarrage en cas d'echec.
Fichier de service (/etc/systemd/system/stentor-relay.service) :
[Unit]
Description=Stentor Relay Agent
After=network.target
[Service]
Type=simple
User=root
WorkingDirectory=/opt/stentor-relay
ExecStart=/opt/stentor-relay/stentor-relay
EnvironmentFile=/opt/stentor-relay/.env
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
Commandes de gestion des services :
# Install and enable the service
sudo systemctl daemon-reload
sudo systemctl enable stentor-relay
# Start the relay
sudo systemctl start stentor-relay
# Check status
sudo systemctl status stentor-relay
# View logs (real-time)
journalctl -u stentor-relay -f
# View recent logs
journalctl -u stentor-relay --since "1 hour ago"
# Restart after configuration change
sudo systemctl restart stentor-relay
Verification du demarrage
En cas de demarrage reussi, le relais enregistre sa configuration et son etat de connexion :
Inscription¶
Avant qu'un relais puisse se connecter via WebSocket, il doit exister dans la base de donnees Stentor. Le gestionnaire WebSocket de /ws/relay appelle relayRepo.GetByID() et renvoie un 404 Not Found si l'UUID du relais ne se trouve pas dans la table relays.
Critique : inscrivez-vous avant de vous connecter
Le relais doit etre enregistre dans la base de donnees avant de demarrer le service de relais. Si le relais est introuvable dans la base de donnees, la negociation WebSocket echouera avec une erreur 404 et le relais ne parviendra pas a se connecter a plusieurs reprises.
Via API¶
Creez un enregistrement de relais via l'API REST. La reponse inclut le id genere - utilisez-le comme RELAY_ID dans le fichier .env du relais.
Via SQL Direct¶
Utile apres une reconstruction de base de donnees (par exemple, deploiement --rebuild-db) lorsque vous devez reenregistrer un relais avec son UUID existant :
INSERT INTO relays (id, name, description, ip_address, status)
VALUES (
'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee',
'Kali Relay',
'Primary attack relay',
'10.0.0.50',
'online'
)
ON CONFLICT (id) DO NOTHING;
Executer via Docker :
ssh root@<proxmox> 'ssh [email protected] \
"docker exec -i stentor-db psql -U stentor -d stentor_db"' <<< \
"INSERT INTO relays (id, name, description, ip_address, status) \
VALUES ('aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee', 'Kali Relay', \
'Primary attack relay', '10.0.0.50', 'online') \
ON CONFLICT (id) DO NOTHING;"
Apres inscription, redemarrez le service relais pour qu'il etablisse la connexion WebSocket :
Protocole WebSocket¶
Le relais communique avec le backend via une connexion WebSocket persistante a /ws/relay. L'authentification utilise des en-tetes personnalises.
Authentification¶
Le relais s'authentifie a l'aide de deux en-tetes sur la demande de mise a niveau WebSocket :
| En-tete | Description |
|---|---|
X-Relay-ID | Relais UUID correspondant a un enregistrement de base de donnees |
X-Relay-Secret | Secret partage correspondant au RELAY_SECRET du serveur |
Les deux en-tetes peuvent egalement etre transmis en tant que parametres de requete (relay_id et secret).
Alternative mTLS
Les relais peuvent egalement s'authentifier a l'aide de certificats clients TLS (mTLS) au lieu des en-tetes de secret partage. Voir Authentification mTLS pour les instructions de configuration.
Types de messages¶
Tous les messages suivent un format d'enveloppe JSON avec les champs type, id, correlation_id, timestamp et payload.
| Type | Direction | Description |
|---|---|---|
command | Serveur -> Relais | Initie des actions (demarrer le listener, mettre en file d'attente, generer le payload) |
response | Relais -> Serveur | Renvoie les resultats de la commande avec l'ID de correlation |
event | Relais -> Serveur | Notifications asynchrones (beacon nouvelle, tache terminee, statut d'ecoute) |
heartbeat | Bidirectionnel | Surveillance de l'etat de la connexion |
ack | Relais -> Serveur | Accuse de reception de la commande avant la fin de l'execution |
Commandes cles (Serveur -> Relais)¶
| Commande | Description |
|---|---|
start_listener | Demarrer un listener C2 sur le relais |
stop_listener | Arreter un listener en cours d'execution |
queue_task | Mettre une tache en file d'attente pour la livrer a un beacon |
generate_payload | Construire un binaire d'implant (EXE, DLL, shellcode, etc.) |
send_email | Envoyer un email de phishing via le serveur SMTP du relais |
tunnel | Transferer les trames du tunnel SOCKS vers un beacon |
host_file | Heberger un fichier sur un URI personnalise sur un listener |
unhost_file | Supprimer un fichier heberge d'un listener |
Evenements cles (Relais -> Serveur)¶
| Evenement | Description |
|---|---|
beacon_new | Nouvel implant enregistre |
beacon_checkin | Beacon existante enregistree |
beacon_dead | Beacon a manque les enregistrements et a ete marque comme mort |
task_complete | Execution de la tache terminee avec des resultats |
listener_started | Le listener a demarre avec succes |
listener_stopped | Le listener s'est arrete |
listener_error | Le listener a rencontre une erreur |
Reference complete du protocole
Pour une documentation complete sur le format de message, les definitions de champs et les diagrammes de sequence, voir Protocole WebSocket.
Surveillance de la sante¶
Statut du relais via API¶
Verifiez l'etat de tous les relais enregistres :
curl -s https://stentor.app/api/v1/relays \
-H "Authorization: Bearer $TOKEN" | jq '.[] | {id, name, status}'
Le champ status reflete l'etat de la connexion WebSocket :
| Statut | Signification |
|---|---|
connected | Le relais a une connexion WebSocket active |
disconnected | Le relais etait precedemment connecte mais la connexion a ete interrompue |
offline | Le relais ne s'est jamais connecte (fraichement inscrit) |
Point de terminaison /healthz¶
Chaque relais expose un point de terminaison HTTP de sante sur un port dedie (par defaut : 9090, configurable via HEALTH_PORT). Ce point de terminaison fonctionne sur un port separe des listeners C2 pour eviter les conflits et est accessible sans authentification.
Champs de la reponse :
{
"status": "healthy",
"uptime": 86400,
"active_listeners": 2,
"connected_beacons": 5,
"last_checkin": "2025-06-15T14:30:00Z",
"version": "1.1.0",
"timestamp": "2025-06-15T14:31:00Z"
}
| Champ | Type | Description |
|---|---|---|
status | string | Toujours "healthy" lorsque le point de terminaison repond |
uptime | int64 | Secondes depuis le demarrage du processus du relais |
active_listeners | int | Nombre de listeners C2 actuellement en cours d'execution |
connected_beacons | int | Nombre de beacons enregistres sur ce relais |
last_checkin | string | Horodatage RFC 3339 du dernier enregistrement de beacon (omis si aucun beacon ne s'est enregistre) |
version | string | Chaine de version du binaire du relais |
timestamp | string | Heure UTC actuelle au format RFC 3339 |
Desactiver le point de terminaison de sante
Definissez HEALTH_PORT=0 dans le fichier .env du relais pour desactiver entierement le point de terminaison /healthz. Cela peut etre utile sur les relais ou l'exposition reseau doit etre minimisee.
Interrogation de sante cote serveur¶
Le serveur Stentor interroge automatiquement le point de terminaison /healthz de tous les relais connectes pour maintenir les donnees de sante a jour.
Comportement de l'interrogation :
- Le serveur interroge toutes les 30 secondes tous les relais avec le statut
connectedet une adresse IP non vide. - Utilise une requete HTTP GET standard (pas le canal WebSocket) pour plus de simplicite et d'isolation.
- Chaque requete d'interrogation a un delai d'attente de 5 secondes pour eviter de bloquer sur des relais qui ne repondent pas.
- Les donnees de sante sont persistees dans la base de donnees a l'aide de champs nullables -- les valeurs
nilindiquent que le relais n'a pas encore ete interroge.
Aucune configuration requise
L'interrogation de sante cote serveur demarre automatiquement au lancement du backend. Il n'y a pas de variables d'environnement cote serveur a configurer -- le serveur interroge toujours sur le port 9090.
Indicateur de sante dans l'interface¶
Le selecteur de relais dans l'interface utilisateur Stentor affiche un indicateur de sante a cote du nom de chaque relais :
| Indicateur | Condition | Signification |
|---|---|---|
| Donnees de sante recues dans les 60 secondes | Le relais est en bonne sante et reactif | |
| Donnees de sante recues dans les 5 minutes | Le relais peut rencontrer des problemes | |
| Donnees de sante datant de plus de 5 minutes ou pas encore recues | Le relais est obsolete ou n'a jamais signale sa sante |
L'interface affiche egalement le nombre de beacons et de listeners a cote du nom du relais lorsque les donnees de sante sont disponibles.
Battement de coeur WebSocket¶
Le relais envoie des messages de battement de coeur periodiques au backend a l'intervalle configure (par defaut : toutes les 30 secondes). La payload du battement de coeur comprend l'ID du relais et l'etat actuel (idle, busy ou error).
Si le backend ne recoit pas de battement de coeur dans l'intervalle prevu, il marque le relais comme potentiellement deconnecte. Le RelayHub met automatiquement a jour l'etat du relais dans la base de donnees lorsque les connexions sont etablies ou perdues.
Battement de coeur vs. interrogation de sante
Le battement de coeur WebSocket surveille la connexion entre le relais et le serveur (le WebSocket est-il actif ?). L'interrogation /healthz surveille l'etat operationnel du relais (combien de listeners, beacons, temps de fonctionnement). Les deux sont des mecanismes independants.
Surveillance des journaux¶
Surveillez l'etat du relais en temps reel via le journal systemd :
# Real-time log stream
journalctl -u stentor-relay -f
# Filter for errors only
journalctl -u stentor-relay -p err
# Logs from the last boot
journalctl -u stentor-relay -b
Messages cles du journal a surveiller :
| Message du journal | Signification |
|---|---|
Relay Agent ready, awaiting commands | Demarrage reussi |
C2 server listening on :8443 | Listener C2 actif |
WebSocket client error | La connexion au backend a echoue |
Received signal SIGTERM, shutting down | Arret progressif initie |
Command X completed successfully | Tache executee |
Command X failed | Erreur d'execution de la tache |
Failover des beacons et resilience des relais¶
Stentor prend en charge le failover multi-relais pour la resilience des beacons. Si un relais tombe en panne, les beacons peuvent automatiquement basculer vers un relais de secours et recuperer de maniere transparente le relais principal lorsqu'il revient.
Liste d'URL de failover¶
Les beacons peuvent etre construits avec plusieurs URL C2. La premiere URL est toujours le relais principal ; les URL supplementaires sont des relais de secours. Les deploiements a URL unique ne sont pas affectes -- le failover est retrocompatible.
Configurez les URL de failover au moment du build via une variable d'environnement ou un drapeau de l'editeur de liens :
# Environment variable (comma-separated)
IMPLANT_C2_URLS=https://relay1.example.com:8443,https://relay2.example.com:8443
# Or via Go ldflags at build time
-ldflags="-X main.DefaultC2URLs=https://relay1.example.com:8443,https://relay2.example.com:8443"
Comportement du failover¶
Lorsqu'un beacon rencontre des echecs consecutifs de communication avec son relais actuel, il bascule automatiquement vers l'URL suivante dans la liste :
| Parametre | Par defaut | Description |
|---|---|---|
MaxFailures | 3 | Nombre d'echecs consecutifs avant de basculer vers le relais suivant |
Apres 3 echecs consecutifs sur l'hote actuel, le beacon passe a l'URL suivante dans la liste de failover. Si la derniere URL echoue egalement, il revient a la premiere.
graph LR
B[Beacon] -->|3 echecs| R1[Relay 1<br/>Principal]
R1 -.->|en panne| X1[X]
B -->|bascule| R2[Relay 2<br/>Secours]
R2 -->|fonctionne| OK[Continuer] Recuperation avec preference pour le principal¶
Lorsqu'un beacon opere sur un relais de secours, il sonde periodiquement le relais principal pour verifier s'il a recupere. Cela garantit que les beacons reviennent toujours au relais prefere lorsque possible.
| Parametre | Par defaut | Description |
|---|---|---|
PrimaryCheckInterval | 5 | Requetes reussies sur un secours avant de sonder le principal |
PrimaryCheckTimeout | 5s | Delai d'attente pour la sonde de recuperation du principal |
Flux de recuperation :
- Le beacon fonctionne sur un relais de secours apres un failover.
- Apres 5 requetes reussies sur le secours, le beacon envoie une sonde legere (enregistrement minimal) vers l'URL du principal.
- Si le principal repond dans les 5 secondes, le beacon bascule de maniere transparente vers le principal.
- Si le principal est toujours en panne, le beacon reste sur le secours et reessaie apres 5 autres requetes reussies.
Transparent pour les operateurs
Le failover et la recuperation se produisent automatiquement sans intervention de l'operateur. Le beacon continue d'executer les taches normalement tout au long du processus. Les operateurs peuvent surveiller a quel relais un beacon est connecte via l'interface Cockpit.
Persistance de l'etat des listeners¶
Les relais persistent toutes les configurations de listeners actifs sur le disque afin de pouvoir les restaurer automatiquement apres un redemarrage ou un crash -- aucune intervention de l'operateur n'est requise.
Fonctionnement :
- L'etat des listeners est sauvegarde dans un fichier JSON dans le repertoire
STATE_DIR(par defaut :/var/lib/stentor-relay). - Utilise des ecritures atomiques (ecriture dans un fichier temporaire, puis renommage) pour la securite en cas de crash -- les ecritures partielles ne corrompent jamais le fichier d'etat.
- L'etat est sauvegarde apres chaque demarrage ou arret de listener, avec un delai de 200 ms pour confirmer le succes de l'operation.
- Au redemarrage, le relais lit le fichier d'etat et redemarre automatiquement tous les listeners precedemment actifs.
Configuration :
Permissions du repertoire
Le repertoire STATE_DIR doit etre accessible en ecriture par le processus du relais. En execution en tant que root (typique pour les deploiements Kali), le repertoire par defaut /var/lib/stentor-relay fonctionne immediatement. Pour les deploiements non-root, assurez-vous que le repertoire existe et a les permissions appropriees.
Exemple de configuration de failover¶
Un deploiement de failover complet avec deux relais et la persistance de l'etat des listeners :
# Beacon build with failover URLs (primary + backup)
IMPLANT_C2_URLS=https://relay1.example.com:8443,https://relay2.example.com:8443
# Relay 1 .env (primary)
BACKEND_URL=wss://stentor.app/ws/relay
RELAY_ID=aaaaaaaa-1111-1111-1111-111111111111
RELAY_SECRET=shared-secret
STATE_DIR=/var/lib/stentor-relay
HEALTH_PORT=9090
# Relay 2 .env (backup)
BACKEND_URL=wss://stentor.app/ws/relay
RELAY_ID=bbbbbbbb-2222-2222-2222-222222222222
RELAY_SECRET=shared-secret
STATE_DIR=/var/lib/stentor-relay
HEALTH_PORT=9090
Authentification mTLS¶
mTLS (mutual TLS) ajoute une authentification par certificat client par relais a la connexion WebSocket. Il fournit une verification d'identite cryptographique comme alternative aux en-tetes de secret partage.
Apercu¶
mTLS est additif -- lorsqu'il est configure, le relais presente un certificat client lors de la negociation TLS. Le serveur verifie le certificat par rapport a une autorite de certification (CA) de confiance et extrait l'UUID du relais a partir du Common Name (CN) du certificat. L'authentification par secret partage reste disponible en tant que solution de repli pour la retrocompatibilite.
flowchart TD
R[Le relais se connecte au serveur] --> TLS{Certificat client<br/>present ?}
TLS -->|Oui| V[Verifier le certificat par rapport au pool CA]
V --> CN[Extraire l'UUID du relais du CN]
CN --> AUTH1[Authentifie via mTLS]
TLS -->|Non| REQ{RELAY_MTLS_REQUIRED<br/>= true ?}
REQ -->|Oui| REJECT[Rejeter la connexion]
REQ -->|Non| SECRET[Verifier l'en-tete X-Relay-Secret]
SECRET --> AUTH2[Authentifie via secret partage] Generation de certificats¶
Generez une CA et un certificat client de relais a l'aide d'OpenSSL. Le CN du certificat doit suivre le format relay-{uuid} -- le serveur extrait l'UUID du relais a partir de ce champ.
# 1. Generate CA key and certificate (one-time setup)
openssl genrsa -out ca.key 4096
openssl req -new -x509 -key ca.key -out ca.crt -days 3650 \
-subj "/CN=Stentor Relay CA"
# 2. Generate relay client key and CSR
# CN must be "relay-{uuid}" matching the relay's RELAY_ID
openssl genrsa -out relay.key 4096
openssl req -new -key relay.key -out relay.csr \
-subj "/CN=relay-aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
# 3. Sign the relay certificate with the CA
openssl x509 -req -in relay.csr -CA ca.crt -CAkey ca.key \
-CAcreateserial -out relay.crt -days 365
Le format du CN est critique
Le Common Name doit etre exactement relay-{uuid} (par exemple, relay-25b2e4d7-8b7f-411f-8fe0-7faed06b90d1). Le serveur analyse ce champ pour extraire l'UUID du relais pour la verification d'identite. Un format de CN incorrect entrainera un echec d'authentification avec ErrInvalidCertCN.
Configuration du serveur¶
Configurez le serveur Stentor pour accepter les connexions mTLS des relais :
| Variable | Par defaut | Description |
|---|---|---|
RELAY_CA_CERT_PATH | -- | Chemin vers le fichier PEM du certificat CA pour verifier les certificats clients des relais |
RELAY_MTLS_REQUIRED | false | Defini a true pour rejeter l'authentification par secret partage et imposer mTLS uniquement |
Le serveur charge le pool de certificats CA au demarrage et l'utilise pour verifier la chaine de certificats presentee par les relais qui se connectent. Il verifie egalement la validite temporelle du certificat (non expire, pas encore valide) et verifie l'utilisation de cle etendue ExtKeyUsageClientAuth.
Configuration du relais¶
Configurez le relais pour presenter un certificat client lors de la connexion au serveur :
| Variable | Par defaut | Description |
|---|---|---|
MTLS_CERT_PATH | -- | Chemin vers le certificat client PEM du relais |
MTLS_KEY_PATH | -- | Chemin vers la cle privee PEM du client relais |
MTLS_CA_CERT_PATH | -- | Certificat CA optionnel pour verifier le certificat du serveur |
Certificat et cle requis ensemble
MTLS_CERT_PATH et MTLS_KEY_PATH doivent tous deux etre definis. Definir un seul d'entre eux provoquera une erreur de validation de configuration au demarrage du relais.
Lorsque MTLS_CA_CERT_PATH n'est pas defini cote relais, il utilise le magasin de certificats du systeme (ou InsecureSkipVerify dans les environnements de developpement avec des certificats de serveur auto-signes).
Exemple de fichier .env du relais avec mTLS :
# Required
BACKEND_URL=wss://stentor.app/ws/relay
RELAY_ID=aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
RELAY_SECRET=your-shared-secret-here
# mTLS authentication
MTLS_CERT_PATH=/opt/stentor-relay/certs/relay.crt
MTLS_KEY_PATH=/opt/stentor-relay/certs/relay.key
MTLS_CA_CERT_PATH=/opt/stentor-relay/certs/ca.crt
Migration du secret partage vers mTLS¶
Suivez ces etapes pour migrer un relais existant de l'authentification par secret partage vers mTLS sans temps d'arret :
Etape 1 : Generer les certificats
# Generate CA and relay certificates (see Certificate Generation above)
openssl genrsa -out ca.key 4096
openssl req -new -x509 -key ca.key -out ca.crt -days 3650 \
-subj "/CN=Stentor Relay CA"
openssl genrsa -out relay.key 4096
openssl req -new -key relay.key -out relay.csr \
-subj "/CN=relay-<your-relay-uuid>"
openssl x509 -req -in relay.csr -CA ca.crt -CAkey ca.key \
-CAcreateserial -out relay.crt -days 365
Etape 2 : Deployer le certificat CA sur le serveur
Copiez ca.crt sur le serveur et definissez RELAY_CA_CERT_PATH dans le .env du serveur. Redemarrez le backend.
Etape 3 : Deployer le certificat/cle client sur le relais
Copiez relay.crt et relay.key sur l'hote du relais (par exemple, /opt/stentor-relay/certs/). Definissez MTLS_CERT_PATH et MTLS_KEY_PATH dans le .env du relais.
Etape 4 : Redemarrer le relais
Le relais s'authentifiera desormais via mTLS. Le secret partage (en-tete X-Relay-Secret) reste comme solution de repli.
Etape 5 : Verifier le fonctionnement de mTLS
Consultez les journaux du serveur pour les messages d'authentification mTLS :
Etape 6 : Imposer mTLS uniquement (optionnel)
Une fois que tous les relais utilisent mTLS, desactivez optionnellement l'authentification par secret partage :
Redemarrez le backend. Les relais sans certificats clients valides ne pourront plus se connecter.
Testez avant d'imposer
Ne definissez RELAY_MTLS_REQUIRED=true qu'apres avoir confirme que tous les relais s'authentifient avec succes via mTLS. Definir ce drapeau avec des relais mal configures les verrouillera.
Depannage¶
| Symptome | Cause | Corriger |
|---|---|---|
| 404 sur connexion WebSocket | L'UUID du relais n'est pas dans la base de donnees | Enregistrez le relais via API ou SQL direct avant de demarrer le service. Verifiez que RELAY_ID dans .env correspond a l'enregistrement de la base de donnees. |
| 401 Non autorise | Mauvais RELAY_SECRET | Verifiez que le RELAY_SECRET du relais correspond a la configuration .env du serveur. Les deux parties doivent utiliser le meme secret partage. |
| La connexion est interrompue a plusieurs reprises | Instabilite du reseau ou debordement de tampon WebSocket | Verifiez les journaux de relais avec journalctl -u stentor-relay -f. Verifiez la connectivite reseau au backend. Le relais se reconnecte automatiquement toutes les 5 secondes par defaut. |
| Le listener ne demarre pas | Port deja utilise ou autorisation refusee | Recherchez les processus conflictuels : ss -tlnp \| grep <port>. Utilisez sudo ou ports >= 1024 pour eviter les problemes d'autorisation. |
| La generation du payload echoue | Chaine d'outils Go ou espace disque manquant | Verifiez que Go est installe sur le relais : go version. Verifiez le disque disponible : df -h /opt/stentor-relay. |
| Le beacon n'apparait pas | Le listener n'a pas demarre ou ACL reseau | Verifiez l'etat du listener via l'API : GET /api/v1/listeners. Verifiez les regles de pare-feu entre l'IP cible et l'IP relais. |
| "echec de la validation de la configuration" | Variables d'environnement manquantes ou invalides | Verifiez le journal du relais pour l'erreur de validation specifique. Assurez-vous que toutes les variables requises (BACKEND_URL, RELAY_ID) sont definies. Verifiez que BACKEND_URL commence par ws:// ou wss://. |
| DNS C2 ne repond pas | Conflit de port DNS ou domaine manquant | Assurez-vous que DNS_DOMAIN est defini lorsque DNS_PORT > 0. Verifiez les conflits de ports : ss -ulnp \| grep <port-dns>. |
| L'envoi SMTP echoue | Relais externe mal configure | Verifiez SMTP_EXTERNAL_HOST, SMTP_EXTERNAL_PORT et les informations d'identification. Testez la connectivite SMTP a partir de l'hote relais. |
Commandes de diagnostic¶
# Check relay process
systemctl status stentor-relay
# View relay configuration (from logs)
journalctl -u stentor-relay | head -20
# Test WebSocket connectivity
curl -s -o /dev/null -w "%{http_code}" \
-H "X-Relay-ID: <relay-id>" \
-H "X-Relay-Secret: <secret>" \
https://stentor.app/ws/relay
# Check listening ports on relay
ss -tlnp | grep stentor
# Verify network path to target
ping -c 3 <target-ip>
# Check TLS certificate expiry
openssl x509 -in /opt/stentor-relay/certs/cert.pem -noout -dates
Architecture multi-relais¶
Stentor prend en charge plusieurs connexions de relais simultanees pour les operations segmentees ou distribuees.
graph TB
subgraph Backend
S[Stentor Server]
end
subgraph External["External Network"]
R1[Relay 1<br/>Internet-facing<br/>HTTPS listener]
end
subgraph Internal["Internal Network"]
R2[Relay 2<br/>Post-pivot<br/>SMB listener]
end
subgraph DMZ
R3[Relay 3<br/>DNS C2 listener]
end
S <-->|WebSocket| R1
S <-->|WebSocket| R2
S <-->|WebSocket| R3
I1[Implant A] -->|HTTPS| R1
I2[Implant B] -->|SMB pipe| R2
I3[Implant C] -->|DNS| R3 Concepts cles¶
-
Chaque listener est lie a un relais specifique via le champ
relay_iddans la configuration du listener. Lorsque vous creez un listener, vous specifiez quel relais doit l'heberger. -
Les beacons s'enregistrent aupres du relais qui heberge leur listener. Un beacon deployee via un listener HTTPS sur le relais 1 communiquera toujours via le relais 1.
-
Les tunnels SOCKS peuvent utiliser n'importe quel relais connecte pour l'acheminement du trafic. Le RelayHub selectionne le premier relais disponible pour la livraison des trames du tunnel.
-
Plusieurs relais peuvent desservir differents segments du reseau. Utilisez des relais distincts pour :
- Infrastructure accessible sur Internet (listeners HTTPS)
- Pivots de reseau interne (listeners de canal SMB)
- Canaux secrets (DNS C2)
- Repartition geographique dans differentes regions
Modeles de deploiement¶
| Modele | Relais | Cas d'utilisation |
|---|---|---|
| Relais simple | 1 | Tests en laboratoire, engagements simples |
| Double relais | 2 | Acces reseau externe + interne |
| Multi-segments | 3+ | Environnements complexes avec segmentation du reseau |
| Geographique | 2+ | Cibles distribuees sur plusieurs sites |
Affectation des listeners¶
Lors de la creation d'un listener, precisez le relais cible :
# Create HTTPS listener on Relay 1
curl -s -X POST https://stentor.app/api/v1/listeners \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "External HTTPS",
"type": "https",
"host": "10.0.0.50",
"port": 8443,
"relay_id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
}'
# Create SMB listener on Relay 2 (internal)
curl -s -X POST https://stentor.app/api/v1/listeners \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Internal SMB",
"type": "smb_pipe",
"host": "192.168.1.50",
"port": 445,
"relay_id": "<internal-relay-uuid>"
}'
Mettre a jour un relais¶
Pour deployer une nouvelle version du binaire du relais :
- Construisez le nouveau binaire sur votre machine de developpement.
- Transfert via le modele d'hote de saut decrit ci-dessus.
- Redemarrez le service :
# On the relay host (or via SSH)
sudo systemctl restart stentor-relay
# Verify the new version
journalctl -u stentor-relay | grep "Version:"
Le relais retablit automatiquement sa connexion WebSocket au redemarrage. Les listeners actifs sont automatiquement restaures a partir de l'etat persiste (voir Persistance de l'etat des listeners) -- aucun redemarrage manuel n'est requis.
Recuperation automatique des listeners
Les listeners sont desormais persistes sur le disque et auto-restaures au redemarrage du relais. Vous n'avez plus besoin de redemarrer manuellement les listeners apres la mise a jour du binaire du relais.