Objectif : installer le Splunk Universal Forwarder sur la VM cible pour un canal de collecte natif Splunk, puis déployer Fail2ban pour la première détection automatisée d'attaques par force brute.
http://[IP_SOC]:8000security créé dans Splunkmainignoreip en premier/var/log/auth.log — vérifier que le fichier existe avant tout| Horaire | Activité | VM(s) | Durée |
|---|---|---|---|
| 09h00 – 09h30 | Cours — Sécurisation convergence des journaux, TLS Forwarder, RBAC Splunk | — | 30 min |
| 09h30 – 10h00 | Cours — Light vs Heavy Forwarder, architecture de collecte Splunk | — | 30 min |
| 10h00 – 10h15 | Pause | — | 15 min |
| 10h15 – 13h00 | TP 1 — Installation Splunk Universal Forwarder sur la VM cible | SOC + Cible | 2h45 |
| 13h00 – 14h00 | Pause déjeuner | — | 1h |
| 14h00 – 17h30 | TP 2 — Déploiement Fail2ban + centralisation dans Splunk | SOC + Cible | 3h30 |
| 17h30 – 18h00 | Validation + débrief + snapshot | — | 30 min |
Le Splunk Universal Forwarder est l'agent natif de Splunk. Il remplace avantageusement rsyslog pour l'envoi des logs vers Splunk : parseurs natifs, compression, chiffrement TLS, file persistante.
rsyslog envoie du texte brut vers Logstash (pipeline ELK). Le Splunk Forwarder envoie les données dans le protocole natif Splunk vers l'Indexer (port 9997) avec compression, file persistante et futur TLS. Les deux canaux coexistent et se complètent.
Le port 9997/TCP est le port de réception standard du Splunk Indexer. Il doit être ouvert depuis le sous-réseau NAT VMware.
# Autoriser le port 9997 depuis le sous-réseau NAT VMware # Adapter 192.168.91.0/24 à votre sous-réseau réel sudo ufw allow from 192.168.91.0/24 to any port 9997 proto tcp sudo ufw reload sudo ufw status | grep 9997
Par défaut, Splunk n'écoute pas sur le port 9997. Il faut activer la réception dans l'interface web ou en ligne de commande.
Settings → Forwarding and receiving → Configure receiving → New
Listen on this port : 9997
→ Save
Ou via ligne de commande (équivalent) :
sudo /opt/splunk/bin/splunk enable listen 9997 --run-as-root
# Vérifier que Splunk écoute sur 9997
ss -tlnp | grep 9997
La commande ss -tlnp | grep 9997 retourne une ligne avec LISTEN. Splunk est prêt à recevoir des Forwarders.
Le Splunk Universal Forwarder est un package séparé de Splunk Enterprise, beaucoup plus léger (~15 Mo RAM). Le lien de téléchargement est fourni par l'enseignant.
# Télécharger le paquet (URL fournie par l'enseignant) wget -O splunkforwarder.deb "URL_FOURNIE" # Installer sudo dpkg -i splunkforwarder.deb # Démarrer et accepter la licence sudo /opt/splunkforwarder/bin/splunk start --accept-license --answer-yes --no-prompt # Note : le Forwarder crée un compte admin séparé de Splunk Enterprise # Utiliser le même mot de passe que Splunk pour simplifier # Activer le démarrage automatique sudo /opt/splunkforwarder/bin/splunk enable boot-start # Vérifier que le Forwarder tourne sudo /opt/splunkforwarder/bin/splunk status
La commande splunk status retourne "splunkd is running". Le Forwarder est installé mais n'envoie encore nulle part.
On indique au Forwarder l'adresse IP et le port du Splunk Indexer sur la VM SOC. Remplacer 192.168.91.10 par l'IP réelle de votre VM SOC.
# Ajouter le serveur Splunk SOC comme destination sudo /opt/splunkforwarder/bin/splunk add forward-server \ 192.168.91.10:9997 # Vérifier la configuration sudo /opt/splunkforwarder/bin/splunk list forward-server
Cette commande écrit dans /opt/splunkforwarder/etc/system/local/outputs.conf la configuration de destination. C'est le fichier de configuration principal du Forwarder pour l'envoi.
On indique au Forwarder quels fichiers surveiller et envoyer vers Splunk. On commence par les logs système et les logs Apache.
# Créer le répertoire de configuration locale sudo mkdir -p /opt/splunkforwarder/etc/system/local/ # Créer le fichier inputs.conf avec les sources à surveiller sudo bash -c 'cat > /opt/splunkforwarder/etc/system/local/inputs.conf' << 'ENDOFFILE' [monitor:///var/log/auth.log] index = security sourcetype = linux_secure [monitor:///var/log/syslog] index = security sourcetype = syslog [monitor:///var/log/apache2/access.log] index = security sourcetype = access_combined [monitor:///var/log/apache2/error.log] index = security sourcetype = apache_error ENDOFFILE # Redémarrer le Forwarder pour appliquer sudo /opt/splunkforwarder/bin/splunk restart
linux_secure et access_combined sont des sourcetypes reconnus nativement par Splunk — il les parse automatiquement sans aucun GROK. C'est l'avantage du Forwarder sur rsyslog/Logstash pour des formats standards.
Depuis l'interface Splunk sur la VM SOC, vérifier que les logs de la VM cible arrivent via le Forwarder.
# Voir tous les événements reçus via le Forwarder (dernières 15 min) index=security # Filtrer uniquement les logs SSH (auth.log) index=security sourcetype=linux_secure # Filtrer les logs Apache index=security sourcetype=access_combined # Identifier les hôtes qui envoient des données index=security | stats count by host, sourcetype
La requête index=security | stats count by host, sourcetype retourne des lignes avec le hostname de la VM cible et au moins deux sourcetypes (linux_secure et access_combined).
1. Vérifier le Forwarder : sudo /opt/splunkforwarder/bin/splunk list forward-server → doit afficher "Active forwards".
2. Vérifier la connectivité : nc -zv 192.168.91.10 9997 depuis la VM cible.
3. Vérifier Splunk reçoit : ss -tlnp | grep 9997 sur la VM SOC → doit afficher LISTEN.
4. Logs du Forwarder : tail -50 /opt/splunkforwarder/var/log/splunk/splunkd.log | grep -i error
Générer du trafic réel pour peupler les index et préparer les exercices Fail2ban.
# Générer du trafic Apache for i in {1..20}; do curl -s http://localhost > /dev/null; done curl -s http://localhost/admin > /dev/null curl -s http://localhost/wp-admin > /dev/null curl -s http://localhost/.env > /dev/null # Tentative de fuite config # Générer des tentatives SSH échouées depuis la VM SOC vers la VM cible # (à exécuter depuis la VM SOC — remplacer l'IP par celle de la VM cible)
# Simuler des tentatives SSH échouées vers la VM cible # Remplacer 192.168.91.20 par l'IP réelle de votre VM cible for i in {1..8}; do ssh -o ConnectTimeout=3 -o StrictHostKeyChecking=no \ hackertest@192.168.91.20 2>/dev/null done echo "Tentatives SSH terminées"
# Voir les tentatives SSH échouées en temps réel index=security sourcetype=linux_secure "Failed password" | rex "from (?<src_ip>\d+\.\d+\.\d+\.\d+)" | stats count as tentatives by src_ip | sort -tentatives # ❓ Quelle IP a le plus de tentatives échouées ? # ❓ Est-ce l'IP de votre VM SOC ? Pourquoi est-ce logique ?
Fail2ban surveille les logs de la VM cible, détecte les attaques par force brute, bannit automatiquement les IPs fautives, et envoie les événements dans Splunk via le Forwarder.
Configurer ignoreip en PREMIER dans jail.local avec l'IP de votre VM SOC ET votre IP localhost. Sans ça, vos propres tentatives SSH de test vous bannissent et vous perdez l'accès à la VM cible.
sudo apt update && sudo apt install -y fail2ban # Vérifier la version fail2ban-client --version # Vérifier que le service tourne sudo systemctl status fail2ban
On ne modifie jamais jail.conf directement — il est écrasé lors des mises à jour. On crée jail.local qui surcharge uniquement les paramètres souhaités.
# Créer jail.local via heredoc pour éviter les problèmes de guillemets # IMPORTANT : remplacer 192.168.91.10 par l'IP réelle de votre VM SOC sudo bash -c 'cat > /etc/fail2ban/jail.local' << 'ENDOFFILE' [DEFAULT] # IPs à ne JAMAIS bannir (adapter avec vos IPs réelles) ignoreip = 127.0.0.1 ::1 192.168.91.0/24 bantime = 3600 ; Ban 1 heure findtime = 600 ; Fenêtre de détection : 10 minutes maxretry = 5 ; 5 échecs max avant bannissement backend = systemd ; Lire les logs via journald [sshd] enabled = true port = ssh logpath = %(sshd_log)s maxretry = 3 ; Plus strict pour SSH : 3 tentatives [apache-auth] enabled = true port = http,https logpath = %(apache_error_log)s maxretry = 5 [apache-badbots] enabled = true port = http,https logpath = %(apache_access_log)s maxretry = 2 ENDOFFILE # Redémarrer Fail2ban sudo systemctl restart fail2ban sudo systemctl status fail2ban
ignoreip = 192.168.91.0/24 ?
En ajoutant tout le sous-réseau NAT VMware, vous évitez de vous bannir vous-même lors des tests, quelle que soit l'IP exacte attribuée par DHCP à la VM SOC. En production, on serait plus restrictif.
# Lister les jails actives sudo fail2ban-client status # Détail d'une jail spécifique sudo fail2ban-client status sshd # Vérifier les logs Fail2ban sudo tail -20 /var/log/fail2ban.log # Tester un filtre sans redémarrer le service sudo fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf # → Affiche combien de lignes matchent le pattern sshd
sudo fail2ban-client status liste les jails sshd, apache-auth et apache-badbots. Chaque jail affiche "Currently banned: 0" au départ.
Pour déclencher Fail2ban, il faut générer des échecs SSH depuis une IP qui n'est pas dans la liste ignoreip. Ici on va modifier temporairement ignoreip pour le test, ou utiliser une commande plus fine.
Puisque la VM SOC est dans ignoreip, ses tentatives SSH ne déclencheront pas de ban. On va donc utiliser fail2ban-client pour bannir manuellement une IP factice et observer le comportement, puis on testera avec une IP hors du réseau NAT.
# Méthode 1 : Bannir manuellement une IP de test sudo fail2ban-client set sshd banip 1.2.3.4 # → L'IP 1.2.3.4 est maintenant bannie par iptables # Vérifier que l'IP est bannie sudo fail2ban-client status sshd # → "Currently banned: 1" et "Banned IP list: 1.2.3.4" # Vérifier la règle iptables créée sudo iptables -L f2b-sshd -n --line-numbers # Voir le log Fail2ban sudo tail -10 /var/log/fail2ban.log # → Doit afficher : Ban 1.2.3.4 # Débannir l'IP de test sudo fail2ban-client set sshd unbanip 1.2.3.4
Pour un test réaliste, retirer temporairement la VM SOC de ignoreip, générer les tentatives, puis remettre la protection.
# Temporairement : réduire ignoreip à localhost uniquement
sudo sed -i 's/ignoreip = 127.0.0.1 ::1 192.168.91.0\/24/ignoreip = 127.0.0.1 ::1/' \
/etc/fail2ban/jail.local
sudo fail2ban-client reload
# Générer 4 tentatives SSH échouées vers la VM cible (maxretry=3 → ban au 4ème) for i in {1..4}; do ssh -o ConnectTimeout=3 -o StrictHostKeyChecking=no \ -o PasswordAuthentication=yes \ hackertest@192.168.91.20 2>/dev/null || true sleep 1 done echo "Tentatives terminées"
# Vérifier que l'IP SOC est bannie sudo fail2ban-client status sshd sudo tail -5 /var/log/fail2ban.log # REMETTRE LA PROTECTION ignoreip immédiatement ! sudo sed -i 's/ignoreip = 127.0.0.1 ::1/ignoreip = 127.0.0.1 ::1 192.168.91.0\/24/' \ /etc/fail2ban/jail.local # Débannir l'IP SOC sudo fail2ban-client set sshd unbanip 192.168.91.10 sudo fail2ban-client reload
Le Forwarder doit surveiller /var/log/fail2ban.log pour envoyer les événements de bannissement vers Splunk.
# Ajouter le log Fail2ban dans inputs.conf sudo bash -c 'cat >> /opt/splunkforwarder/etc/system/local/inputs.conf' << 'ENDOFFILE' [monitor:///var/log/fail2ban.log] index = security sourcetype = fail2ban ENDOFFILE # Redémarrer le Forwarder pour appliquer sudo /opt/splunkforwarder/bin/splunk restart # Vérifier que le fichier inputs.conf est correct cat /opt/splunkforwarder/etc/system/local/inputs.conf
Pour que Splunk parse correctement les logs Fail2ban, on crée un sourcetype dédié dans l'interface.
Settings → Source types → New Source Type Name : fail2ban Description: Fail2ban ban/unban events Category : Operating System Line breaking → Every line is a separate event Timestamp → Current time (auto-detect) → Save
Exemple : 2026-04-02 11:15:32,123 fail2ban.actions [1234]: NOTICE [sshd] Ban 1.2.3.4
Les champs clés sont l'action (Ban / Unban), la jail (sshd), et l'IP. La requête SPL les extrait avec rex.
Générer d'abord un nouveau bannissement (étape 4 ou 5) pour avoir des données fraîches, puis réaliser les exercices ci-dessous dans l'ordre.
index=security sourcetype=fail2ban # ❓ Combien d'événements Ban vs Unban voyez-vous ? # ❓ Quelle jail a généré le plus d'événements ?
index=security sourcetype=fail2ban "Ban" | rex "NOTICE \[(?<jail>\w+)\] Ban (?<banned_ip>\d+\.\d+\.\d+\.\d+)" | stats count as nb_bans by banned_ip, jail | sort -nb_bans # ⭐ LIVRABLE : Screenshot → binome_tp2_fail2ban.png # ❓ Quelle IP a été bannie le plus souvent ? Depuis quelle jail ?
# Vue complète : tentatives SSH → bannissement index=security (sourcetype=linux_secure "Failed password") OR (sourcetype=fail2ban "Ban") | rex field=_raw "from (?<src_ip>\d+\.\d+\.\d+\.\d+)" | rex field=_raw "Ban (?<banned_ip>\d+\.\d+\.\d+\.\d+)" | eval ip=coalesce(src_ip, banned_ip) | stats count by ip, sourcetype | sort -count # ❓ Est-ce que les IPs qui ont tenté le SSH sont bien celles qui ont été bannies ? # ❓ Pourquoi corréler ces deux sourcetypes est utile pour un analyste L1 ?
index=security (sourcetype=linux_secure "Failed password")
OR (sourcetype=fail2ban "Ban")
| timechart span=5m count by sourcetype
# Visualization → Line Chart
# Sauvegarder : Save As → Report → "TP2_Attaques_SSH_Timeline"
# ❓ Le pic de bannissement suit-il le pic de tentatives ?
# ❓ Quel est le délai entre les premières tentatives et le ban ?
Par défaut, la communication entre le Forwarder et l'Indexer est en clair sur le port 9997. En production, il faut chiffrer ce flux. Voici la démarche :
# Dans /opt/splunk/etc/system/local/inputs.conf sur la VM SOC # Ajouter le stanza SSL pour le port 9997 [splunktcp-ssl:9997] disabled = false [SSL] serverCert = $SPLUNK_HOME/etc/auth/server.pem sslPassword = password requireClientCert = false
La configuration TLS complète est présentée ici à titre informatif et correspond au chapitre II.B "Sécurisation de la convergence des journaux" de la fiche de cours. Elle sera approfondie lors du projet Jour 5.
Tous ces points doivent être validés avant de quitter. Le Jour 3 (Suricata + Wazuh) démarre depuis cet état.
Faire un snapshot des deux VMs nommé "Jour2_OK". Vérifier aussi que ignoreip dans jail.local inclut bien le sous-réseau NAT complet — ne pas laisser la version restreinte du test.
ss -tlnp | grep 9997 retourne LISTEN sur la VM SOCsudo /opt/splunkforwarder/bin/splunk status → "splunkd is running"sudo /opt/splunkforwarder/bin/splunk list forward-server → "Active forwards"index=security | stats count by host, sourcetype retourne le hostname de la VM ciblelinux_secure et access_combined apparaissent dans les résultatssudo fail2ban-client status liste 3 jails actives (sshd, apache-auth, apache-badbots)ignoreip dans /etc/fail2ban/jail.local contient bien 192.168.91.0/24 (ou votre sous-réseau NAT)/var/log/fail2ban.log contient au moins un événement "Ban"index=security sourcetype=fail2ban "Ban" retourne au moins 1 événementbanned_ip et jailbinome_tp2_fail2ban.png réalisée (résultat exercice 2)Un botnet utilise des milliers d'IPs différentes, chacune ne faisant qu'une ou deux tentatives — jamais assez pour déclencher maxretry. Fail2ban est efficace contre les scanners naïfs, pas contre les attaques distribuées sophistiquées. C'est pourquoi on ajoute Suricata (Jour 3) pour la détection réseau plus fine.
rsyslog → Logstash → Elasticsearch : pipeline flexible, normalisation GROK personnalisable, multi-destination. Splunk Forwarder → Splunk Indexer : protocole natif Splunk, sourcetypes automatiques, compression, file persistante, futur TLS intégré. Les deux coexistent pour couvrir à la fois la stack ELK (Logstash) et Splunk.
1. Débannir l'IP immédiatement : sudo fail2ban-client set sshd unbanip X.X.X.X. 2. Ajouter l'IP dans ignoreip si légitime. 3. Créer un ticket dans le système de gestion d'incidents. 4. Revoir le seuil maxretry si trop faible. C'est une illustration parfaite du rôle L1 : triage rapide sans impacter la disponibilité.
Demain (Jour 3) : vous ajouterez Suricata (sonde réseau NIDS) et Wazuh (agent HIDS) pour couvrir les deux couches de détection manquantes. Le SOC commencera à ressembler à un vrai centre opérationnel.