Mode opératoire — Détection d’intrusion : Wazuh (serveur et agents) et Suricata (sonde réseau sur pfSense)

Document autonome. Partie théorique, puis mise en œuvre telle qu’elle a été réalisée et vérifiée les 02 et 03/11/2026 sur srv-wazuh (10.0.30.16, Ubuntu Server 24.04, VM 113) et sur le pare-feu fw-01 (pfSense 2.9.0, 2 Gio) — phase 16 du suivi, tâches 16.2 à 16.10. La méthode vaut pour toute infrastructure qui veut être prévenue d’une attaque, et pas seulement d’une panne. Prérequis : MO-18-Ajouter-une-machine.md (intégrer la nouvelle VM avant d’y installer son rôle ; §4.3 et §5.5 : l’agent Wazuh sur une machine), MO-4-Cles-SSH.md. Contexte et preuves : Documentation-pfSense.md (étapes 59 et 60), dossier de choix.

Valeurs masquées. Aucun mot de passe ici : le mot de passe admin de Wazuh, le mot de passe d’inscription des agents et les mots de passe internes sont dans le gestionnaire de mots de passe (entrées « Wazuh »).

Dernière mise à jour : 04/11/2026 (§11.2 : filtrer le bruit des Windows) État au 12/11/2026 : 5 agents + le serveur : srv-ha, ad-core-01, poste-win11, srv-web-01, srv-web-02 (les nouveaux postes Windows reçoivent l’agent par la GPO de la phase 21). Semaine de mesure terminée (bilan du 11/11 : mémoire 2,5 à 2,7 Gio sur 5,8, swap peu actif, disque stable) → extension à toutes les machines décidée (16.7, à faire). Le schéma du §3 montre la cible, pas l’état actuel.


Sommaire

§Contenu
1Le besoin, et pourquoi Wazuh + Suricata
2Théorie : agents, manager, indexeur, niveaux, enrôlement
3L’architecture retenue
4La machine virtuelle, et son intégration avant tout
5Installer le serveur tout-en-un
6Exiger un mot de passe d’inscription
7Le pare-feu : un flux par zone
8Les agents, par script
9Suricata sur pfSense
9 bisLes alertes de Suricata dans Wazuh
10Tester la détection
11Exploiter : lire les alertes, mesurer, suivre
11 bisPrévenir par mail
12Pièges et checklist

1 · Le besoin, et pourquoi Wazuh + Suricata

La supervision du lab (Prometheus, Grafana, journaux dans Galera) répond à « est-ce que ça marche ? ». Elle voit une panne, un disque plein, une rafale de mots de passe faux. Elle ne voit pas une attaque qui ne casse rien : un fichier système modifié, un compte créé en douce, un balayage de ports, un exploit qui passe sur le réseau.

OutilOù il regardeVerdict
Les alertes Grafana existantesles mesures et les journaux déjà collectésutiles, mais aveugles à l’intérieur des machines et au trafic
CrowdSecles journaux ; partage d’adresses malveillantes avec une communautéécarté : doublon de Wazuh sur les journaux, ne voit ni les fichiers ni les comptes, et des adresses sortent du lab
Snort (paquet pfSense)le réseauécarté : même rôle que Suricata, qui est multi-cœurs et exporte en JSON
Wazuh dans les machines : intégrité des fichiers, comptes, journaux de sécurité, configuration, vulnérabilités ; Linux et Windowsretenu ; libre ; un écran dédié ; lit les alertes de Suricata
Suricata le réseau, sur le pare-feu que tout trafic inter-zones traverseretenu en complément : ce que Wazuh ne voit pas (les appareils sans agent, les balayages)

Les quatre conditions de la décision (02/11) sont dans le dossier de choix §4.

2 · Théorie : agents, manager, indexeur, niveaux, enrôlement

NotionCe que c’est
Agentun petit service installé sur chaque machine surveillée (Linux, Windows, macOS). Il lit les journaux, calcule les empreintes des fichiers système, inventorie comptes et logiciels, et envoie tout au serveur
Managerle serveur qui reçoit les événements des agents et les passe dans ses règles : c’est lui qui décide « ceci est une alerte de niveau 10 »
Indexeurune base OpenSearch qui stocke et indexe les alertes pour l’écran ; c’est lui qui pèse en mémoire (Java), pas le nombre d’agents
Tableau de bordl’écran web (port 443) : agents, alertes, audit de configuration, vulnérabilités
Niveaula gravité d’une alerte, de 0 à 15. Repères du lab : fichier modifié = 7, compte créé = 8, force brute = 10. Les mails partent à partir de 10 (§11 bis, en service depuis le 03/11)
Enrôlementl’inscription d’un agent : il se présente sur le port 1515, reçoit une clé, puis envoie ses événements sur le port 1514 (chiffré). Sans mot de passe d’inscription, n’importe quelle machine qui atteint 1515 peut s’inscrire
FIM (File Integrity Monitoring)la surveillance d’intégrité des fichiers : l’agent compare les empreintes à intervalle régulier (règle 550 « Integrity checksum changed »)
EVE JSONle format d’export de Suricata, un événement par ligne : Wazuh sait le lire tel quel

