Aller au contenu
TAAF-OPS --:-- UTC

TP 3 — Couverture MITRE & Corrélation (et ses limites)

Acte 2 · SIEM Avancé MITRE ATT&CK · S2AN · Navigator · Corrélation

Auteur : Thibaut Fontaine Institution : Université de la Réunion Date : 2026



📡 Poste SOC · La Réunion — Acte 2, Détecter : vous armez Alfred Faure (Crozet), ~2 900 km. Liaison SATCOM nominale.

Vous savez écrire des règles (TP1). Vous savez les transformer en alertes (TP2). Maintenant on passe de « j’ai des règles » à « je couvre une surface » — et on apprend où votre stack s’arrête.

Une détection isolée ne raconte rien. Le jour J fut une chaîne : phishing (T1078) → escalade AD (T1068) → accès coffre (T1213) → exfil (T1041). Ici vous mesurez votre couverture ATT&CK (où sont vos angles morts ?) et vous corrélez plusieurs sources sur une même étape — pour voir la kill chain, pas des alertes éparses. C’est le dernier TP du module SIEM core : il clôt l’Acte 2.

  • Comprendre la détection comme discipline de couverture (pas de règles isolées).
  • Générer un layer ATT&CK Navigator à partir d’un repo de règles Sigma (S2AN).
  • Visualiser et lire la couverture (techniques couvertes / non couvertes / partielles).
  • Construire une corrélation 2 étages en LogQL (détecte → re-détecte sur le stream de détections).
  • Identifier et documenter les limites de Loki (pourquoi un XDR/Wazuh existe).
graph LR
 subgraph "Source"
 RULES[/Repo taaf-detections
règles Sigma taggées/] end subgraph "Génération couverture" S2AN[S2AN
parser Sigma] LAYER[/Layer ATT&CK
JSON Navigator/] NAV[MITRE Navigator
self-hosted] end subgraph "Corrélation 2 étages" R1[Règles TP1/TP2] STREAM[Stream Loki
'detections'] R2[Règle corrélation
count over time] end RULES --> S2AN S2AN --> LAYER LAYER --> NAV RULES --> R1 R1 -->|via webhook ou Alloy| STREAM STREAM --> R2 R2 -->|alerte 'kill chain'| AL([Alerte Grafana]) classDef src fill:#ffcc99,stroke:#333,stroke-width:2px classDef cov fill:#99ff99,stroke:#333,stroke-width:2px classDef corr fill:#99ccff,stroke:#333,stroke-width:2px class RULES src class S2AN,LAYER,NAV cov class R1,STREAM,R2,AL corr

Fenêtre de terminal
# Vérifier le repo TP1/TP2
cd ~/taaf-detections
ls rules/ # → 3+ règles Sigma
grep -l "tags:" rules/**/*.yml | wc -l # → 3+ (toutes taggées)
# Activer le venv Sigma
source ~/sigma-venv/bin/activate

Si une règle n’a pas de tag attack.txxxx, vous devez la corriger maintenant (ouvrez le YAML, ajoutez les tags) — sans tag, S2AN ignore la règle silencieusement.

S2AN (« Sigma to ATT&CK Navigator ») est un binaire Go qui parse un repo de règles Sigma et génère un layer JSON :

Fenêtre de terminal
# Sur la VM soc
curl -sL https://github.com/threatcode/s2an/releases/latest/download/s2an_linux_amd64 \
-o ~/sigma-venv/bin/s2an
chmod +x ~/sigma-venv/bin/s2an
s2an --version # → s2an 0.x
Fenêtre de terminal
docker run -d --name attack-navigator \
-p 4200:4200 \
--restart unless-stopped \
mitre/attack-navigator:latest

Accès : http://IP_SOC:4200.


Fenêtre de terminal
cd ~/taaf-detections
grep -A 5 "^tags:" rules/**/*.yml

Sortie attendue : pour chaque règle, ≥ 1 ligne - attack.txxxx.

TypeExempleNotes
Tactiqueattack.initial_accessUne seule tactique principale par règle
Techniqueattack.t1078Toujours minuscules, sans point
Sous-techniqueattack.t1078.002Domain Accounts (sous T1078)

Reprenez la règle TP1 vpn-auth-external-ip.yml. Le tag attack.t1078 (Valid Accounts) est trop générique. Précisez :

tags:
- attack.initial_access
- attack.t1078
- attack.t1078.002 # Domain Accounts (l'AD est compromis)
- attack.t1133 # External Remote Services (VPN)

