Add auto-blocking for distributed attacks
When 5+ IPs perform same attack type (RCE, SQL_INJECTION, XSS, PATH_TRAVERSAL, BRUTEFORCE) within 2 minutes: - Block all individual attacking IPs immediately via IPset - If 25+ IPs from same /24 subnet, block entire subnet Uses batch_block_ips() for efficient IPset operations. All blocking is kernel-level via IPset (no CSF commands).
This commit is contained in:
@@ -3263,34 +3263,66 @@ detect_distributed_attacks() {
|
||||
|
||||
# Check for same attack type from 5+ different IPs (use awk for performance)
|
||||
for attack_type in RCE SQL_INJECTION XSS PATH_TRAVERSAL BRUTEFORCE; do
|
||||
# Single AWK pass to count attacks and unique IPs
|
||||
local result=$(echo "$recent" | awk -v pattern="$attack_type" '
|
||||
# Single AWK pass to extract all attacking IPs
|
||||
local attacking_ips=$(echo "$recent" | awk -v pattern="$attack_type" '
|
||||
$0 ~ pattern {
|
||||
count++
|
||||
# Extract IP (first field matching IP pattern)
|
||||
for(i=1; i<=NF; i++) {
|
||||
if($i ~ /^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/) {
|
||||
ips[$i]=1
|
||||
print $i
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
END {
|
||||
print count "|" length(ips)
|
||||
}
|
||||
')
|
||||
IFS='|' read -r attack_count unique_ips <<< "$result"
|
||||
' | sort -u)
|
||||
|
||||
if [ "${attack_count:-0}" -ge 5 ]; then
|
||||
# Count unique IPs
|
||||
local unique_ips=$(echo "$attacking_ips" | grep -c "^[0-9]" 2>/dev/null || echo "0")
|
||||
|
||||
if [ "$unique_ips" -ge 5 ]; then
|
||||
# Distributed attack detected!
|
||||
local time_str=$(date +"%H:%M:%S")
|
||||
echo -e "${CRITICAL_COLOR}[${time_str}] DISTRIBUTED_ATTACK | ${attack_type} from ${unique_ips} IPs in last 2min | Possible botnet${NC}" >> "$TEMP_DIR/recent_events"
|
||||
if [ "${unique_ips:-0}" -ge 5 ]; then
|
||||
# Distributed attack detected!
|
||||
local time_str=$(date +"%H:%M:%S")
|
||||
|
||||
# Mark in a file for Quick Actions to see
|
||||
echo "${attack_type}|${unique_ips}|$(date +%s)" >> "$TEMP_DIR/distributed_attacks"
|
||||
# BLOCK ALL INDIVIDUAL IPs IN THE ATTACK
|
||||
local -a batch_ips=()
|
||||
while IFS= read -r ip; do
|
||||
[ -n "$ip" ] && batch_ips+=("$ip")
|
||||
done <<< "$attacking_ips"
|
||||
|
||||
if [ ${#batch_ips[@]} -gt 0 ]; then
|
||||
batch_block_ips "${batch_ips[@]}"
|
||||
echo -e "${CRITICAL_COLOR}[${time_str}] DISTRIBUTED_ATTACK | ${attack_type} from ${unique_ips} IPs | BLOCKED ALL${NC}" >> "$TEMP_DIR/recent_events"
|
||||
fi
|
||||
|
||||
# Check for subnet-level coordination (25+ IPs from same /24)
|
||||
declare -A subnet_counts
|
||||
while IFS= read -r ip; do
|
||||
[ -z "$ip" ] && continue
|
||||
local subnet="${ip%.*}" # Get /24 subnet (bash built-in)
|
||||
((subnet_counts[$subnet]++))
|
||||
done <<< "$attacking_ips"
|
||||
|
||||
# Block entire subnets with 25+ attacking IPs
|
||||
for subnet in "${!subnet_counts[@]}"; do
|
||||
local subnet_ip_count=${subnet_counts[$subnet]}
|
||||
if [ "$subnet_ip_count" -ge 25 ]; then
|
||||
local subnet_cidr="${subnet}.0/24"
|
||||
|
||||
# Check if not already blocked
|
||||
if ! grep -q "^${subnet_cidr}\$" "$TEMP_DIR/blocked_subnets" 2>/dev/null; then
|
||||
echo "$subnet_cidr" >> "$TEMP_DIR/blocked_subnets"
|
||||
|
||||
# Add to IPset (kernel-level blocking)
|
||||
if [ "$IPSET_AVAILABLE" -eq 1 ]; then
|
||||
ipset add "$IPSET_NAME" "$subnet_cidr" -exist 2>/dev/null
|
||||
echo -e "${CRITICAL_COLOR}[${time_str}] SUBNET_BLOCK | $subnet_cidr | ${attack_type} from ${subnet_ip_count} IPs | BLOCKED${NC}" >> "$TEMP_DIR/recent_events"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# Mark in a file for Quick Actions to see
|
||||
echo "${attack_type}|${unique_ips}|$(date +%s)" >> "$TEMP_DIR/distributed_attacks"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user