Principe à retenir : Wazuh regarde dans les machines, Suricata regarde entre les zones. Les deux ensemble couvrent aussi les appareils qui n’auront jamais d’agent (zone VISITEURS).

Ports du serveur (documentation officielle, vérifiés à l’usage pour 1514, 1515 et 443) :

PortUsageQui s’y connecte
1514/tcpévénements des agentschaque machine équipée
1515/tcpenrôlementchaque machine, une fois
443/tcptableau de bordadministrateur (Tailscale, Pangolin)
55000/tcpAPI du managerle tableau de bord (local) ; prévu dans le plan d’adressage, pas ouvert dans pfSense
9200/tcpindexeurle manager et le tableau de bord (local)

3 · L’architecture retenue

   WEB (10)            BDD (20)             USERS (40)            VISITEURS (50)
   srv-ha ─ agent      srv-mysql-0x ─ agent  poste-win11 ─ agent   poste-visiteur ─ agent
      │                    │                    │                     │  (10.0.50.200 seul)
      └────────────────────┴──── 1514 / 1515 ───┴─────────────────────┘
                                   │  une règle par zone, vers SRV_WAZUH seul, avant les rejets
                                   ▼
   ┌───────────────── ADM (30) · srv-wazuh 10.0.30.16 · 6 Gio fixes ─────────────────┐
   │  wazuh-manager (règles, agents)  ──►  wazuh-indexer (OpenSearch, tas Java 1 Gio) │
   │  wazuh-dashboard : https://10.0.30.16  (Tailscale) · wazuh.pangolin.<domaine>     │
   └──────────────────────────────────────────────────────────────────────────────────┘
            ▲ syslog 514/udp via srv-supervision (lignes « suricata » seulement, §9 bis)
   pfSense fw-01 : Suricata, mode détection, interfaces VISITEURS (vtnet1.50) et USERS (vtnet1.40)
ChoixPourquoi
Serveur tout-en-un sur une VM dédiéeune seule machine à sauvegarder et à mesurer ; l’installeur officiel fait tout
6 Gio fixes (minimum officiel : 8)l’hyperviseur partagé est à 81 % ; essai assumé, mesuré une semaine (dette T-17) ; ballon désactivé : un serveur Java dont on reprend la mémoire plante (H-67)
Ubuntu Server 24.04dans la liste des systèmes supportés par Wazuh ; Debian n’y est pas
Zone ADMserveur d’infrastructure, même VLAN que la supervision : aucune règle pour les agents de l’ADM
Mot de passe d’inscription exigésans lui, un invité qui atteint 1515 inscrit un faux agent
Suricata en détection seule, 2 zonespfSense n’a que 2 Gio ; le blocage sur cartes virtuelles n’est pas vérifié et un faux positif couperait un service (dette T-18)

4 · La machine virtuelle, et son intégration avant tout

Contexte : Proxmox, pool du lab. Objectif : une VM intégrée à l’environnement (Termix, supervision, alertes, sauvegarde, adressage) avant d’y installer Wazuh. Si elle casse pendant l’installation, on la voit et on la restaure.

ÉlémentValeur retenue
VM4 vCPU (2 au minimum), 6144 / 6144 Mio (Hardware → Memory : minimum = maximum, ballon décoché), disque 64 Go
SystèmeUbuntu Server 24.04, sans interface graphique, OpenSSH coché à l’installation
Réseauvmbr1, étiquette 30, IP fixe 10.0.30.16/24, passerelle et DNS 10.0.30.1
Compteipfixe (sudo), mot de passe dans Bitwarden avant tout
Agent QEMUpaquet qemu-guest-agent et option cochée dans Proxmox, puis arrêt/démarrage (un reboot ne suffit pas, H-69)

Deux pièges de l’installeur Ubuntu (H-68) : le champ « Masque de sous-réseau » attend le réseau (10.0.30.0/24) ; le partitionnement LVM ne donne que la moitié du disque à la racine. Agrandir :

sudo lvextend -l +100%FREE /dev/ubuntu-vg/ubuntu-lv && sudo resize2fs /dev/mapper/ubuntu--vg-ubuntu--lv && df -h /

/ à la taille du disque (03/11 : 31 → 61 Go).

Puis les six points du MO-18 : (a) Termix par clé, mot de passe SSH interdit ; (b) ajouter-machine.sh 10.0.30.16 depuis le bastion ; (c) up{host="srv-wazuh"} = 1 ; (d) « Machine injoignable » compte une instance de plus ; (e) sauvegarde de la nuit suivante ; (f) adressage, registre, documentation, schéma.

Validation — sudo sshd -T | grep -i passwordauth → passwordauthentication no ; depuis une autre machine, ssh -o PubkeyAuthentication=no [email protected] → Permission denied (publickey) ; up = 1 dans Prometheus ; journaux dans la base dans l’heure (03/11 : 39 lignes) ; « Machine injoignable » à 15 instances (capture 146).

5 · Installer le serveur tout-en-un

Contexte : session Termix sur srv-wazuh, compte ipfixe, accès Internet de la zone ADM. Objectif : manager, indexeur et tableau de bord actifs sur la même machine, mot de passe admin rangé.

