#!/usr/bin/env python3 """ siem_analyzer.py ================= A small, dependency-free SIEM (Security Information & Event Management) log analyzer. It ingests traffic/activity logs from THREE endpoints: 1. Web server access log (endpoint-1 : nginx/Apache "combined" style) 2. Firewall / router log (endpoint-2 : SRC/DST/PORT/ACTION style) 3. SSH authentication log (endpoint-3 : syslog "sshd" style) ...runs a set of detection rules against each, correlates activity from the SAME source IP across DIFFERENT endpoints (the core value-add of a real SIEM), and writes the results as JSON for the companion HTML/CSS/JS dashboard to render. Usage ----- python3 siem_analyzer.py python3 siem_analyzer.py --logs-dir ./logs --out-dir ./dashboard No third-party packages required (standard library only). """ from __future__ import annotations import argparse import json import re import sys from urllib.parse import unquote from collections import Counter, defaultdict from dataclasses import dataclass, field, asdict from datetime import datetime, timedelta, timezone from pathlib import Path from typing import List, Dict, Any, Tuple # -------------------------------------------------------------------------- # Configuration: detection thresholds & signatures # -------------------------------------------------------------------------- THRESHOLDS = { "brute_force_attempts": 5, # failed logins ... "brute_force_window_sec": 300, # ... within this many seconds "port_scan_distinct_ports": 8, # distinct dest ports ... "port_scan_window_sec": 120, # ... within this many seconds "high_rate_requests": 15, # requests ... "high_rate_window_sec": 60, # ... within this many seconds } # Example threat-intel seed list: IPs already known to be bad regardless of # behaviour observed in these logs. In production this would be pulled from # a feed (AbuseIPDB, OTX, internal blocklist, etc). KNOWN_MALICIOUS_IPS = { "192.0.2.77": "Listed in external threat-intel feed (example seed entry)", } # (regex, label, severity) -- checked against URL path + query + referer SUSPICIOUS_WEB_PATTERNS: List[Tuple[re.Pattern, str, str]] = [ (re.compile(r"union(\s|%20)+select", re.I), "SQL_INJECTION", "critical"), (re.compile(r"'\s*or\s*'?1'?\s*=\s*'?1", re.I), "SQL_INJECTION", "critical"), (re.compile(r"sleep\(\d+\)", re.I), "SQL_INJECTION", "critical"), (re.compile(r"", re.I), "XSS", "high"), (re.compile(r"javascript:", re.I), "XSS", "high"), (re.compile(r"\.\./\.\./", re.I), "PATH_TRAVERSAL", "high"), (re.compile(r"etc/passwd|etc/shadow", re.I), "PATH_TRAVERSAL", "high"), (re.compile(r";\s*(rm|wget|curl|nc)\s", re.I), "COMMAND_INJECTION", "critical"), ] SCANNER_USER_AGENTS = ["sqlmap", "nikto", "nmap", "masscan", "acunetix", "nessus", "wpscan"] SEVERITY_WEIGHT = {"critical": 10, "high": 5, "medium": 2, "low": 1} SEVERITY_ORDER = ["critical", "high", "medium", "low"] ENDPOINT_WEB = "web-server (endpoint-1)" ENDPOINT_FW = "firewall (endpoint-2)" ENDPOINT_AUTH = "ssh-auth (endpoint-3)" # -------------------------------------------------------------------------- # Parsing # -------------------------------------------------------------------------- WEB_LOG_RE = re.compile( r'(?P\S+) \S+ \S+ \[(?P