Skip to content

C2 Server (C3PO)

Documentation complète disponible

Cette page est un résumé. La documentation exhaustive de C3PO est disponible dans la section dédiée :

C3PO — Control Server — Architecture, installation, TUI, dashboard, API (40+ endpoints), déploiement, sécurité.

Le serveur C2 (Command & Control) C3PO gère la communication avec les agents ESP32 déployés.

Vue d'ensemble

C3PO est le serveur C2 principal d'Espilon, offrant :

  • CLI interactif avec autocomplétion
  • TUI multi-pane (Textual) pour voir tous les devices simultanément
  • Dashboard Web (Flask) avec Dashboard, Cameras, MLAT, OTA, Build, CAN
  • Réception caméra UDP avec enregistrement vidéo
  • Multilatération (MLAT) pour le positionnement RSSI
  • Communication chiffrée ChaCha20 + Protocol Buffers
  • Gestion de groupes de devices
graph TB
    subgraph "ESP32 Agents"
        A1[Agent 1]
        A2[Agent 2]
        A3[Agent 3]
        CAM[ESP32-CAM]
    end

    subgraph "C3PO Server"
        TCP[TCP Server<br/>Port 2626]
        UDP[UDP Receiver<br/>Port 5000]
        WEB[Web Dashboard<br/>Port 8000]
        MLAT[MLAT Engine]
        CLI[CLI / TUI]
    end

    A1 <-->|ChaCha20 + Protobuf| TCP
    A2 <-->|ChaCha20 + Protobuf| TCP
    A3 <-->|ChaCha20 + Protobuf| TCP
    CAM -->|JPEG Frames| UDP

    TCP --> CLI
    UDP --> WEB
    MLAT --> WEB
    CLI --> WEB

Installation

Prérequis

  • Python 3.10+ (testé avec 3.11)
  • pip (gestionnaire de paquets)

Étapes

# 1. Naviguer vers le dossier C2
cd tools/c2

# 2. Créer un environnement virtuel
python3 -m venv .venv

# 3. Activer l'environnement
source .venv/bin/activate

# 4. Installer les dépendances
pip install -r requirements.txt
# 1. Naviguer vers le dossier C2
cd tools\c2

# 2. Créer un environnement virtuel
python -m venv .venv

# 3. Activer l'environnement
.\.venv\Scripts\Activate.ps1

# 4. Installer les dépendances
pip install -r requirements.txt

Dépendances

Package Version Usage
pycryptodome >=3.15.0 Chiffrement ChaCha20
protobuf >=4.21.0 Sérialisation Protocol Buffers
flask >=2.0.0 Dashboard Web + API
python-dotenv >=1.0.0 Configuration .env
textual >=0.40.0 Interface TUI multi-pane
opencv-python >=4.8.0 Traitement vidéo caméra
numpy >=1.24.0 Calculs matriciels
scipy >=1.10.0 Algorithme MLAT

Vérification

python -c "from web.server import UnifiedWebServer; print('OK')"

Configuration

Fichier .env

Copiez .env.example vers .env et ajustez :

cp .env.example .env
.env
# C2 TCP Server
C2_HOST=0.0.0.0
C2_PORT=2626

# Web Dashboard
WEB_HOST=0.0.0.0
WEB_PORT=8000
WEB_USERNAME=admin
WEB_PASSWORD=admin
FLASK_SECRET_KEY=change_this_for_prod

# Camera UDP
UDP_HOST=0.0.0.0
UDP_PORT=5000
CAMERA_SECRET_TOKEN=Sup3rS3cretT0k3n

# MLAT API
MULTILAT_AUTH_TOKEN=multilat_secret_token

# Storage
IMAGE_DIR=static/streams
VIDEO_FPS=10
VIDEO_CODEC=MJPG

Clés de chiffrement

Les clés ChaCha20 doivent correspondre entre le C2 et le firmware ESP32.

# Générer une clé 32 bytes
openssl rand -hex 32

# Générer un nonce 12 bytes
openssl rand -hex 12

