Opérations sur un lab en cours
Opérations sur un lab en cours (API Scenario)
Ce guide couvre les opérations sur un lab en cours d'exécution via l'API Scenario : lancer un lab avec une intégration défensive (une chaîne de collecteurs de logs comme Splunk), puis récupérer le rapport d'attaque et les alertes de sécurité déclenchées.
Prérequis : un jeton d'accès et un identifiant d'espace de travail — voir le guide d'authentification.
export BASE="https://app.mantis-platform.io/api/scenario/lab"
export TOKEN="<votre jeton d'accès>"
export WORKSPACE_ID="<votre workspace id>"1. Lancer un lab avec une intégration défensive (Splunk)
Les intégrations défensives sont déployées via la liste log_collectors dans lab_config. Une chaîne enchaîne des agents (qui expédient les logs) → un agrégateur (ex. logstash) → un SIEM (ex. Splunk).
Découvrir les collecteurs disponibles
GET /log_collector renvoie le catalogue (types de location autorisés, mandatory_inputs, clés user_config).
curl "$BASE/log_collector" \
-H "Authorization: Bearer $TOKEN" \
-H "X-Workspace-Id: $WORKSPACE_ID"import requests
BASE = "https://app.mantis-platform.io/api/scenario/lab"
HEADERS = {"Authorization": f"Bearer {TOKEN}", "X-Workspace-Id": WORKSPACE_ID}
for c in requests.get(f"{BASE}/log_collector", headers=HEADERS).json():
print(c["collector_name"], c["collector_type"], "requiert :", c["mandatory_inputs"])Construire la chaîne Splunk
Une configuration Splunk fonctionnelle : winlogbeat (agent, sous Windows) → logstash (agrégateur) → splunk (agrégateur). Splunk requiert une entrée logstash et ne prend pas de user_config (identifiants UI par défaut : admin / AmossysSPLUNK35;). Le champ output de chaque entrée nomme l'instance suivante.
[
{
"instance_name": "winlogbeat_windows",
"collector_name": "winlogbeat",
"collector_type": "agent",
"location": [{ "location_type": "system_type", "value": "windows" }],
"output": [{ "instance_name": "logstash01", "collector_name": "logstash", "collector_type": "aggregator" }]
},
{
"instance_name": "logstash01",
"collector_name": "logstash",
"collector_type": "aggregator",
"location": [{ "location_type": "new_node", "value": "logstash01" }],
"output": [{ "instance_name": "splunk01", "collector_name": "splunk", "collector_type": "aggregator" }]
},
{
"instance_name": "splunk01",
"collector_name": "splunk",
"collector_type": "aggregator",
"location": [{ "location_type": "new_node", "value": "splunk01" }],
"output": []
}
]Vous pouvez éventuellement valider le câblage avec POST /log_collector/config_check (envoyez le tableau brut ci-dessus ; il renvoie {"requirements_met": bool, "errors": {...}}).
Lancer avec la chaîne
Intégrez le tableau dans lab_config.log_collectors puis appelez run_lab :
curl -X POST "$BASE/scenario/run_lab?workspace_id=$WORKSPACE_ID" \
-H "Authorization: Bearer $TOKEN" \
-H "X-Workspace-Id: $WORKSPACE_ID" \
-H "Content-Type: application/json" \
-d '{
"lab_config": {
"content_type": "KILLCHAIN",
"content_name": "my-scenario",
"scenario_profile": "default",
"log_collectors": [ /* le tableau ci-dessus */ ]
}
}'splunk_pipeline = [ ... ] # le tableau ci-dessus
lab_config = {
"content_type": "KILLCHAIN",
"content_name": "my-scenario",
"scenario_profile": "default",
"log_collectors": splunk_pipeline,
}
resp = requests.post(
f"{BASE}/scenario/run_lab",
params={"workspace_id": WORKSPACE_ID},
json={"lab_config": lab_config},
headers=HEADERS,
)
resp.raise_for_status()
lab_id = resp.json()
print("Lab lancé :", lab_id)2. Récupérer le rapport d'attaque
GET /runner/{lab_id}/attack_report renvoie un tableau JSON des étapes d'attaque jouées. Chaque entrée porte un id, un status, les dates started_date / last_update, les target_nodes concernés et, pour les étapes d'attaque, un worker décrivant la technique (données MITRE, titre, …).
Il se remplit dès que les attaques commencent (statut du lab SCENARIO_EXECUTION ou après) et vaut [] avant cela — il n'y a pas d'erreur « pas encore prêt », interrogez donc en boucle selon le statut du lab.
curl "$BASE/runner/$LAB_ID/attack_report" -H "Authorization: Bearer $TOKEN"import time
def wait_for_report(lab_id):
while True:
report = requests.get(f"{BASE}/runner/{lab_id}/attack_report", headers=HEADERS).json()
if report:
return report
time.sleep(10)
for step in wait_for_report(lab_id):
print(step["id"], step["status"], step.get("worker", {}).get("title"))3. Récupérer les alertes de sécurité
GET /runner/{lab_id}/security_alerts renvoie {"<produit>": [<SecurityAlert>, ...]} — une clé par SIEM/EDR configuré (ex. "Splunk"). Chaque alerte est reliée au rapport d'attaque via correlated_attacks (liste d'identifiants d'étapes d'attaque) ; une liste vide peut indiquer un faux positif.
Les alertes sont produites par une corrélation post-exécution : elles n'apparaissent qu'après la fin du lab (SCENARIO_FINISHED), uniquement si un SIEM/EDR capable de lever des alertes a été déployé, et selon une cadence périodique (~50 s) tributaire de la latence d'ingestion du SIEM. Avant cela l'endpoint renvoie {} — interrogez en boucle.
curl "$BASE/runner/$LAB_ID/security_alerts" -H "Authorization: Bearer $TOKEN"alerts = requests.get(f"{BASE}/runner/{lab_id}/security_alerts", headers=HEADERS).json()
for product, product_alerts in alerts.items():
for a in product_alerts:
print(product, a["alert_name"], a["alert_status"], "-> attaques", a["correlated_attacks"])Exemple de réponse :
{
"Splunk": [
{
"alert_name": "Suspicious PowerShell Execution",
"alert_status": "NEW",
"signature_name": "Encoded PowerShell command",
"mitre_data": { "technique": {"id": "T1059.001", "name": "PowerShell"} },
"asset_hostname": "WIN10",
"start_time": "2025-10-08T20:51:25+00:00",
"end_time": "2025-10-08T20:51:59+00:00",
"correlated_attacks": [3828]
}
]
}Étape suivante
Pour jouer des actions red-team (commandes, Atomic Red Team) sur le lab, voir Opérations red-team.