5.1 Télécharger l’installeur et le lire avant de le lancer. C’est un script qui tourne en root : on regarde au moins son en-tête (version, ce qu’il fait) et sa taille.

curl -sO https://packages.wazuh.com/4.14/wazuh-install.sh && ls -l wazuh-install.sh && head -30 wazuh-install.sh

un fichier d’environ 215 Ko, en-tête « Wazuh installer » version 4.14 (03/11).

5.2 Lancer l’installation tout-en-un (-a = all-in-one). Elle prend plusieurs minutes.

sudo bash wazuh-install.sh -a

La documentation prévoit une option pour ignorer le contrôle matériel si l’installeur refuse de tourner sous 8 Gio. Le 03/11, à 6 Gio, aucun blocage : l’option n’a pas servi (bash wazuh-install.sh --help la liste si besoin).

en fin d’installation, l’installeur affiche le compte admin et son mot de passe, et laisse une archive wazuh-install-files.tar (tous les mots de passe internes).

5.3 Ranger les secrets, tout de suite.

  • mot de passe admin → Bitwarden (Wazuh - admin), jamais dans un fichier ni dans le chat ;
  • l’archive hors du dossier de travail, lisible par root seul :
sudo mv wazuh-install-files.tar /root/ && sudo chmod 600 /root/wazuh-install-files.tar && sudo ls -l /root/wazuh-install-files.tar

5.4 Désactiver le dépôt apt (recommandation officielle : une mise à jour non préparée casserait l’accord de version entre le serveur et ses agents ; on met à jour volontairement, serveur d’abord, agents ensuite) :

sudo sed -i 's/^deb /#deb /' /etc/apt/sources.list.d/wazuh.list && sudo apt-get update -qq && grep ^#deb /etc/apt/sources.list.d/wazuh.list

5.5 Le tas Java de l’indexeur. C’est ce qui pèse. L’installeur l’avait déjà réglé à 1 Gio le 03/11 (moins que les 1,5 Gio prévus au cadrage) : gardé tel quel. Vérifier :

grep -E '^-Xm[sx]' /etc/wazuh-indexer/jvm.options

-Xms1024m et -Xmx1024m (valeurs égales : le tas ne grandit pas en cours de route). bootstrap.memory_lock (mémoire verrouillée, hors swap) : prévu au cadrage, À VÉRIFIER dans /etc/wazuh-indexer/opensearch.yml.

5.6 Vérifier les trois services et la mémoire.

systemctl is-active wazuh-manager wazuh-indexer wazuh-dashboard && free -h

Validation — trois fois active ; le 03/11 juste après l’installation : 2,2 Gio utilisés sur 5,8, java 1,24 Go, swap 265 Mio (à suivre, §11.3). Tableau de bord : https://10.0.30.16, certificat autosigné accepté, connexion avec admin. Accès externe : ressource Pangolin wazuh.pangolin.<domaine> (cible https 10.0.30.16:443, contrôle de santé TCP, protégée), même modèle que Grafana (MO-10).

6 · Exiger un mot de passe d’inscription

Contexte : sur srv-wazuh, avant le premier agent. Objectif : le serveur refuse tout agent qui ne présente pas le mot de passe.

6.1 Le mot de passe : généré, rangé dans Bitwarden (entrée « Wazuh - inscription des agents »), puis écrit dans le fichier attendu par le service d’enrôlement, sans jamais s’afficher :

read -rsp 'Mot de passe d inscription (Bitwarden) : ' MDP; echo; printf '%s\n' "$MDP" | sudo tee /var/ossec/etc/authd.pass >/dev/null; unset MDP; sudo chmod 640 /var/ossec/etc/authd.pass && sudo chown root:wazuh /var/ossec/etc/authd.pass && sudo ls -l /var/ossec/etc/authd.pass

-rw-r----- 1 root wazuh … authd.pass.

6.2 L’option dans ossec.conf (copie de sécurité d’abord) : dans le bloc <auth>, passer <use_password> à yes.

sudo cp /var/ossec/etc/ossec.conf /var/ossec/etc/ossec.conf.avant-authd && sudo sed -i 's#<use_password>no</use_password>#<use_password>yes</use_password>#' /var/ossec/etc/ossec.conf && sudo systemctl restart wazuh-manager

6.3 Vérifier : lire tout le bloc, pas trois lignes. Le 03/11, un grep -A3 '<auth>' s’arrêtait avant la ligne use_password et laissait croire que l’option manquait (H-71). Lire le bloc entier :

sudo sed -n '/<auth>/,/<\/auth>/p' /var/ossec/etc/ossec.conf | grep -E 'use_password|port' ; sudo grep -i 'password' /var/ossec/logs/ossec.log | tail -2

Validation — <use_password>yes</use_password> ; journal du manager : « Using password specified on file ». Un agent lancé sans le bon mot de passe est refusé à l’enrôlement.

7 · Le pare-feu : un flux par zone

Contexte : pfSense, Firewall → Aliases puis Rules. Objectif : chaque zone atteint le seul serveur Wazuh, sur les deux ports, rien d’autre. Même modèle que les journaux (514).