Sécurité des clés

  • Ne jamais utiliser les clés par défaut en production
  • Ne jamais commiter les clés dans le repo
  • Les clés doivent être identiques sur le C2 et les ESP32

Lancement

Mode CLI (classique)

python c3po.py

Mode TUI (Textual)

python c3po.py --tui

Le mode TUI affiche :

  • Panneau gauche : Tous les devices connectés avec leurs logs
  • Panneau droit : Logs globaux du système
  • Barre inférieure : Input avec autocomplétion style zsh

Raccourcis TUI

Touche Action
Alt+G Toggle panneau global
Ctrl+L Clear logs globaux
Ctrl+Q Quitter
Esc Focus sur l'input
Tab Autocomplétion
Up / Down Historique

Commandes CLI

Gestion des devices

list

Liste tous les devices connectés :

c2:> list

Connected Devices:
ID            IP Address       Status    Connected For    Last Seen
─────────────────────────────────────────────────────────────────────
ce4f626b      192.168.1.42     online    2m 34s           0s
a1b2c3d4      192.168.1.43     online    15m 12s          2s

send

Envoie une commande à un device :

# À un device spécifique
c2:> send ce4f626b system_uptime

# À tous les devices
c2:> send all system_mem

# À un groupe
c2:> send group scanners mlat start AA:BB:CC:DD:EE:FF

modules

Affiche les commandes ESP disponibles par module :

c2:> modules

╔══════════════════════════════════════════════════════════════╗
║                    ESP MODULES & COMMANDS                     ║
╚══════════════════════════════════════════════════════════════╝

┌─ system ─────────────────────────────────────────────────────┐
│  system_reboot    Reboot ESP32                               │
│  system_mem       Memory info                                │
│  system_uptime    Device uptime                              │
│  system_info      Auto-query on connect                      │
└──────────────────────────────────────────────────────────────┘
...

Gestion des groupes

# Créer/ajouter à un groupe
c2:> group add scanners ce4f626b a1b2c3d4

# Lister les groupes
c2:> group list

# Voir les membres d'un groupe
c2:> group show scanners

# Retirer d'un groupe
c2:> group remove scanners ce4f626b

Services

web

Gère le dashboard web :

c2:> web start     # Démarre sur http://0.0.0.0:8000
c2:> web stop      # Arrête le serveur
c2:> web status    # Affiche le statut + stats MLAT

camera

Gère le récepteur UDP caméra :

c2:> camera start   # Démarre sur UDP port 5000
c2:> camera stop    # Arrête le récepteur
c2:> camera status  # Packets reçus, frames décodés, erreurs

Autres commandes

Commande Description
help [cmd] Aide générale ou par commande
active_commands Commandes en cours d'exécution
clear Efface l'écran (CLI) ou logs globaux (TUI)
exit Quitter C3PO

Commandes ESP (Modules)

Les commandes envoyées aux ESP32 sont organisées par module.

Module System

Commande Description
system_reboot Redémarre l'ESP32
system_mem Affiche la mémoire disponible
system_uptime Temps depuis le boot
system_info Infos complètes (envoyé auto à la connexion)

Module Network

Commande Arguments Description
ping <host> Ping ICMP
arp_scan - Scan ARP du réseau local
proxy_start <ip> <port> Démarre proxy TCP
proxy_stop - Arrête le proxy
dos_tcp <ip> <port> <count> TCP flood (test)

Module FakeAP

Commande Arguments Description
fakeap_start <ssid> [open\|wpa2] [pass] Crée un point d'accès
fakeap_stop - Arrête le Fake AP
fakeap_status - Statut du Fake AP
fakeap_clients - Liste les clients connectés
fakeap_portal_start - Active le portail captif
fakeap_portal_stop - Désactive le portail
fakeap_sniffer_on - Active le sniffer
fakeap_sniffer_off - Désactive le sniffer

Module Recon (Camera + MLAT)

Caméra

Commande Arguments Description
cam_start <ip> <port> Démarre le flux vidéo vers C2
cam_stop - Arrête le flux

MLAT (Multilatération)