Faites de même pour les 2 autres règles :

RègleTags ATT&CK recommandés
falco-classified-vault-read.ymlattack.collection · attack.t1213 · attack.t1213.002 (data from cloud storage)
postgres-genetic-samples-no-approval.ymlattack.collection · attack.t1213.003 · attack.exfiltration · attack.t1041
Fenêtre de terminal
git add rules/
git commit -m "feat(detections): TP3 — sous-techniques ATT&CK affinées"

4. Étape 2 — Générer le layer Navigator (S2AN)

Section intitulée « 4. Étape 2 — Générer le layer Navigator (S2AN) »
Fenêtre de terminal
cd ~/taaf-detections
s2an \
-r rules/ \
-o build/navigator/taaf-coverage-layer.json \
-n "TAAF SOC — couverture détections" \
--score-applied 100 \
--score-partial 50

Options :

  • -r : repo à parser (récursif)
  • -o : fichier de sortie JSON
  • -n : nom du layer (visible dans Navigator)
  • --score-applied : score affiché pour une technique entièrement couverte
  • --score-partial : score pour une technique partiellement couverte

Sortie attendue (extrait JSON) :

{
"name": "TAAF SOC — couverture détections",
"domain": "enterprise-attack",
"techniques": [
{
"techniqueID": "T1078.002",
"score": 100,
"comment": "vpn-auth-external-ip.yml",
"color": ""
},
{
"techniqueID": "T1213.002",
"score": 100,
"comment": "falco-classified-vault-read.yml"
},
{
"techniqueID": "T1041",
"score": 100,
"comment": "postgres-genetic-samples-no-approval.yml"
}
],
"gradient": {
"colors": ["#ff6666", "#ffe766", "#8ec843"],
"minValue": 0,
"maxValue": 100
}
}

Le layer ne contient que les techniques couvertes. Vous savez ce que vous manquez par soustraction.

Pour comparer à un référentiel APT :

Fenêtre de terminal
# Télécharger le layer d'un groupe APT connu (par ex. Volt Typhoon)
curl -sL https://attack.mitre.org/docs/enterprise-attack-v15.1/enterprise-attack-v15.1-layers/G1017-enterprise-layer.json \
-o build/navigator/volt-typhoon-layer.json

Dans Navigator, vous chargerez les deux layers et utiliserez layer expression (a - b) pour voir ce que Volt Typhoon fait que vous ne détectez pas.


5. Étape 3 — Visualiser dans Navigator self-hosted

Section intitulée « 5. Étape 3 — Visualiser dans Navigator self-hosted »
  1. Ouvrez http://IP_SOC:4200 dans votre navigateur.
  2. Open Existing LayerUpload from local → sélectionnez taaf-coverage-layer.json.

📸 Capture obligatoire #1 : matrice ATT&CK Enterprise avec vos techniques en vert (couvertes). Annotez 3 trous critiques (ex : T1068 Privilege Escalation — vous ne détectez PAS l’escalade svc_backup → Domain Admins).

  1. + (en haut) → Create New LayerCreate Layer from other layers.
  2. Domain : Enterprise.
  3. Score expression : a - b (avec a = layer TAAF, b = layer APT).
  4. Vous obtenez un layer négatif = ce que l’APT fait que vous ne détectez pas.

📸 Capture obligatoire #2 : layer a - b montrant les angles morts.

5.3 — Lecture : couverture vs surface d’attaque

Section intitulée « 5.3 — Lecture : couverture vs surface d’attaque »
LectureConclusion
Beaucoup de techniques vertes mais sur 1 tactique seulementVous êtes spécialiste d’une phase, fragile sur le reste
Couverture diluée (1 règle par technique sur 10 tactiques)Bonne diversité mais peu de profondeur
Trous sur Privilege Escalation / Defense EvasionVous voyez entrer, vous ne voyez pas la prise de contrôle

La détection est une discipline de couverture, pas une collection de règles isolées. Cette lecture doit apparaître dans votre rapport.


Loki ne fait pas la corrélation native multi-événements ordonnée. Le pattern qu’on utilise : détecte → logge la détection → recherche la combinaison de détections.

6.1 — Étage 1 : Émettre un événement structuré sur chaque détection

Section intitulée « 6.1 — Étage 1 : Émettre un événement structuré sur chaque détection »

Configurez Grafana Alerting pour, à chaque firing, écrire un événement JSON sur un stream Loki dédié.

