chore: fix wazuh modsecurity decoder + noise rules
- Réécriture modsecurity_decoder.xml pour le format JSON audit libmodsecurity3 (Docker JSON log, log_format:json) Décoders séparés : blocked (403), rule, pass - Nouveau local_modsecurity_rules.xml : alertes niveaux 6/10/12 pour règles déclenchées, blocages 403 et scan répété - local_ssh_pam_noise.xml : rule 100001 → 100010 (évite conflit avec le placeholder de local_rules.xml) - Fix mln-uber ossec.conf : gestion-waf log filename .log.json → -json.log - docker-compose.yml + wazuh.indexer.yml : upgrade 4.14.4 → 4.14.5 + compatibility.override_main_response_version: true Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -34,7 +34,7 @@ services:
|
||||
|
||||
# ─── Wazuh Manager ────────────────────────────────────────
|
||||
wazuh.manager:
|
||||
image: wazuh/wazuh-manager:4.14.4
|
||||
image: wazuh/wazuh-manager:4.14.5
|
||||
hostname: wazuh.manager
|
||||
container_name: wazuh_manager
|
||||
restart: unless-stopped
|
||||
@@ -81,7 +81,7 @@ services:
|
||||
|
||||
# ─── Wazuh Indexer (OpenSearch) ───────────────────────────
|
||||
wazuh.indexer:
|
||||
image: wazuh/wazuh-indexer:4.14.4
|
||||
image: wazuh/wazuh-indexer:4.14.5
|
||||
hostname: wazuh.indexer
|
||||
container_name: wazuh_indexer
|
||||
restart: unless-stopped
|
||||
@@ -109,7 +109,7 @@ services:
|
||||
|
||||
# ─── Wazuh Dashboard ──────────────────────────────────────
|
||||
wazuh.dashboard:
|
||||
image: wazuh/wazuh-dashboard:4.14.4
|
||||
image: wazuh/wazuh-dashboard:4.14.5
|
||||
hostname: wazuh.dashboard
|
||||
container_name: wazuh_dashboard
|
||||
restart: unless-stopped
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
network.host: "0.0.0.0"
|
||||
node.name: "wazuh.indexer"
|
||||
cluster.initial_master_nodes:
|
||||
- "wazuh.indexer"
|
||||
cluster.name: "wazuh-cluster"
|
||||
|
||||
# Compatibilité Filebeat 7.x (libbeat) avec OpenSearch 2.x
|
||||
# Filebeat envoie _type dans les requêtes bulk — OpenSearch 2.x le rejette
|
||||
# sans ce flag.
|
||||
compatibility.override_main_response_version: true
|
||||
|
||||
path.data: /var/lib/wazuh-indexer
|
||||
path.logs: /var/log/wazuh-indexer
|
||||
|
||||
|
||||
@@ -1,29 +1,35 @@
|
||||
<!-- ═══════════════════════════════════════════════════════════════
|
||||
Decoders ModSecurity (nginx error.log)
|
||||
Format attendu :
|
||||
[client IP:PORT] ModSecurity: Access denied with code 403
|
||||
(phase 2). Message [id "XXXXX"] [msg "..."] [uri "..."]
|
||||
[client IP:PORT] ModSecurity: Warning. ... [id "XXXXX"]
|
||||
[msg "..."] [uri "..."]
|
||||
Decoders ModSecurity — JSON Audit Log (libmodsecurity3)
|
||||
Format : {"transaction":{"client_ip":"...","request":{"uri":"..."},
|
||||
"response":{"http_code":N},"messages":[{"details":{"ruleId":"N"}}]}}
|
||||
Collecté via log_format:json sur les fichiers Docker container log
|
||||
(Wazuh extrait le champ "log" du wrapper Docker JSON avant décodage)
|
||||
═══════════════════════════════════════════════════════════════ -->
|
||||
|
||||
<!-- Decoder parent : identifie toute ligne ModSecurity -->
|
||||
<decoder name="modsecurity">
|
||||
<prematch>ModSecurity: </prematch>
|
||||
<!-- Parent : toute transaction ModSecurity JSON -->
|
||||
<decoder name="docker-waf-modsec">
|
||||
<prematch>{"transaction":{</prematch>
|
||||
</decoder>
|
||||
|
||||
<!-- Decoder enfant : Access denied (requête bloquée) -->
|
||||
<decoder name="modsecurity-block">
|
||||
<parent>modsecurity</parent>
|
||||
<prematch>ModSecurity: Access denied</prematch>
|
||||
<regex>\[client (\d+\.\d+\.\d+\.\d+):\p+\] ModSecurity: Access denied with code (\d+) \(phase \d+\)\.\s*(\S[^[]*?)\s*\[id "(\d+)"\][^\[]*\[msg "([^"]+)"\][^\[]*\[uri "([^"]+)"\]</regex>
|
||||
<order>srcip,status,extra_data,id,extra_data2,url</order>
|
||||
<!-- Accès bloqué (http_code exactement 403) avec règle déclenchée.
|
||||
Listé en premier — priorité sur docker-waf-modsec-rule. -->
|
||||
<decoder name="docker-waf-modsec-blocked">
|
||||
<parent>docker-waf-modsec</parent>
|
||||
<regex>"client_ip":"(\d+\.\d+\.\d+\.\d+)".+"uri":"([^"]+)".+"http_code":403.+"ruleId":"(\d+)"</regex>
|
||||
<order>srcip,url,id</order>
|
||||
</decoder>
|
||||
|
||||
<!-- Decoder enfant : Warning (règle matchée sans blocage) -->
|
||||
<decoder name="modsecurity-warning">
|
||||
<parent>modsecurity</parent>
|
||||
<prematch>ModSecurity: Warning</prematch>
|
||||
<regex>\[client (\d+\.\d+\.\d+\.\d+):\p+\] ModSecurity: Warning\.[^\[]*\[id "(\d+)"\][^\[]*\[msg "([^"]+)"\][^\[]*\[uri "([^"]+)"\]</regex>
|
||||
<order>srcip,id,extra_data,url</order>
|
||||
<!-- Règle déclenchée sans blocage (warning / anomaly scoring).
|
||||
Capte aussi les non-403 avec ruleId. -->
|
||||
<decoder name="docker-waf-modsec-rule">
|
||||
<parent>docker-waf-modsec</parent>
|
||||
<regex>"client_ip":"(\d+\.\d+\.\d+\.\d+)".+"uri":"([^"]+)".+"ruleId":"(\d+)"</regex>
|
||||
<order>srcip,url,id</order>
|
||||
</decoder>
|
||||
|
||||
<!-- Trafic passant sans règle matchée (fallback) -->
|
||||
<decoder name="docker-waf-modsec-pass">
|
||||
<parent>docker-waf-modsec</parent>
|
||||
<regex>"client_ip":"(\d+\.\d+\.\d+\.\d+)".+"uri":"([^"]+)"</regex>
|
||||
<order>srcip,url</order>
|
||||
</decoder>
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
<!-- ═══════════════════════════════════════════════════════════════
|
||||
Règles ModSecurity — WAF container (gestion-waf)
|
||||
Source : logs JSON audit libmodsecurity3 via docker-waf-modsec*
|
||||
srcip = client_ip, url = uri, id = ruleId
|
||||
═══════════════════════════════════════════════════════════════ -->
|
||||
|
||||
<group name="web,modsecurity,">
|
||||
|
||||
<!-- Trafic passant sans règle déclenchée — supprimé (niveau 0) -->
|
||||
<rule id="100100" level="0">
|
||||
<decoded_as>docker-waf-modsec-pass</decoded_as>
|
||||
<description>ModSecurity: trafic légitime (supprimé).</description>
|
||||
</rule>
|
||||
|
||||
<!-- Règle WAF déclenchée sans blocage (warning / anomaly scoring) -->
|
||||
<rule id="100101" level="6">
|
||||
<decoded_as>docker-waf-modsec-rule</decoded_as>
|
||||
<description>ModSecurity: règle $(id) — $(srcip) → $(url)</description>
|
||||
<group>web,modsecurity,attack,</group>
|
||||
</rule>
|
||||
|
||||
<!-- Accès bloqué (HTTP 403) -->
|
||||
<rule id="100102" level="10">
|
||||
<decoded_as>docker-waf-modsec-blocked</decoded_as>
|
||||
<description>ModSecurity: accès bloqué (403) — $(srcip) → $(url) [règle $(id)]</description>
|
||||
<group>web,modsecurity,attack,blocked,</group>
|
||||
</rule>
|
||||
|
||||
<!-- Blocages répétés depuis la même IP → scan ou attaque -->
|
||||
<rule id="100103" level="12" frequency="5" timeframe="60">
|
||||
<if_matched_sid>100102</if_matched_sid>
|
||||
<same_source_ip />
|
||||
<description>ModSecurity: blocages répétés depuis $(srcip) — scan ou attaque</description>
|
||||
<group>web,modsecurity,attack,blocked,</group>
|
||||
</rule>
|
||||
|
||||
</group>
|
||||
@@ -7,6 +7,37 @@
|
||||
détection de brute-force (5710, 5716, 5720, 5760, 5763…)
|
||||
-->
|
||||
|
||||
<!-- ─── DPKG ───────────────────────────────────────────────────────────── -->
|
||||
<group name="syslog,dpkg,">
|
||||
<rule id="2901" level="0" overwrite="yes">
|
||||
<if_sid>2900</if_sid>
|
||||
<description>Dpkg: supprimé.</description>
|
||||
</rule>
|
||||
<rule id="2902" level="0" overwrite="yes">
|
||||
<if_sid>2900</if_sid>
|
||||
<description>Dpkg: supprimé.</description>
|
||||
</rule>
|
||||
<rule id="2903" level="0" overwrite="yes">
|
||||
<if_sid>2900</if_sid>
|
||||
<description>Dpkg: supprimé.</description>
|
||||
</rule>
|
||||
<rule id="2904" level="0" overwrite="yes">
|
||||
<if_sid>2900</if_sid>
|
||||
<description>Dpkg: supprimé.</description>
|
||||
</rule>
|
||||
</group>
|
||||
|
||||
<!-- ─── IP ADMIN (90.50.148.138) ─────────────────────────────────────── -->
|
||||
<!-- Auth success supprimé pour l'IP admin : pas de valeur sécurité,
|
||||
les échecs restent visibles si l'IP était usurpée. -->
|
||||
<group name="syslog,sshd,">
|
||||
<rule id="100010" level="0">
|
||||
<if_sid>5715</if_sid>
|
||||
<srcip>90.50.148.138</srcip>
|
||||
<description>sshd: auth success IP admin — supprimé.</description>
|
||||
</rule>
|
||||
</group>
|
||||
|
||||
<!-- ─── PAM ──────────────────────────────────────────────────────────── -->
|
||||
<group name="pam,syslog,">
|
||||
|
||||
@@ -74,3 +105,30 @@
|
||||
</rule>
|
||||
|
||||
</group>
|
||||
|
||||
<!-- ─── IOC Suricata/Windows — parents exclus (0475, 0580, 0840) ──────────
|
||||
Ces règles dans 0999-malicious-ioc-rules.xml ont des if_sid qui
|
||||
pointent vers des fichiers exclus. Sans overwrite, analysisd log des
|
||||
warnings (7617)/(7619) au démarrage. On les remplace par des règles
|
||||
level 0 pour silence les warnings sans affecter la détection IOC SSH. -->
|
||||
<group name="ids,">
|
||||
<rule id="99917" level="0" overwrite="yes">
|
||||
<match>.</match>
|
||||
<description>Suricata: malicious domain — non applicable (pas d'agent Suricata).</description>
|
||||
</rule>
|
||||
<rule id="99918" level="0" overwrite="yes">
|
||||
<match>.</match>
|
||||
<description>Suricata: malicious domain DNS — non applicable.</description>
|
||||
</rule>
|
||||
</group>
|
||||
|
||||
<group name="windows,windows_security,">
|
||||
<rule id="99919" level="0" overwrite="yes">
|
||||
<match>.</match>
|
||||
<description>Windows: failed logon malicious IP — non applicable (pas d'agent Windows).</description>
|
||||
</rule>
|
||||
<rule id="99920" level="0" overwrite="yes">
|
||||
<match>.</match>
|
||||
<description>Windows: successful logon malicious IP — non applicable.</description>
|
||||
</rule>
|
||||
</group>
|
||||
|
||||
Reference in New Issue
Block a user