Commande Arguments Description
mlat config [gps\|local] <c1> <c2> Configure la position du scanner
mlat mode <ble\|wifi> Mode de scan (BLE ou WiFi)
mlat start <mac> Démarre le scan d'une cible
mlat stop - Arrête le scan
mlat status - Statut du scanner

Exemples MLAT :

# Configurer un scanner en GPS
c2:> send scanner1 mlat config gps 48.8566 2.3522

# Configurer en coordonnées locales (mètres)
c2:> send scanner2 mlat config local 0 5

# Démarrer le scan BLE
c2:> send scanner1 mlat mode ble
c2:> send scanner1 mlat start AA:BB:CC:DD:EE:FF

Dashboard Web

Accès

Après web start, accédez à :

http://localhost:8000

Identifiants par défaut : admin / admin

Pages

Page Description
/dashboard Liste des devices connectés
/cameras Flux caméras en direct + enregistrement
/mlat Visualisation multilatération
/ota Gestion des mises à jour firmware OTA
/build Build firmware depuis le navigateur

Enregistrement Caméra

Sur la page /cameras :

  1. Cliquez sur le bouton record (cercle rouge)
  2. Le timer s'affiche pendant l'enregistrement
  3. Re-cliquez pour arrêter
  4. Les fichiers sont dans static/recordings/

API REST

Authentification par session (login) ou Bearer token :

curl -H "Authorization: Bearer multilat_secret_token" \
     http://localhost:8000/api/devices

Endpoints

Méthode Endpoint Description
GET /api/devices Liste des devices
GET /api/cameras Liste des caméras
GET /api/stats Statistiques serveur
POST /api/recording/start/<id> Démarrer enregistrement
POST /api/recording/stop/<id> Arrêter enregistrement
GET /api/recordings Liste des enregistrements
POST /api/mlat/collect Recevoir données MLAT
GET /api/mlat/state État MLAT (scanners + cible)
POST /api/mlat/config Configurer MLAT
POST /api/mlat/clear Reset MLAT
GET /api/can/frames Frames CAN (device_id, can_id, limit, offset)
GET /api/can/stats Statistiques CAN
GET /api/can/frames/export Export CSV des frames CAN
POST /api/ota/update Déclencher mise à jour OTA
POST /api/build/start Lancer un build firmware
GET /api/build/status Status du build en cours
GET /api/build/log Log du build (offset)
GET /api/build/defaults Defaults depuis deploy.json
POST /api/commands/send Envoyer commande à un device
GET /api/commands/history Historique des commandes

MLAT (Multilatération)

Principe

La multilatération utilise les mesures RSSI de plusieurs scanners pour localiser une cible (device BLE ou WiFi).

graph TB
    subgraph "Scanners ESP32"
        S1[Scanner 1<br/>Position connue]
        S2[Scanner 2<br/>Position connue]
        S3[Scanner 3<br/>Position connue]
    end

    TARGET((Cible<br/>Position ?))

    S1 -.->|RSSI -45| TARGET
    S2 -.->|RSSI -52| TARGET
    S3 -.->|RSSI -48| TARGET

    subgraph "C2 Server"
        MLAT[MLAT Engine<br/>scipy.optimize]
    end

    S1 -->|MLAT:G;lat;lon;rssi| MLAT
    S2 -->|MLAT:G;lat;lon;rssi| MLAT
    S3 -->|MLAT:G;lat;lon;rssi| MLAT

    MLAT -->|Position calculée| WEB[Dashboard]

Configuration

  1. Placer 3+ scanners avec positions connues
  2. Configurer chaque scanner :
    c2:> send scanner1 mlat config gps 48.8566 2.3522
    c2:> send scanner2 mlat config gps 48.8570 2.3525
    c2:> send scanner3 mlat config gps 48.8568 2.3520
    
  3. Démarrer le scan :
    c2:> send group scanners mlat mode ble
    c2:> send group scanners mlat start AA:BB:CC:DD:EE:FF
    
  4. Visualiser sur /mlat

Calibration

Ajustez les paramètres via l'API :