Solution propre : utiliser un contact point webhook vers une URL qui pousse vers Loki. Sur la VM soc, montez un mini-relai Python (ou utilisez vector / fluent-bit) :

# vector.yaml — sur la VM soc, port 5000
sources:
grafana_alerts:
type: http
address: 0.0.0.0:5000
decoding:
codec: json
transforms:
to_loki:
type: remap
inputs: [grafana_alerts]
source: |
.stream = "soc_detections"
.severity = .commonLabels.severity
.rule = .commonLabels.alertname
.attack_id = .commonLabels.attack_id
.src_ip = .alerts[0].labels.src_ip
.user = .alerts[0].labels.user
.timestamp = now()
sinks:
loki:
type: loki
inputs: [to_loki]
endpoint: http://IP_VM2:3100
labels:
stream: "soc_detections"
severity: "{{ severity }}"
encoding:
codec: json
Fenêtre de terminal
docker run -d --name vector-relay \
-v $(pwd)/vector.yaml:/etc/vector/vector.yaml:ro \
-p 5000:5000 \
timberio/vector:latest -c /etc/vector/vector.yaml

Ajoutez dans Grafana un nouveau contact point webhook-soc-detections → URL http://IP_SOC:5000. Routez en parallèle de Discord (severity =~ ".*").

6.2 — Étage 2 : Règle de corrélation sur le stream soc_detections

Section intitulée « 6.2 — Étage 2 : Règle de corrélation sur le stream soc_detections »

Créez la règle Sigma rules/correlation/killchain-phishing-to-exfil.yml :

title: Kill Chain — Phishing then Exfil (jour J pattern)
id: 1a2b3c4d-5e6f-7890-abcd-1234567890ab
status: experimental
description: |
Détecte la cooccurrence sur 30 minutes d'une alerte de phishing/auth
externe (T1078) et d'une alerte d'exfil (T1041) pour le même utilisateur.
Approxime la corrélation temporelle ordonnée (non supportée nativement
par le backend Loki).
references:
- https://attack.mitre.org/techniques/T1078/
- https://attack.mitre.org/techniques/T1041/
author: TAAF SOC
date: 2026/06/16
logsource:
product: grafana
service: soc_detections
detection:
phishing:
stream: 'soc_detections'
attack_id: 'T1078'
exfil:
stream: 'soc_detections'
attack_id: 'T1041'
timeframe: 30m
condition: phishing and exfil
fields:
- user
- src_ip
- attack_id
level: critical
tags:
- attack.tactic.collection
- attack.tactic.exfiltration

Compilation manuelle en LogQL (le backend n’a pas de mode natif timeframe croisé, on l’écrit à la main) :

sum by (user) (
count_over_time({stream="soc_detections", attack_id="T1078"}[30m])
)
and
sum by (user) (
count_over_time({stream="soc_detections", attack_id="T1041"}[30m])
)

Provisionnez cette requête comme une 3ème alerte dans Grafana, sévérité critical, route vers discord-soc-critical.

Rejouez l’attaque (logger pour T1078, accès NextCloud pour T1213, requête PG pour T1041).

Résultat attendu : 3 alertes individuelles dans Discord (TP2), puis une 4ème alerte « Kill Chain » qui tombe après les deux premières dans une fenêtre de 30 min.

📸 Capture obligatoire #3 : message Discord « 🔥 Kill Chain detected ».


7. Étape 5 — La limite : pourquoi Loki ne fait pas tout

Section intitulée « 7. Étape 5 — La limite : pourquoi Loki ne fait pas tout »
QuestionLoki natifWazuh / XDR
Détecter une chaîne ordonnée (A puis B puis C) ?⚠️ approx✅ natif
Compter sur une fenêtre glissante par entité ?
Corréler agent + réseau + endpoint en une vue ?⚠️ via streams✅ natif
Inventaire CVE ↔ activité runtime ?
FIM (intégrité fichiers) cross-référencé ?

C’est précisément pourquoi les SIEM commerciaux et XDR existent. Le TP bonus Wazuh (en option) vous fera déployer un SIEM clé-en-main et comparer : ce que vous gagnez (corrélation native, FIM, vuln scanning, ~5000 règles out-of-box), ce que vous perdez (8 Go RAM JVM OpenSearch, 2ᵉ langage de requête, 2ᵉ vitre).