ObjetValeur
Alias SRV_WAZUH (Host)10.0.30.16
Alias PORTS_WAZUH (Port)1514, 1515
Onglet WEBWEB subnets → SRV_WAZUH : PORTS_WAZUH, TCP, placée avant le rejet
Onglet BDDBDD subnets → SRV_WAZUH : PORTS_WAZUH : seconde exception assumée à « la base n’initie rien »
Onglet USERSUSERS subnets → SRV_WAZUH : PORTS_WAZUH
Onglet VISITEURS10.0.50.200 seul (le poste de test géré) ; jamais VISITEURS subnets
Onglet ADMrien : même VLAN, le trafic ne traverse pas le pare-feu

La source doit appartenir au VLAN de l’onglet. Une règle VISITEURS avec USERS subnets en source (copiée de l’onglet voisin) ne correspond à rien : le paquet tombe sur le rejet, refus immédiat (H-70, même leçon que B-05). Le refus est immédiat et journalisé : c’est le signe qu’une règle au-dessus n’a pas correspondu.

Validation — depuis une machine de chaque zone (Linux : nc -zv 10.0.30.16 1514 puis 1515 ; Windows : Test-NetConnection 10.0.30.16 -Port 1514) : open / TcpTestSucceeded : True (03/11 : srv-web-01, srv-mysql-01, poste-visiteur, poste-win11). Captures 147 à 152.

8 · Les agents, par script

Contexte : le pas à pas par machine est le point (b bis) du MO-18 (§4.3 Linux, §5.5 Windows). Ici : ce que font les scripts, et comment vérifier côté serveur.

Script (scripts/securite/)OùCe qu’il fait
ajouter-agent-wazuh.sh <IP> [<IP>…]bastion srv-docker, compte ipfixevérifie la zone de l’adresse (en BDD : rappelle la règle Internet temporaire), lit le nom de la machine, demande le mot de passe d’inscription une fois pour toutes les machines, le transmet par SSH dans un fichier temporaire 600 effacé aussitôt lu, lance l’installeur ; ssh -t pour le sudo de la cible
installer-wazuh-agent.sh <serveur> <nom>la machine Linux, rootdépôt officiel signé, agent dans la version du serveur (4.14.9-1), inscription par WAZUH_MANAGER / WAZUH_AGENT_NAME / WAZUH_REGISTRATION_PASSWORD, dépôt désactivé ensuite, attente de status='connected' dans /var/ossec/var/run/wazuh-agentd.state (jusqu’à 60 s)
installer-wazuh-agent.ps1la machine Windows, PowerShell administrateurMSI 4.14.9-1 téléchargé, empreinte SHA-512 officielle vérifiée (sinon annulé), mot de passe d’inscription saisi en secret, msiexec /q, attente de status='connected'

Même version que le serveur. Un agent plus récent que le manager est refusé : la version est figée dans les scripts (wazuh-control info sur le serveur donne la sienne). Mettre à jour le serveur d’abord, puis changer la version dans les scripts.

Le serveur voit-il l’agent ? Sur srv-wazuh :

sudo /var/ossec/bin/agent_control -l

Validation — une ligne ID: 00x, Name: <machine>, IP: any, Active par machine. Le 03/11 : srv-ha (001), ad-core-01 (002), poste-win11 (003), une machine de chaque type avant d’étendre. Dans le tableau de bord, Agents : état Active, premiers résultats d’audit de configuration en quelques minutes.

Deux corrections au premier essai : le script Linux n’attendait que 10 s et annonçait un échec alors que l’agent était inscrit (H-72) ; sous Windows, le fichier .sha512 était reçu comme un binaire, Trim impossible (H-73).

9 · Suricata sur pfSense

Contexte : pfSense 2.9.0, 2 Gio de RAM. Objectif : une sonde réseau en détection seule sur les zones VISITEURS et USERS, règles ET Open à jour, export EVE JSON pour Wazuh.

9.1 Avant tout : sauvegarde de la configuration (Diagnostics → Backup & Restore), et relevé de la mémoire libre du pare-feu dans Prometheus (node_memory_MemFree_bytes de fw-01) : 03/11, 1 477 Mo avant Suricata.

9.2 Installer : System → Package Manager → Available Packages, suricata, Install.

9.3 Les réglages communs (Services → Suricata → Global Settings) :

RéglageValeurCapture
Jeux de règlesETOpen coché seul (ETPro, Snort, Feodo, ABUSE.ch non)154
Update Interval12 HOURS, heure de départ laissée avec ses minutes aléatoires ; Live Rule Swap décoché155
Keep Suricata Settings After Deinstallcoché155

Puis Updates → Update : Result: success, jeu ET Open daté (capture 159).

9.4 Une interface (Interfaces → Add) :

RéglageValeurCapture
Enable, Interfacecoché, VISITEURS (vtnet1.50), description parlante156
Loggingjournal HTTP (défaut) ; TLS, file-store, packet log, stats, verbose : non156, 157
EVE OutputEVE JSON Log coché, type FILE, EVE Log Alerts coché, charge utile BOTH157
Block Offendersdécoché (détection seule)158
Categories7 catégories ET Open : attack_response, dos, exploit, malware, scan, shellcode, web_server160a-c

Save, puis sur la liste des interfaces : démarrer (icône ▶). état vert, Blocking Mode DISABLED (capture 161).

