From 06a0e6ff133b7ac050a6aa9c654918827f9b1412 Mon Sep 17 00:00:00 2001 From: Nuxgrid Date: Fri, 31 Jul 2026 11:06:12 +0200 Subject: [PATCH] chore: update --- .../wazuh/config/wazuh_manager/ossec.conf | 4 +- .../wazuh/create-saved-queries-web.py | 107 ++++++++++++++++++ .../wazuh/create-saved-query-no-vpn.py | 78 +++++++++++++ 3 files changed, 188 insertions(+), 1 deletion(-) create mode 100644 monitoring/security/wazuh/create-saved-queries-web.py create mode 100644 monitoring/security/wazuh/create-saved-query-no-vpn.py diff --git a/monitoring/security/wazuh/config/wazuh_manager/ossec.conf b/monitoring/security/wazuh/config/wazuh_manager/ossec.conf index e8611ad3..290dec99 100755 --- a/monitoring/security/wazuh/config/wazuh_manager/ossec.conf +++ b/monitoring/security/wazuh/config/wazuh_manager/ossec.conf @@ -17,7 +17,7 @@ ALERTES ═══════════════════════════════════════════════════════════ --> - 4 + 3 127.0.0.1 ^localhost.localdomain$ 90.50.148.138 + 90.120.69.13 10.0.0.3 diff --git a/monitoring/security/wazuh/create-saved-queries-web.py b/monitoring/security/wazuh/create-saved-queries-web.py new file mode 100644 index 00000000..9dc7daf1 --- /dev/null +++ b/monitoring/security/wazuh/create-saved-queries-web.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python3 +""" +Crée des Saved Queries réutilisables pour la détection d'attaques web +(ModSecurity/OWASP, rules 100100-100396 — voir +config/wazuh_manager/rules/modsecurity_owasp_rules.xml) dans OpenSearch +Dashboards (Wazuh). + +Usage: + docker cp create-saved-queries-web.py wazuh_dashboard:/tmp/ + docker exec wazuh_dashboard python3 /tmp/create-saved-queries-web.py + +Une fois créées, ouvrir n'importe quelle vue (Security Events, Discover...) > +barre de recherche > icone dossier (Saved Queries) > sélectionner la query. +""" + +import json +import urllib.request +import urllib.error +import ssl +import base64 +import sys +import os + +# ── Configuration ──────────────────────────────────────────────────────────── +DASHBOARD_HOST = "https://localhost:5601" +DASHBOARD_USER = "kibanaserver" +DASHBOARD_PASS = os.environ.get("DASHBOARD_PASSWORD", "E9Jpr6586kQ3wYrCS2!") + +# ── Queries ─────────────────────────────────────────────────────────────────── +QUERIES = [ + { + "id": "web-attacks-all", + "title": "Attaques Web - Toutes", + "description": "Tous les événements ModSecurity/OWASP (bloqués + remontés en anomaly scoring).", + "kuery": "rule.groups: web", + }, + { + "id": "web-attacks-blocked", + "title": "Attaques Web - Bloquées (WAF)", + "description": "Requêtes réellement bloquées par le WAF (exclut les anomaly scoring non bloquants, groupe 'warning').", + "kuery": "rule.groups: web AND NOT rule.groups: warning", + }, + { + "id": "web-attacks-critical", + "title": "Attaques Web - Critiques", + "description": "Niveau >= 13 : SQLi/RCE/command injection bloquées, XXE, SSRF, patterns répétés (owasp_injection critical/brute_force).", + "kuery": "rule.groups: web AND rule.level >= 13", + }, + { + "id": "web-attacks-scanners", + "title": "Attaques Web - Scanners / Recon", + "description": "Détection de scanners/bots (OWASP#9 — groupe scanner_detection).", + "kuery": "rule.groups: scanner_detection", + }, + { + "id": "web-attacks-repeated", + "title": "Attaques Web - Patterns répétés (brute-force)", + "description": "Attaques soutenues détectées par fréquence : SQLi (100290), XSS (100291), RCE (100292), path traversal (100293), anomaly scoring répété (100394-100396).", + "kuery": "rule.id: 100290 OR rule.id: 100291 OR rule.id: 100292 OR rule.id: 100293 OR rule.id: 100394 OR rule.id: 100395 OR rule.id: 100396", + }, +] + +# ── Client HTTP ─────────────────────────────────────────────────────────────── +ctx = ssl.create_default_context() +ctx.check_hostname = False +ctx.verify_mode = ssl.CERT_NONE + +_auth = base64.b64encode(f"{DASHBOARD_USER}:{DASHBOARD_PASS}".encode()).decode() +_headers = { + "Content-Type": "application/json", + "osd-xsrf": "true", + "Authorization": f"Basic {_auth}", +} + +def api(method, path, body=None): + data = json.dumps(body).encode() if body else None + req = urllib.request.Request(DASHBOARD_HOST + path, data=data, headers=_headers, method=method) + try: + with urllib.request.urlopen(req, context=ctx, timeout=15) as r: + return json.loads(r.read()) + except urllib.error.HTTPError as e: + return {"error": e.code, "msg": e.read().decode()[:300]} + +def main(): + print("=== Creation Saved Queries: Attaques Web ===\n") + failed = False + for q in QUERIES: + body = { + "attributes": { + "title": q["title"], + "description": q["description"], + "query": {"language": "kuery", "query": q["kuery"]}, + "filters": [], + } + } + r = api("POST", f"/api/saved_objects/query/{q['id']}?overwrite=true", body) + if "id" in r: + print(f" OK {q['title']}") + else: + print(f" ERR {q['title']}: {r}") + failed = True + if failed: + sys.exit(1) + print("\n=== Termine ===") + +if __name__ == "__main__": + main() diff --git a/monitoring/security/wazuh/create-saved-query-no-vpn.py b/monitoring/security/wazuh/create-saved-query-no-vpn.py new file mode 100644 index 00000000..f813028b --- /dev/null +++ b/monitoring/security/wazuh/create-saved-query-no-vpn.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python3 +""" +Crée une Saved Query "Sans VPN" réutilisable dans OpenSearch Dashboards (Wazuh). + +Objectif : permettre d'exclure en un clic les alertes WireGuard/VPN (handshakes, +timeouts, roaming, reconnexions — rules 100800-100826) de la vue native +"Security Events" / "Threat Hunting", qui liste par défaut TOUTES les alertes +sans filtre de groupe. Le dashboard dédié "VPN - Activite WireGuard" +(create-dashboard-vpn.py) continue lui d'afficher ces événements normalement : +cette query ne supprime rien de l'index, elle filtre uniquement l'affichage. + +Usage: + docker cp create-saved-query-no-vpn.py wazuh_dashboard:/tmp/ + docker exec wazuh_dashboard python3 /tmp/create-saved-query-no-vpn.py + +Une fois créée, ouvrir "Security Events" > barre de recherche > icône +"Saved Queries" (dossier) > sélectionner "Sans VPN". +""" + +import json +import urllib.request +import urllib.error +import ssl +import base64 +import sys +import os + +# ── Configuration ──────────────────────────────────────────────────────────── +DASHBOARD_HOST = "https://localhost:5601" +DASHBOARD_USER = "kibanaserver" +DASHBOARD_PASS = os.environ.get("DASHBOARD_PASSWORD", "E9Jpr6586kQ3wYrCS2!") + +QUERY_ID = "no-vpn-alerts" +QUERY_TITLE = "Sans VPN" +QUERY_DESC = "Exclut les alertes WireGuard/VPN (handshakes, timeouts, roaming) de la vue Security Events." +QUERY_KUERY = "NOT rule.groups: wireguard" + +# ── Client HTTP ─────────────────────────────────────────────────────────────── +ctx = ssl.create_default_context() +ctx.check_hostname = False +ctx.verify_mode = ssl.CERT_NONE + +_auth = base64.b64encode(f"{DASHBOARD_USER}:{DASHBOARD_PASS}".encode()).decode() +_headers = { + "Content-Type": "application/json", + "osd-xsrf": "true", + "Authorization": f"Basic {_auth}", +} + +def api(method, path, body=None): + data = json.dumps(body).encode() if body else None + req = urllib.request.Request(DASHBOARD_HOST + path, data=data, headers=_headers, method=method) + try: + with urllib.request.urlopen(req, context=ctx, timeout=15) as r: + return json.loads(r.read()) + except urllib.error.HTTPError as e: + return {"error": e.code, "msg": e.read().decode()[:300]} + +def main(): + print("=== Creation Saved Query: Sans VPN ===\n") + body = { + "attributes": { + "title": QUERY_TITLE, + "description": QUERY_DESC, + "query": {"language": "kuery", "query": QUERY_KUERY}, + "filters": [], + } + } + r = api("POST", f"/api/saved_objects/query/{QUERY_ID}?overwrite=true", body) + if "id" in r: + print(f" OK Saved Query '{QUERY_TITLE}' créée ({r['id']})") + print(" Utilisation : Security Events > barre de recherche > icone dossier (Saved Queries) > 'Sans VPN'") + else: + print(f" ERR {r}") + sys.exit(1) + +if __name__ == "__main__": + main()