CRITICAL FEATURE: Persistent historical IP attack tracking across monitor restarts

Implement lifetime detection history for each attacking IP.
Most servers see 0 SYN_RECV, so 70 active is highly suspicious.
Track which IPs have attacked 5-10 times over days, not just current session.

New behavior:
- Store historical hit count in ip_history_IPADDR file
- Load count at each detection
- Use TOTAL lifetime hits for threshold decisions, not just session hits
- Dramatically lower threshold for repeat attackers

Threshold adaptation:
- 10+ lifetime attacks: threshold = 1 (block even 1 connection)
- 5-9 lifetime attacks: threshold = 1 (from original 3)
- 3-4 lifetime attacks: threshold = 2 (from original 3)
- 2 lifetime attacks: threshold = 2 (from original 3)
- 1st attack: threshold = 3 (baseline)

Example: IP probes on Day 1, 2, 3 at 2-3 connections each
- Day 1: 2 connections < 3 threshold, not detected
- Day 2: 2 connections, now has 2 lifetime hits, threshold=2, 2 is NOT > 2, missed
- Day 3: 2 connections, now has 3 lifetime hits, threshold=2, 2 is NOT > 2, missed
- Day 4: 2 connections, now has 4 lifetime hits, threshold=2, 2 is NOT > 2, missed
- Day 5: 2 connections, now has 5 lifetime hits, threshold=1, 2 > 1, DETECTED & BLOCKED ✓

This catches persistent low-level attackers that would otherwise evade detection.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
cschantz
2026-03-06 23:03:09 -05:00
parent 3946a84e58
commit 4a9b449d60
+27 -8
View File
@@ -2619,14 +2619,22 @@ monitor_network_attacks() {
# Minimum threshold of 3 to prevent false positives on busy web servers
[ "$threshold" -lt 3 ] && threshold=3
# CRITICAL FIX: Adaptive threshold based on detection history
# An IP detected multiple times with SYN activity is more likely an attacker
# Lower threshold for repeat offenders to catch persistent attacks
if [ "${hits:-0}" -ge 3 ]; then
threshold=$((threshold - 2)) # Seen 3+ times: lower threshold significantly
# CRITICAL FIX: Adaptive threshold based on LIFETIME detection history
# Use persistent historical tracking (total_lifetime_hits) to catch repeat attackers
# An IP that attacks 5-10 times over days should be detected at lower threshold
# This catches distributed/low-level probes that space out attempts
local effective_hits="${total_lifetime_hits:-0}"
if [ "$effective_hits" -ge 10 ]; then
threshold=1 # Seen 10+ times across ALL TIME: auto-block even 1 connection
[ "$threshold" -lt 1 ] && threshold=1
elif [ "${hits:-0}" -ge 2 ]; then
threshold=$((threshold - 1)) # Seen 2 times: lower threshold slightly
elif [ "$effective_hits" -ge 5 ]; then
threshold=$((threshold - 2)) # 5-9 times: lower threshold by 2 (from 3 to 1)
[ "$threshold" -lt 1 ] && threshold=1
elif [ "$effective_hits" -ge 3 ]; then
threshold=$((threshold - 1)) # 3-4 times: lower threshold by 1
[ "$threshold" -lt 2 ] && threshold=2
elif [ "$effective_hits" -ge 2 ]; then
threshold=$((threshold - 1)) # 2 times: lower threshold slightly
[ "$threshold" -lt 2 ] && threshold=2
fi
@@ -2643,9 +2651,20 @@ monitor_network_attacks() {
fi
IFS='|' read -r score hits bot_type attacks ban_count rep_score <<< "$current_data"
# Increment hits
# Increment hits (this session)
hits=$((hits + 1))
# CRITICAL FIX: Persistent historical tracking across monitor restarts
# Track total lifetime detections of each IP (not just current session)
# This allows catching repeat attackers even if they space out attacks over time
local history_file="$TEMP_DIR/ip_history_${ip//\./_}"
local total_lifetime_hits=0
if [ -f "$history_file" ]; then
total_lifetime_hits=$(cat "$history_file" 2>/dev/null || echo 0)
fi
total_lifetime_hits=$((total_lifetime_hits + 1))
echo "$total_lifetime_hits" > "$history_file" 2>/dev/null
# Smart whitelisting: Skip IPs with MANY successful established connections
# Only whitelist if IP has 20+ established connections (highly unlikely for attacker)
# CRITICAL FIX: Use -w flag to match whole word (prevent partial IP matches)