Le moteur met ≈ 50 s à charger ses 23 000 règles. Un test lancé avant la ligne Engine started. du suricata.log ne donne rien (H-76). Attendre, ou lire le journal : Logs View → suricata.log.

9.5 La seconde interface : icône Duplicate sur VISITEURS, changer l’interface en USERS (vtnet1.40) et la description, Save, démarrer (capture 163).

9.6 Relever la mémoire après chaque interface (même mesure qu’en 9.1, plus ps sur pfSense) :

avantVISITEURSVISITEURS + USERS
mémoire libre1 477 Mo827 Mo674 Mo
processus suricata—396 Mo396 + 368 Mo
swap000

Validation — deux interfaces vertes en DISABLED ; 22996 rules successfully loaded (4 règles ja3 refusées : empreinte TLS non activée, sans effet) ; mémoire libre > 600 Mo, swap 0. Décision d’Axel (03/11) : on s’arrête là (option A) : ≈ 370 à 400 Mo par interface, les 3 autres zones ne tiennent pas. Option B pour plus tard : une seule instance sur le trunk vtnet1 pour les 5 zones. Un peu de RAM en plus sur pfSense est possible ; au-delà de 2 Gio de plus, on passe à B.

9 bis · Les alertes de Suricata dans Wazuh

Contexte : Suricata tourne sur pfSense, qui n’a pas d’agent Wazuh. Objectif : ses alertes dans Wazuh, et les plus graves par mail, sans rien installer sur le pare-feu.

Suricata (pfSense) ── « Send Alerts to System Log », format court, local1
      │  pfSense envoie tout son journal à srv-supervision (UDP 514, déjà en place)
      ▼
srv-supervision ──► base des journaux (programme = suricata, 6 mois)
      │  rsyslog renvoie SEULEMENT les lignes « suricata »
      ▼
srv-wazuh 10.0.30.16:514/udp (réception syslog, depuis 10.0.30.15 seul)
      │  décodeur local « suricata-fast » + règles 100200 (niveau 6) / 100201 (niveau 10)
      ▼
syslog_output niveau ≥ 10 ──► base des journaux ──► règle Grafana « Intrusion détectée (Wazuh) » ──► mail

Pourquoi pas le JSON (EVE) : le journal de pfSense coupe ses messages à 480 octets (c’est écrit sous l’option), une alerte JSON en fait plus de 1 000. On envoie le format court, et on apprend à Wazuh à le lire.

1. Suricata écrit ses alertes dans le journal de pfSense : Services → Suricata → Interfaces → crayon de chaque interface → Logging Settings → Send Alerts to System Log, Facility LOCAL1, Priority NOTICE → Save ; puis ⟳ redémarrer chaque interface et attendre Engine started (≈ 50 s). Sans redémarrage, rien ne change (H-78).

2. srv-supervision renvoie les seules lignes « suricata » à Wazuh : dans /etc/rsyslog.d/31-reception-pfsense.conf (copie d’abord), juste après la ligne if ($fromhost-ip != "10.0.30.1") then stop :

  if ($programname == "suricata") then {
    action(type="omfwd" name="suricata_vers_wazuh" target="10.0.30.16" port="514" protocol="udp")
  }
sudo rsyslogd -N1 && sudo systemctl restart rsyslog

End of config validation run. Bye. Les lignes continuent aussi d’aller dans la base (programme = suricata).

3. Wazuh écoute en syslog, depuis srv-supervision seul : bloc ajouté à ossec.conf (copie d’abord) :

<ossec_config>
  <remote>
    <connection>syslog</connection>
    <port>514</port>
    <protocol>udp</protocol>
    <allowed-ips>10.0.30.15</allowed-ips>
    <local_ip>10.0.30.16</local_ip>
  </remote>
</ossec_config>

local_ip évite le conflit avec le rsyslog local, qui tient 127.0.0.1:514 (§11 bis).

4. Le décodeur et les règles : contenu de scripts/securite/suricata-local_decoder.xml ajouté à /var/ossec/etc/decoders/local_decoder.xml, et de suricata-local_rules.xml à /var/ossec/etc/rules/local_rules.xml (copies d’abord, propriétaire wazuh:wazuh). Tester avant de redémarrer :

echo 'Nov  3 18:49:16 SIO2527-pfSense-axel.sio.internal suricata[18722]: [1:2100498:7] GPL ATTACK_RESPONSE id check returned root [Classification: Potentially Bad Traffic] [Priority: 2] {TCP} 10.0.50.200:37422 -> 3.137.48.32:80' | sudo /var/ossec/bin/wazuh-logtest

Phase 2 : name: 'suricata-fast', priority: '2', srcip: '10.0.50.200' ; Phase 3 : id: '100201', level: '10'. Puis sudo systemctl restart wazuh-manager et sudo ss -ulnp | grep ':514' → 10.0.30.16:514 tenu par wazuh-remoted.

Priorité SuricataRègle WazuhNiveauEffet
3 (basse)1002006tableau Wazuh
1 ou 2 (haute, moyenne)10020110tableau Wazuh et mail (§11 bis)