Pour la prod TAAF (golden-box 4 Go) : le SOC Grafana-natif que vous venez de construire est le bon choix. Pour une infra plus large (multi-sites avec endpoints Windows), Wazuh ou un XDR commercial est justifié.

Rédigez une note de 1 page (markdown) :

  1. Ce que mon SIEM Grafana-natif détecte bien (cite les 3 règles, leur LogQL, leur ATT&CK).
  2. Mes angles morts (cite 2-3 techniques visibles dans Navigator que vous ne couvrez pas — proposez la règle qui les couvrirait).
  3. Mes limites architecturales (corrélation temporelle ordonnée, pas de FIM, pas de scan vuln). Décision : justifié pour le contexte TAAF (golden-box, équipes réduites).
  4. Plan de migration vers un SIEM plus capable si la surface s’étend (Wazuh, Sentinel, Splunk).

  1. Repo taaf-detections finalisé :
    • rules/ avec tous les tags ATT&CK affinés (sous-techniques quand pertinent)
    • rules/correlation/killchain-phishing-to-exfil.yml
    • build/navigator/taaf-coverage-layer.json
    • scripts/build-layer.sh qui automatise S2AN
    • docs/limites-loki.md (la note 1 page de la § 7.3)
  2. Captures Navigator :
    • Layer TAAF seul (techniques en vert)
    • Layer a - b vs APT de référence (les angles morts)
  3. Capture Discord : alerte « Kill Chain » qui tombe après les 3 alertes individuelles.
  4. Compose Vector (vector.yaml + commande de lancement) versionné dans le repo monitoring.
CritèrePondération
Tags ATT&CK affinés (sous-techniques présentes quand pertinent)15 %
Layer Navigator généré et chargeable dans MITRE Navigator15 %
Comparaison a - b vs un layer APT de référence10 %
Corrélation 2 étages fonctionne (alerte Kill Chain tombe après les détections élémentaires)25 %
Note technique 1 page (limites Loki + plan de migration)20 %
Repo Git propre, scripts reproductibles15 %

Format de rendu : PDF nom-prenom-promo.pdf sur Moodle.


scripts/build-layer.sh :

#!/usr/bin/env bash
set -euo pipefail
OUT="build/navigator"
mkdir -p "$OUT"
s2an \
-r rules/ \
-o "$OUT/taaf-coverage-layer.json" \
-n "TAAF SOC — couverture détections (auto)" \
--score-applied 100 --score-partial 50
echo "[✓] Layer généré : $OUT/taaf-coverage-layer.json"

Corrigé — couverture attendue (référence prof)

Section intitulée « Corrigé — couverture attendue (référence prof) »

Pour la promo 2026-A, après les 3 règles TP1 + la règle correlation :

Technique ATT&CKCouverte ?
T1078.002 Domain Accounts
T1133 External Remote Services
T1213.002 Data from Cloud Storage
T1213.003 Data from Code Repositories
T1041 Exfiltration Over C2
T1068 Privilege Escalation❌ (gap classique — escalade svc_backup)
T1059.001 PowerShell❌ (traité Acte 3 — tp-module1-lotl-windows)
T1071.001 Web Protocols (C2)❌ (pourrait être ajouté avec une règle Zeek)

L’étudiant doit identifier au moins T1068 et T1059.001 comme angles morts dans sa note.

  • Tags sans le préfixe attack. (juste t1078) → S2AN ignore. -10 %.
  • Layer généré mais pas chargeable (JSON cassé, mauvais domain) → -10 %.
  • Corrélation faite avec or au lieu de and → l’alerte tombe sur chaque alerte individuelle, défait la corrélation. -15 %.
  • Note technique manquante ou sans plan de migration → -15 %.

À la fin du TP3, l’étudiant a le SOC Grafana-natif complet. Les bonus :

  • tp-wazuh-bonus : comparer avec un SIEM clé-en-main (gain de corrélation native vs coût RAM).
  • tp-integration-windows : étendre la collecte côté Windows (Sysmon → Falco/Wazuh).
  • tp-soar-capstone : orchestrer la réponse (Shuffle + MISP + Caldera).

L’Acte 3 (Audit & Purple Team) valide ce que vous avez construit ici :

  • tp-module1-lotl-windows (Acte 3) → comble le trou T1059.001 que vous avez identifié.
  • tp-audit-ad-pingcastle (Acte 3) → traite la cause racine de T1068.
  • tp-purple-team (Acte 3) → rejoue la kill chain et mesure combien d’étapes vos alertes attrapent réellement.