This commit is contained in:
larssand
2026-06-21 15:19:24 +02:00
parent d41d318134
commit 5bb381a063
6 changed files with 81 additions and 20 deletions

View File

@@ -75,7 +75,7 @@ def _rate_per_minute(events: list[LogEvent]) -> tuple[float | None, float]:
def detect_source_anomalies(
events: list[LogEvent], *, limit: int = 20, baselines: dict[str, dict[str, float | int]] | None = None
events: list[LogEvent], *, limit: int = 20, baselines: dict[str, dict[str, object]] | None = None
) -> list[AnomalyFinding]:
baselines = baselines or {}
by_src: dict[str, list[LogEvent]] = defaultdict(list)
@@ -200,6 +200,19 @@ def detect_source_anomalies(
score += min(15, distinct_dst_ports)
reasons.append(f"many destination ports contacted ({distinct_dst_ports})")
baseline = baselines.get(src_ip)
if baseline:
known_destinations = set(baseline.get("known_destinations", []))
known_ports = set(baseline.get("known_destination_ports", []))
new_destinations = {event.dst_ip for event in src_events if event.dst_ip and event.dst_ip not in known_destinations}
new_ports = {event.fields.get("dstport") for event in src_events if event.fields.get("dstport") and event.fields.get("dstport") not in known_ports}
if len(known_destinations) >= 5 and len(new_destinations) >= 3:
score += min(15, 5 + len(new_destinations))
reasons.append(f"new destinations relative to historical baseline ({len(new_destinations)})")
if len(known_ports) >= 3 and len(new_ports) >= 2:
score += min(12, 4 + len(new_ports))
reasons.append(f"new destination ports relative to historical baseline ({len(new_ports)})")
if _is_public_ip(src_ip) and (utm_count or deny_count >= 10):
score += 10
reasons.append("public source with repeated security-relevant events")
@@ -232,6 +245,7 @@ def detect_source_anomalies(
"distinct_dst_ports": distinct_dst_ports,
"policy_count": len(policies),
"implicit_deny_events": implicit_deny_count,
"baseline_ready": int(src_ip in baselines),
},
)
)