Validation — depuis poste-visiteur : curl -s http://httpbin.org/anything --data "uid=0(root) gid=0(root)". dans alerts.json, une alerte 100201 niveau 10 en une seconde ; puis un mail [FIRING] Intrusion détectée (Wazuh) avec la machine fw-01 (Suricata) (03/11 : alerte à 18:51:45, mail à 18:54:16 ; capture 171).

10 · Tester la détection

Principe : chaque test est une attaque simulée, réversible, lancée depuis une machine du lab, et prouvée par l’alerte lue à la source. Lancer les actions par l’agent QEMU (qm guest exec) ou en session Termix, après avoir relu l’invite (utilisateur@machine) : un test lancé sur la mauvaise machine ne prouve rien (H-57).

10.1 Wazuh. Sur srv-wazuh, suivre les alertes en direct (fichier JSON, une alerte par ligne) :

sudo tail -f /var/ossec/logs/alerts/alerts.json | grep -oE '"timestamp":"[^"]+"|"name":"[^"]+"|"level":[0-9]+|"description":"[^"]+"'
TestActionAttendu
A · fichier système modifiésur srv-ha : echo "# test detection Wazuh $(date +%F_%T)" | sudo tee -a /etc/hosts.allow ; forcer la vérification : sudo /var/ossec/bin/agent_control -r -u 001 (sur le serveur) ; retirer la ligne ensuiterègle 550 « Integrity checksum changed », niveau 7, fichier /etc/hosts.allow
B · compte créésur poste-win11 (administrateur) : net user testwazuh <mot de passe de test> /add, puis net user testwazuh /delete60109 « User account enabled or created », 60111 « User account disabled or deleted », niveau 8
C · force brute SSHdepuis le bastion : 10 fois ssh -o BatchMode=yes -o ConnectTimeout=3 [email protected] true (aucun mot de passe envoyé)5710 × 10 (niveau 5), puis 5712 « sshd: brute force trying to get access », niveau 10

le 03/11 : 3 attaques, 3 détections en 2 à 3 s (capture 153 ; heures du fichier en UTC = Paris − 1 h).

net user … /add pose une question si le mot de passe dépasse 14 caractères et attend une réponse : un mot de passe de test de 14 caractères au plus, ou l’option /y (H-74). Le compte est supprimé aussitôt : ce test crée deux alertes, et ne laisse rien.

10.2 Suricata. La règle GPL ATTACK_RESPONSE id check returned root (sid 2100498) se déclenche sur tout paquet contenant uid=0(root). Le site de test habituel testmynids.org a expiré (H-75) : on envoie la phrase à un service d’écho, qui la renvoie.

Depuis poste-visiteur :

curl -s http://httpbin.org/anything --data "uid=0(root) gid=0(root) groups=0(root)"

Depuis poste-win11 (PowerShell) :