curl -X POST http://localhost:8000/api/mlat/config \
     -H "Authorization: Bearer TOKEN" \
     -H "Content-Type: application/json" \
     -d '{"rssi_at_1m": -40, "path_loss_n": 2.5}'
Paramètre Défaut Description
rssi_at_1m -40 RSSI à 1 mètre (calibration)
path_loss_n 2.5 Exposant path loss (2.0 = espace libre, 3.5 = indoor)
smoothing_window 5 Fenêtre de lissage RSSI

Architecture

tools/C3PO/
├── c3po.py              # Point d'entrée (CLI / TUI)
├── requirements.txt     # Dépendances Python
├── .env.example         # Template configuration
├── core/                # Coeur du système
│   ├── crypto.py        # ChaCha20 encryption
│   ├── device.py        # Classe Device
│   ├── registry.py      # DeviceRegistry
│   ├── groups.py        # GroupRegistry
│   ├── transport.py     # TCP handler + CAN/HP prefix parsing
│   ├── session.py       # Central runtime state
│   └── can_store.py     # CAN frame ring buffer storage
├── commands/            # Command system
│   └── registry.py      # CommandRegistry
├── tui/                 # Interface Textual
│   ├── app.py           # Application TUI
│   ├── commander.py     # Command dispatcher (can, groups, etc.)
│   ├── help.py          # Help system
│   ├── styles/          # CSS Textual
│   └── widgets/         # Composants UI
├── web/                 # Dashboard Flask
│   ├── server.py        # UnifiedWebServer
│   ├── mlat.py          # MlatEngine
│   ├── auth.py          # Decorators auth
│   ├── build_manager.py # Background firmware builder
│   └── routes/          # Blueprints API
│       ├── pages.py     # HTML pages
│       ├── api_devices.py
│       ├── api_cameras.py
│       ├── api_mlat.py
│       ├── api_stats.py
│       ├── api_ota.py
│       ├── api_build.py
│       ├── api_commands.py
│       ├── api_monitor.py
│       └── api_can.py   # CAN frame API
├── streams/             # Réception caméra
│   ├── config.py        # Configuration .env
│   └── udp_receiver.py  # UDP + Recording
├── templates/           # HTML Jinja2
├── static/              # CSS/JS/images
│   ├── streams/         # Frames JPEG (runtime)
│   └── recordings/      # Vidéos AVI (runtime)
├── utils/               # Utilitaires
│   └── display.py       # Formatage console
└── proto/               # Protocol Buffers
    └── c2_pb2.py        # Messages générés

Dépannage

L'agent ne se connecte pas

Vérifications :

  1. Le serveur C2 tourne ? (python c3po.py)
  2. Port 2626 ouvert dans le firewall ?
  3. IP du serveur correcte dans le firmware ?
  4. Clés ChaCha20 identiques ?
# Tester le port
nc -zv IP_SERVEUR 2626
Erreur de déchiffrement

Cause : Clés différentes entre C2 et ESP32

Solution : Vérifier que CRYPTO_KEY et CRYPTO_NONCE sont identiques dans :

  • tools/c2/core/crypto.py
  • idf.py menuconfig → Security
Pas de flux caméra

Vérifications :

  1. camera start lancé sur le C2 ?
  2. cam_start <ip> <port> envoyé à l'ESP32-CAM ?
  3. Token identique ? (CAMERA_SECRET_TOKEN et CAMERA_UDP_TOKEN)
  4. Port UDP 5000 accessible ?
TUI ne se lance pas

Solution :

pip install textual
MLAT ne calcule pas de position

Vérifications :

  1. Au moins 3 scanners actifs ?
  2. Chaque scanner configuré avec sa position ?
  3. Les scanners envoient des données RSSI ?

Sécurité

Production

  • Changez toutes les clés par défaut
  • Utilisez un VPN pour l'accès distant
  • Limitez l'accès au port 2626 (firewall)
  • Changez WEB_USERNAME / WEB_PASSWORD
  • Changez FLASK_SECRET_KEY
  • Changez MULTILAT_AUTH_TOKEN

Précédent : Flasher | Suivant : Modules