(Invoke-WebRequest http://httpbin.org/anything -Method Post -Body 'uid=0(root) gid=0(root) groups=0(root)').StatusCode

Lire sur pfSense : Services → Suricata → Alerts, interface choisie ; ou en shell, tail /var/log/suricata/suricata_<interface>*/alerts.log.

Validation — en 2 s : [1:2019284:3] ET ATTACK_RESPONSE Output of id command from HTTP server et [1:2100498:7] GPL ATTACK_RESPONSE id check returned root, avec l’adresse source de la zone testée (captures 162 et 164). Depuis le poste visiteur, une troisième alerte : la commande, notée dans le journal du poste, est partie vers srv-supervision:514 et Suricata l’a reconnue dans ce flux aussi.

11 · Exploiter : lire les alertes, mesurer, suivre

11.1 Où lire.

BesoinOù
état des agentssudo /var/ossec/bin/agent_control -l ; tableau Agents
les alertes brutes/var/ossec/logs/alerts/alerts.json (JSON) et alerts.log (texte) sur srv-wazuh
enquêtertableau de bord : Threat Hunting, filtre par agent et par niveau ; File Integrity Monitoring ; Configuration Assessment
les alertes de SuricatapfSense Services → Suricata → Alerts ; dans Wazuh, règles 100200 et 100201 (§9 bis) ; dans la base des journaux, programme = suricata
les alertes graves, par mail§11 bis : niveau ≥ 10 et créations de comptes
les alertes graves, à l’écrantableau « Lab BTS — Production » : bandeau « Alertes en cours » en haut ; section Journaux et sécurité : « Intrusions Wazuh (24 h) » et « Dernières intrusions détectées par Wazuh »
le journal du manager/var/ossec/logs/ossec.log

11.2 Le bruit, et comment le faire taire. Les Windows produisent en continu des alertes de niveau 3 sans intérêt : comptes machine (NOM$) qui ouvrent et ferment des sessions, comptes virtuels sshd_<numéro> qu’OpenSSH crée à chaque connexion sur le port 22, compte Système au démarrage d’un service. Le 04/11 : 14 067 alertes en une journée, 96 % de niveau 3. On ne supprime rien à la source (le journal Windows reste complet) : on ajoute des règles locales de niveau 0, qui disent à Wazuh « tu as vu, mais ce n’est pas une alerte ».

  1. Compter avant de filtrer (qui fait le bruit ?) : sur srv-wazuh, compter par règle et par compte dans /var/ossec/logs/alerts/alerts.json (champs rule.id, data.win.eventdata.targetUserName, logonType).
  2. Copier le fichier des règles locales :
sudo cp -p /var/ossec/etc/rules/local_rules.xml /var/ossec/etc/rules/local_rules.xml.avant-bruit
  1. Ajouter à la fin le contenu de scripts/securite/bruit-windows-local_rules.xml (règles 100210 à 100213 : chaque règle part d’une règle Windows existante par <if_sid> et n’agit que si le compte correspond).
  2. Valider la configuration avant de redémarrer :
sudo /var/ossec/bin/wazuh-analysisd -t

aucune ligne ERROR ; puis :

sudo systemctl restart wazuh-manager
  1. Mesurer : même comptage sur les 15 minutes d’avant et d’après. Le 04/11 : 173 → 43 alertes ; plus aucune alerte sshd_ ni compte machine ; restent les comptes humains (Administrateur, admin).

Ne jamais filtrer les échecs (60122) ni les comptes humains : c’est précisément ce qu’on veut voir. Un filtre trop large rend Wazuh aveugle sans aucun message d’erreur.

Le compte Système s’écrit Système en français : le « è » fait deux octets dans le journal, une expression Syst.me ne le trouve pas, il faut Syst.{1,2}me (H-80).

11.3 La semaine de mesure (03 → 10/11). À relever chaque jour, ou en fin de semaine dans le tableau de production :

free -h && df -h /var/ossec && systemctl is-active wazuh-indexer
Mesure03/1110/11
mémoire utilisée (sur 5,8 Gio)2,3 GioÀ COMPLÉTER
swap265 Mio après l’installation, 631 Mio en fin de journéeÀ COMPLÉTER
/var/ossecÀ COMPLÉTERÀ COMPLÉTER

Décision du 10/11 : étendre à tout le lab (16.7) si le swap n’explose pas et que l’indexeur reste actif ; sinon repli (CrowdSec + Suricata, ou Wazuh sans indexeur).

11.4 Ce qui reste à faire (tâche 16.7, décidée le 11/11 après la semaine de mesure) : agents sur toutes les autres machines (nœuds Galera avec la règle Internet temporaire). pfSense n’a pas d’agent : ses alertes Suricata arrivent par syslog (§9 bis).

11 bis · Prévenir par mail

Contexte : Wazuh détecte, mais rien ne prévient l’administrateur. Objectif : un mail pour toute alerte de niveau ≥ 10 et pour toute création de compte, par le circuit de mails déjà en place (MO-17 §11).

Le principe : Wazuh envoie ses alertes graves en syslog au rsyslog de sa propre machine ; celui-ci les transmet à srv-supervision avec le reste du journal ; une règle Grafana sur la base des journaux envoie le mail.

wazuh-analysisd ── alerte niveau ≥ 10, ou règle 60109 / 5902 (création de compte)
      │  wazuh-csyslogd (syslog_output)
      ▼
rsyslog de srv-wazuh, 127.0.0.1:514 (UDP, local seulement)
      │  envoi déjà en place de tout le journal (ajouter-machine.sh), TCP 514
      ▼
srv-supervision ──► base des journaux (Galera, conservée 6 mois)
      │
      ▼
règle Grafana « Intrusion détectée (Wazuh) », critique ──► circuit de mails existant

Pourquoi pas Grafana directement sur l’indexeur ? Il n’écoute que sur 127.0.0.1:9200 (installation tout-en-un) ; l’ouvrir demanderait de refaire ses certificats. Le syslog réutilise un chemin qui existe et garde les alertes 6 mois.

1. rsyslog local, sur 127.0.0.1 seulement (session srv-wazuh) :

printf 'module(load="imudp")\ninput(type="imudp" address="127.0.0.1" port="514")\n' | sudo tee /etc/rsyslog.d/10-wazuh-local.conf && sudo rsyslogd -N1 && sudo systemctl restart rsyslog && sudo ss -ulnp | grep ':514'

End of config validation run. Bye., puis 127.0.0.1:514 tenu par rsyslogd.

2. Les alertes de niveau ≥ 10 vers ce rsyslog (copie de la configuration d’abord) :

sudo cp /var/ossec/etc/ossec.conf /var/ossec/etc/ossec.conf.avant-syslog && printf '\n<ossec_config>\n  <syslog_output>\n    <level>10</level>\n    <server>127.0.0.1</server>\n    <port>514</port>\n  </syslog_output>\n</ossec_config>\n' | sudo tee -a /var/ossec/etc/ossec.conf

3. Plus les créations de comptes (60109 Windows, 5902 Linux, niveau 8) : un second bloc, même méthode (copie ossec.conf.avant-comptes), avec <rule_id>60109,5902</rule_id> à la place de <level>. Les deux blocs sont dans scripts/securite/ossec-syslog-output.xml. Puis :

sudo /var/ossec/bin/wazuh-csyslogd -t && sudo systemctl restart wazuh-manager && sleep 15 && sudo /var/ossec/bin/wazuh-control status | grep -E 'csyslogd|analysisd'

wazuh-csyslogd is running... et wazuh-analysisd is running... (le message « This option is deprecated » de wazuh-control enable client-syslog est sans gravité : le module est actif par défaut).

4. La règle Grafana « Intrusion détectée (Wazuh) », source mysql (compte en lecture seule), dossier Lab BTS, groupe critiques, attente 1 min, absence de données = Normal :

SELECT CASE WHEN message LIKE '%Location: (%'
            THEN SUBSTRING_INDEX(SUBSTRING_INDEX(message, 'Location: (', -1), ')', 1) ELSE 'srv-wazuh' END AS agent,
       TRIM(SUBSTRING_INDEX(SUBSTRING_INDEX(message, 'Rule: ', -1), ';', 1)) AS regle, COUNT(*) AS value
FROM journaux WHERE hote = 'srv-wazuh' AND programme = 'ossec'
  AND recu_le > UTC_TIMESTAMP() - INTERVAL 15 MINUTE GROUP BY 1, 2

Condition : value > 0. Résumé : {{ $labels.agent }} : {{ $labels.regle }}.

15 minutes, pas 5 (H-77) : la fenêtre doit être plus longue que l’envoi groupé du chemin critique (5 min), sinon une seconde intrusion « se résout » avant que son mail ne parte.

Validation — une force brute SSH (10 connexions d’un compte inexistant) → mail [FIRING] « Intrusion détectée (Wazuh) … srv-ha 5712 » en moins de 2 minutes (03/11 : 1 min 29 s) ; un compte créé sous Windows et sous Linux → les deux dans un mail [FIRING] (03/11 : [FIRING:3] à 18:33:15). Preuves : captures 167 et 168.

12 · Pièges et checklist

PiègeSymptômeOù c’est documenté
Installeur Ubuntu : « masque » = réseau ; LVM à moitiéhas host bits set ; / à 31 Go sur 64H-68
Option QEMU Guest Agent non cochée dans ProxmoxA dependency job for qemu-guest-agent.service failed, adresse absente dans ProxmoxH-69
Source d’une règle hors du VLAN de l’ongletrefus immédiat sur 1514/1515 depuis la zoneH-70
grep -A3 pour vérifier un bloc XMLon croit l’option absenteH-71
Script qui n’attend pas l’enrôlement« échec » alors que l’agent est inscritH-72
Fichier .sha512 lu comme un binaire sous PowerShell[System.Byte] ne contient pas de méthode nommée « Trim »H-73
net user /add avec un mot de passe longla commande attend une réponse, rien ne se passeH-74
Site de test testmynids.org disparuaucune alerte, page « domaine à vendre »H-75
Test lancé avant Engine started.aucune alerte SuricataH-76
Fenêtre de la règle de mail plus courte que l’envoi groupémail [RESOLVED] sans [FIRING]H-77
Option Suricata modifiée sans redémarrer l’interfacerien dans le journal de pfSenseH-78
Format court de Suricata non reconnu par WazuhNo decoder matched, règle 1002 niveau 2H-79
Filtre de bruit écrit avec un . pour un caractère accentuéles alertes du compte Système continuentH-80
Ballon activé sur la VM WazuhJava plante quand Proxmox reprend la mémoireH-67
Agent plus récent que le serveurenrôlement refusé§8 : version figée
Port 1515 ouvert à toute la zone VISITEURSun invité peut inscrire un faux agent§7 : poste géré seul
 VM 6144/6144 Mio sans ballon, 64 Go, Ubuntu 24.04, racine agrandie, agent QEMU (option + arrêt/démarrage)
 MO-18 fait en entier AVANT Wazuh : Termix par clé, mot de passe SSH interdit, up=1, journaux, alertes, sauvegarde, adressage
 wazuh-install.sh lu (en-tête, taille) avant sudo bash … -a ; 3 services active
 Mot de passe admin dans Bitwarden ; wazuh-install-files.tar dans /root en 600 ; dépôt apt désactivé
 jvm.options : -Xms = -Xmx (1 Gio) ; free -h relevé
 authd.pass 640 root:wazuh ; <use_password>yes</use_password> ; « Using password specified on file »
 Alias SRV_WAZUH et PORTS_WAZUH ; une règle par zone avant les rejets ; VISITEURS = 10.0.50.200 seul ; nc -zv depuis chaque zone
 Scripts dans la version du serveur ; agent_control -l : Active pour chaque machine
 Suricata : config pfSense sauvegardée avant ; ETOpen, 12 h ; EVE JSON FILE ; Block Offenders décoché ; 7 catégories ; mémoire relevée avant/après
 3 tests Wazuh (550, 60109/60111, 5712) et 1 test Suricata par zone (2100498) : alertes lues, captures datées
 Semaine de mesure notée (mémoire, swap, /var/ossec) ; décision du 10/11 écrite dans le suivi
 Alertes Suricata → Wazuh (§9 bis) : redémarrage de Suricata, wazuh-logtest avant redémarrage de Wazuh, test de bout en bout jusqu'au mail
 Reste (16.7, décidée le 11/11) : agents sur toutes les autres machines

La règle à retenir en une phrase : Wazuh regarde dans les machines, Suricata regarde entre les zones ; un mot de passe d’inscription, une règle par zone vers le seul serveur, la même version partout, et chaque détection prouvée par une attaque simulée avant de faire confiance à l’écran.