#!/bin/bash ################################################################################ # Live Network Security Monitor - ENHANCED with Intelligence ################################################################################ # Purpose: Real-time monitoring with bot intelligence and threat scoring # Version: 2.0 - Intelligence Mode # Features: # - Bot classification using learned signatures # - IP reputation DB integration # - Real-time threat scoring (0-100) # - Attack vector detection # - Quick action blocking system # - Ban tracking and history ################################################################################ # Get script directory SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" source "$SCRIPT_DIR/lib/common-functions.sh" source "$SCRIPT_DIR/lib/system-detect.sh" source "$SCRIPT_DIR/lib/ip-reputation.sh" source "$SCRIPT_DIR/lib/bot-signatures.sh" source "$SCRIPT_DIR/lib/attack-patterns.sh" source "$SCRIPT_DIR/lib/threat-intelligence.sh" # Require root if [ "$EUID" -ne 0 ]; then print_error "This script must be run as root" exit 1 fi # Color definitions for threat levels CRITICAL_COLOR='\033[1;41;97m' # White on Red background HIGH_COLOR='\033[1;31m' # Bold Red MEDIUM_COLOR='\033[1;33m' # Bold Yellow LOW_COLOR='\033[0;36m' # Cyan SAFE_COLOR='\033[0;32m' # Green INFO_COLOR='\033[0;37m' # White BOLD='\033[1m' # Bold text NC='\033[0m' # Configuration REFRESH_INTERVAL=2 # Seconds between dashboard refreshes MAX_DISPLAY_LINES=20 THREAT_THRESHOLD_CRITICAL=80 THREAT_THRESHOLD_HIGH=60 THREAT_THRESHOLD_MEDIUM=40 # Temporary files for tracking TEMP_DIR="/tmp/live-monitor-$$" SNAPSHOT_DIR="/var/lib/server-toolkit/live-monitor" mkdir -p "$TEMP_DIR" "$SNAPSHOT_DIR" 2>/dev/null touch "$TEMP_DIR/recent_events" touch "$TEMP_DIR/ip_data" echo "0" > "$TEMP_DIR/event_counter" # Save snapshot of IP data (for persistence across restarts) save_snapshot() { { for ip in "${!IP_DATA[@]}"; do echo "$ip=${IP_DATA[$ip]}" done } > "$SNAPSHOT_DIR/ip_data_snapshot" 2>/dev/null } # Cleanup function cleanup() { echo "" echo "Stopping monitoring processes..." # Save snapshot before exit save_snapshot # Kill all child processes pkill -P $$ 2>/dev/null # Wait a moment for background jobs sleep 1 # Clean up temp directory rm -rf "$TEMP_DIR" 2>/dev/null # Restore cursor command -v tput &>/dev/null && tput cnorm echo "✓ Cleanup complete (snapshot saved)" exit 0 } trap cleanup EXIT INT TERM # Statistics counters declare -A IP_DATA # Stores: IP -> score|hits|bot_type|attacks|ban_count declare -A ATTACK_TYPE_COUNTER TOTAL_THREATS=0 START_TIME=$(date +%s) MAX_TRACKED_IPS=500 # Prevent memory overflow # Load persistent data from previous sessions if exists if [ -f "$SNAPSHOT_DIR/ip_data_snapshot" ]; then while IFS='=' read -r ip data; do [ -n "$ip" ] && IP_DATA[$ip]="$data" done < "$SNAPSHOT_DIR/ip_data_snapshot" fi # Hide cursor for cleaner display command -v tput &>/dev/null && tput civis ################################################################################ # Intelligence Functions ################################################################################ # Get or create IP intelligence data # Returns: score|hits|bot_type|attacks|ban_count|rep_score get_ip_intelligence() { local ip="$1" # Check if we have cached data if [ -n "${IP_DATA[$ip]}" ]; then echo "${IP_DATA[$ip]}" return 0 fi # Query IP reputation database local rep_data=$(lookup_ip "$ip" 2>/dev/null) if [ -n "$rep_data" ]; then # Parse: IP|HIT_COUNT|REP_SCORE|COUNTRY|ATTACK_FLAGS|... IFS='|' read -r _ db_hits rep_score country attack_flags _ _ _ notes ban_count _ <<< "$rep_data" # Initialize with learned data local score=${rep_score:-0} local hits=${db_hits:-0} local bot_type="unknown" local attacks=$(decode_attack_flags "$attack_flags" 2>/dev/null | tr ',' ' ' || echo "") ban_count=${ban_count:-0} # Cache it IP_DATA[$ip]="$score|$hits|$bot_type|$attacks|$ban_count|$rep_score" echo "${IP_DATA[$ip]}" else # New IP - initialize IP_DATA[$ip]="0|0|unknown||0|0" echo "${IP_DATA[$ip]}" fi } # Update IP intelligence update_ip_intelligence() { local ip="$1" local url="$2" local user_agent="$3" local method="${4:-GET}" # Get current data local current=$(get_ip_intelligence "$ip") IFS='|' read -r score hits bot_type attacks ban_count rep_score <<< "$current" # Increment hits hits=$((hits + 1)) # Enrich with threat intelligence on first encounter (hits == 1) if [ $hits -eq 1 ]; then # Check if whitelisted first if is_whitelisted_service "$ip" 2>/dev/null; then score=0 bot_type="legit" else # Get threat intelligence (in background to avoid slowing down) ( local threat_intel=$(get_threat_intelligence "$ip" 2>/dev/null) IFS='|' read -r abuse_conf abuse_rpts country isp geo timing whitelisted <<< "$threat_intel" # Store enrichment data for later use local enrich_file="$TEMP_DIR/threat_enrich_${ip//\./_}" echo "$threat_intel" > "$enrich_file" # Boost score based on AbuseIPDB confidence if [ "${abuse_conf:-0}" -ge 75 ]; then # High confidence malicious - add 30 points local current_data="${IP_DATA[$ip]}" IFS='|' read -r old_score old_hits old_bot old_attacks old_ban old_rep <<< "$current_data" local new_score=$((old_score + 30)) [ $new_score -gt 100 ] && new_score=100 IP_DATA[$ip]="$new_score|$old_hits|$old_bot|$old_attacks|$old_ban|$old_rep" elif [ "${abuse_conf:-0}" -ge 50 ]; then # Medium confidence - add 15 points local current_data="${IP_DATA[$ip]}" IFS='|' read -r old_score old_hits old_bot old_attacks old_ban old_rep <<< "$current_data" local new_score=$((old_score + 15)) [ $new_score -gt 100 ] && new_score=100 IP_DATA[$ip]="$new_score|$old_hits|$old_bot|$old_attacks|$old_ban|$old_rep" fi # High-risk country adds 5 points if is_high_risk_country "${geo:-XX}" 2>/dev/null; then local current_data="${IP_DATA[$ip]}" IFS='|' read -r old_score old_hits old_bot old_attacks old_ban old_rep <<< "$current_data" local new_score=$((old_score + 5)) [ $new_score -gt 100 ] && new_score=100 IP_DATA[$ip]="$new_score|$old_hits|$old_bot|$old_attacks|$old_ban|$old_rep" fi ) & fi fi # Classify bot if unknown if [ "$bot_type" = "unknown" ] && [ -n "$user_agent" ]; then bot_type=$(classify_bot_type "$user_agent") fi # Record attack pattern for learning if [ -n "$url" ]; then record_attack_pattern "$ip" "${attacks:-unknown}" "$url" "${user_agent:-unknown}" 2>/dev/null & fi # Detect attacks in URL local new_attacks=$(detect_all_attacks "$url" "$method") if [ -n "$new_attacks" ]; then # Add to attack list (unique) if [ -z "$attacks" ]; then attacks="$new_attacks" else attacks="$attacks,$new_attacks" fi # Remove duplicates attacks=$(echo "$attacks" | tr ',' '\n' | sort -u | tr '\n' ',' | sed 's/,$//') # Update attack type counter IFS=',' read -ra ATTACK_ARRAY <<< "$new_attacks" for attack in "${ATTACK_ARRAY[@]}"; do ((ATTACK_TYPE_COUNTER["$attack"]++)) done # Calculate attack score local attack_score=$(calculate_attack_score "$new_attacks") score=$((score + attack_score)) ((TOTAL_THREATS++)) fi # Request volume scoring if [ $hits -gt 100 ]; then score=$((score + 5)) elif [ $hits -gt 50 ]; then score=$((score + 3)) elif [ $hits -gt 20 ]; then score=$((score + 1)) fi # Adjust score based on bot type case "$bot_type" in legit|ai|monitor) # Legitimate bots - reduce score score=$((score - 5)) [ $score -lt 0 ] && score=0 ;; suspicious) # Suspicious bots - increase score score=$((score + 10)) ;; esac # Cap at 100 [ $score -gt 100 ] && score=100 # Check if we're tracking too many IPs (memory protection) if [ ${#IP_DATA[@]} -ge $MAX_TRACKED_IPS ]; then # Remove lowest scoring IPs local to_remove=() for check_ip in "${!IP_DATA[@]}"; do local check_score=$(echo "${IP_DATA[$check_ip]}" | cut -d'|' -f1) [ "$check_score" -lt 10 ] && to_remove+=("$check_ip") done # Remove up to 100 low-score IPs local removed=0 for remove_ip in "${to_remove[@]}"; do unset IP_DATA[$remove_ip] ((removed++)) [ $removed -ge 100 ] && break done fi # Update cached data IP_DATA[$ip]="$score|$hits|$bot_type|$attacks|$ban_count|$rep_score" # Update IP reputation DB in background (if score > 0) if [ $score -gt 0 ]; then (update_ip_reputation "$ip" 1 "$score" 0 "Live monitor: $new_attacks" >/dev/null 2>&1) & fi } # Get threat level from score get_threat_level() { local score="$1" if [ "$score" -ge "$THREAT_THRESHOLD_CRITICAL" ]; then echo "CRITICAL" elif [ "$score" -ge "$THREAT_THRESHOLD_HIGH" ]; then echo "HIGH" elif [ "$score" -ge "$THREAT_THRESHOLD_MEDIUM" ]; then echo "MEDIUM" else echo "LOW" fi } # Get color for threat level get_threat_color() { local level="$1" case "$level" in CRITICAL) echo "$CRITICAL_COLOR" ;; HIGH) echo "$HIGH_COLOR" ;; MEDIUM) echo "$MEDIUM_COLOR" ;; LOW) echo "$LOW_COLOR" ;; SAFE) echo "$SAFE_COLOR" ;; *) echo "$INFO_COLOR" ;; esac } # Get bot color get_bot_color() { local bot_type="$1" case "$bot_type" in legit) echo "$SAFE_COLOR" ;; ai) echo '\033[0;34m' ;; # Blue monitor) echo "$MEDIUM_COLOR" ;; suspicious) echo "$HIGH_COLOR" ;; *) echo "$INFO_COLOR" ;; esac } ################################################################################ # Dashboard Display Functions ################################################################################ draw_header() { clear local uptime=$(($(date +%s) - START_TIME)) local uptime_str=$(printf "%02d:%02d:%02d" $((uptime/3600)) $((uptime%3600/60)) $((uptime%60))) # Read event counter from file (updated by subshell) local event_count=$(cat "$TEMP_DIR/event_counter" 2>/dev/null || echo "0") echo -e "${CRITICAL_COLOR}╔════════════════════════════════════════════════════════════════════════════╗${NC}" echo -e "${CRITICAL_COLOR}║ 🚨 LIVE SECURITY MONITOR - INTELLIGENCE MODE 🧠 ║${NC}" echo -e "${CRITICAL_COLOR}╚════════════════════════════════════════════════════════════════════════════╝${NC}" echo -e "${INFO_COLOR}Runtime: ${uptime_str} | Events: ${event_count} | Threats: ${TOTAL_THREATS} | Monitoring...${NC}" echo "" } draw_intelligence_panel() { echo -e "${HIGH_COLOR}┌─ THREAT INTELLIGENCE ──────────────────────────────────────────────────────┐${NC}" # Get top IPs by threat score local count=0 for ip in "${!IP_DATA[@]}"; do IFS='|' read -r score hits bot_type attacks ban_count rep_score <<< "${IP_DATA[$ip]}" echo "$score|$ip|$hits|$bot_type|$attacks|$ban_count|$rep_score" done | sort -t'|' -k1 -rn | head -10 | while IFS='|' read -r score ip hits bot_type attacks ban_count rep_score; do local level=$(get_threat_level "$score") local color=$(get_threat_color "$level") local bot_color=$(get_bot_color "$bot_type") # Build status line local status_line=$(printf "%-15s" "$ip") status_line+=$(printf " Score:%-3s" "$score") status_line+=$(printf " Hits:%-4s" "$hits") # Bot type indicator case "$bot_type" in legit) status_line+=" ✅BOT" ;; ai) status_line+=" 🤖AI" ;; monitor) status_line+=" 📊MON" ;; suspicious) status_line+=" ⚠️ SUS" ;; *) status_line+="" ;; esac # Threat level status_line+=$(printf " [%-8s]" "$level") # Attacks if [ -n "$attacks" ]; then # Show first attack type local first_attack=$(echo "$attacks" | cut -d',' -f1) local icon=$(get_attack_icon "$first_attack") status_line+=" $icon$(echo "$attacks" | cut -d',' -f1)" fi # Ban count if [ "$ban_count" -gt 0 ]; then status_line+=" 🚫x$ban_count" fi # Known threat indicator if [ "$rep_score" -gt 0 ]; then status_line+=" [KNOWN]" fi echo -e "${color}${status_line}${NC}" done echo -e "${HIGH_COLOR}└────────────────────────────────────────────────────────────────────────────┘${NC}" echo "" } draw_attack_breakdown() { echo -e "${MEDIUM_COLOR}┌─ ATTACK VECTORS ───────────────────────────────────────────────────────────┐${NC}" if [ ${#ATTACK_TYPE_COUNTER[@]} -eq 0 ]; then echo -e "${LOW_COLOR} No attacks detected yet...${NC}" else for attack_type in "${!ATTACK_TYPE_COUNTER[@]}"; do local count="${ATTACK_TYPE_COUNTER[$attack_type]}" local icon=$(get_attack_icon "$attack_type") local color=$(get_attack_color "$attack_type") printf "${color} ${icon} %-20s %5d${NC}\n" "$attack_type" "$count" done | sort -t' ' -k3 -rn | head -5 fi echo -e "${MEDIUM_COLOR}└────────────────────────────────────────────────────────────────────────────┘${NC}" echo "" } draw_live_feed() { echo -e "${HIGH_COLOR}┌─ LIVE THREAT FEED ─────────────────────────────────────────────────────────┐${NC}" if [ -f "$TEMP_DIR/recent_events" ] && [ -s "$TEMP_DIR/recent_events" ]; then tail -n "$MAX_DISPLAY_LINES" "$TEMP_DIR/recent_events" else echo -e "${LOW_COLOR} Waiting for events...${NC}" fi echo -e "${HIGH_COLOR}└────────────────────────────────────────────────────────────────────────────┘${NC}" echo "" } draw_quick_actions() { echo -e "${MEDIUM_COLOR}┌─ QUICK ACTIONS & RECOMMENDATIONS ─────────────────────────────────────────┐${NC}" # Get blockable IPs (score >= 60, not already blocked) local blockable_count=0 local blockable_ips="" local has_ddos=0 local has_ssh_bruteforce=0 local high_conn_count=0 for ip in "${!IP_DATA[@]}"; do IFS='|' read -r score hits bot_type attacks ban_count rep_score <<< "${IP_DATA[$ip]}" # Check attack patterns [[ "$attacks" =~ DDOS ]] && has_ddos=1 [[ "$attacks" =~ BRUTEFORCE ]] && has_ssh_bruteforce=1 # Skip if score too low for blocking [ "$score" -lt 60 ] && continue # Quick check - only verify if CSF/iptables commands available # Don't check on every refresh (too slow) blockable_count=$((blockable_count + 1)) blockable_ips+="$ip " done # Check for high connection counts if [ -f "$TEMP_DIR/recent_events" ]; then high_conn_count=$(grep -c "HIGH_CONN_COUNT" "$TEMP_DIR/recent_events" 2>/dev/null || echo "0") fi # IP Blocking Recommendations if [ $blockable_count -gt 0 ]; then echo -e "${HIGH_COLOR} ⚠️ $blockable_count high-threat IPs ready to block${NC}" echo -e "${MEDIUM_COLOR} → Press 'b' to open blocking menu${NC}" else echo -e "${SAFE_COLOR} ✓ No IPs requiring immediate blocks${NC}" fi # Intelligent Firewall Recommendations local recommendations=0 if [ $has_ddos -eq 1 ] || [ $high_conn_count -gt 0 ]; then echo -e "${HIGH_COLOR} ⚠️ DDoS/SYN Flood Detected - Firewall Protection Recommended${NC}" echo -e "${MEDIUM_COLOR} → Enable SYNFLOOD protection: ${BOLD}csf -e SYNFLOOD${NC}" echo -e "${MEDIUM_COLOR} → Optimize CT_LIMIT: ${BOLD}Press 'c' to run CT_LIMIT optimizer${NC}" echo -e "${MEDIUM_COLOR} → Or manual: ${BOLD}modules/security/optimize-ct-limit.sh${NC}" recommendations=1 fi if [ $has_ssh_bruteforce -eq 1 ]; then local ssh_attacks=$(grep -c "SSH_BRUTEFORCE" "$TEMP_DIR/recent_events" 2>/dev/null || echo "0") if [ $ssh_attacks -gt 5 ]; then echo -e "${HIGH_COLOR} ⚠️ SSH Bruteforce ($ssh_attacks attempts) - Strengthen SSH Security${NC}" echo -e "${MEDIUM_COLOR} → Lower LF_SSHD trigger: ${BOLD}Edit /etc/csf/csf.conf → LF_SSHD=\"3\"${NC}" echo -e "${MEDIUM_COLOR} → Enable PortKnocking or change SSH port${NC}" recommendations=1 fi fi if [ $recommendations -eq 0 ]; then echo "" fi echo -e "${INFO_COLOR} Keys: 'b' Block | 'c' CT_LIMIT | 's' Stats | 'r' Refresh | 'h' Help | 'q' Quit${NC}" echo -e "${MEDIUM_COLOR}└────────────────────────────────────────────────────────────────────────────┘${NC}" } ################################################################################ # Quick Action Menu ################################################################################ show_blocking_menu() { # Pause monitoring local monitoring_paused=1 clear print_banner "Quick IP Blocking" echo "" echo "Select IPs to block (1-hour temporary ban):" echo "" # Build array of blockable IPs local -a blockable_list=() for ip in "${!IP_DATA[@]}"; do IFS='|' read -r score hits bot_type attacks ban_count rep_score <<< "${IP_DATA[$ip]}" # Skip if score too low or already blocked [ "$score" -lt 60 ] && continue is_ip_blocked "$ip" 2>/dev/null && continue blockable_list+=("$ip|$score|$hits|$attacks") done if [ ${#blockable_list[@]} -eq 0 ]; then echo "No IPs meet blocking criteria (score >= 60)" echo "" read -p "Press Enter to continue..." return fi # Check if any IPs to block if [ ${#blockable_list[@]} -eq 0 ]; then echo "" echo -e "${SAFE_COLOR}No IPs meet blocking criteria (score >= 60 and not already blocked)${NC}" echo "" read -p "Press Enter to continue..." return fi # Sort by score IFS=$'\n' blockable_list=($(sort -t'|' -k2 -rn <<<"${blockable_list[*]}")) unset IFS # Display IPs local idx=1 for entry in "${blockable_list[@]}"; do IFS='|' read -r ip score hits attacks <<< "$entry" local level=$(get_threat_level "$score") local color=$(get_threat_color "$level") printf "${color} %2d) %-15s Score:%-3s Hits:%-5s Attacks: %s${NC}\n" \ "$idx" "$ip" "$score" "$hits" "${attacks:-none}" ((idx++)) done echo "" echo -e "${BOLD}Options:${NC}" echo " 1-${#blockable_list[@]}) Block specific IP" echo " a) Block ALL high-threat IPs (score >= 80)" echo " 0) Cancel" echo "" read -p "Select option: " choice if [ "$choice" = "0" ]; then return elif [ "$choice" = "a" ]; then # Block all IPs with score >= 80 local blocked=0 for entry in "${blockable_list[@]}"; do IFS='|' read -r ip score hits attacks <<< "$entry" [ "$score" -lt 80 ] && continue echo "" block_ip_temporary "$ip" 1 "Auto-block: High threat (score $score)" ((blocked++)) done echo "" echo "Blocked $blocked IPs" read -p "Press Enter to continue..." elif [[ "$choice" =~ ^[0-9]+$ ]] && [ "$choice" -ge 1 ] && [ "$choice" -le ${#blockable_list[@]} ]; then # Block specific IP local entry="${blockable_list[$((choice-1))]}" IFS='|' read -r ip score hits attacks <<< "$entry" echo "" block_ip_temporary "$ip" 1 "Manual block from live monitor (score $score)" echo "" read -p "Press Enter to continue..." else echo "Invalid option" read -p "Press Enter to continue..." fi } ################################################################################ # Log Monitoring ################################################################################ monitor_apache_logs() { # Try multiple log locations local log_files=() # Set default if not defined by system-detect.sh local LOG_DIR="${SYS_LOG_DIR:-/var/log/apache2/domlogs}" # Main access log if [ -f "${LOG_DIR}/access_log" ]; then log_files+=("${LOG_DIR}/access_log") elif [ -f "/var/log/httpd/access_log" ]; then log_files+=("/var/log/httpd/access_log") elif [ -f "/var/log/apache2/access.log" ]; then log_files+=("/var/log/apache2/access.log") fi # Domain logs (cPanel domlogs) if [ -d "${LOG_DIR}" ]; then # Find recent domain logs (modified in last hour) while IFS= read -r domain_log; do [ -f "$domain_log" ] && log_files+=("$domain_log") done < <(find "${LOG_DIR}" -type f \( -name "*.com" -o -name "*.net" -o -name "*.org" \) 2>/dev/null | head -5) fi if [ ${#log_files[@]} -eq 0 ]; then echo "ERROR: No accessible Apache log files found" >> "$TEMP_DIR/recent_events" echo "Checked: ${LOG_DIR}, /var/log/httpd, /var/log/apache2" >> "$TEMP_DIR/recent_events" return 1 fi # Monitor all log files local event_count=0 tail -f "${log_files[@]}" 2>/dev/null | while read -r line; do # Increment event counter (update file every 10 events for performance) ((event_count++)) if [ $((event_count % 10)) -eq 0 ]; then echo "$event_count" > "$TEMP_DIR/event_counter" fi # Parse Apache combined log format (supports IPv4 and IPv6) # Note: bytes field can be - or number, so use [0-9-]+ if [[ "$line" =~ ^([0-9a-f.:]+)\ -\ -\ \[([^\]]+)\]\ \"([A-Z]+)\ ([^\"]+)\ [^\"]+\"\ ([0-9]+)\ ([0-9-]+)\ \"[^\"]*\"\ \"([^\"]+)\" ]]; then local ip="${BASH_REMATCH[1]}" local timestamp="${BASH_REMATCH[2]}" local method="${BASH_REMATCH[3]}" local url="${BASH_REMATCH[4]}" local status="${BASH_REMATCH[5]}" local bytes="${BASH_REMATCH[6]}" local user_agent="${BASH_REMATCH[7]}" # Skip local/private IPs and server's own IP if [[ "$ip" =~ ^127\. ]] || \ [[ "$ip" =~ ^10\. ]] || \ [[ "$ip" =~ ^192\.168\. ]] || \ [[ "$ip" =~ ^172\.(1[6-9]|2[0-9]|3[01])\. ]] || \ [[ "$ip" =~ ^169\.254\. ]] || \ [[ "$ip" == "localhost" ]] || \ [[ "$ip" == "::1" ]]; then continue fi # Update intelligence update_ip_intelligence "$ip" "$url" "$user_agent" "$method" # Get updated data local intel=$(get_ip_intelligence "$ip") IFS='|' read -r score hits bot_type attacks ban_count rep_score <<< "$intel" # Determine if this is a threat local level=$(get_threat_level "$score") # Log all traffic with attacks, or score > 0, or suspicious bots # This ensures we see everything interesting, not just high scores if [ "$score" -gt 0 ] || [ -n "$attacks" ] || [ "$bot_type" = "suspicious" ]; then local color=$(get_threat_color "$level") local time_str=$(date +"%H:%M:%S") # Build log line local log_line="${color}[${time_str}] $ip" log_line+=" | Score:$score [$level]" # Show bot type if interesting if [ "$bot_type" = "suspicious" ] || [ "$bot_type" = "ai" ]; then log_line+=" | Bot:$bot_type" fi if [ -n "$attacks" ]; then local first_attack=$(echo "$attacks" | cut -d',' -f1) local icon=$(get_attack_icon "$first_attack") log_line+=" | $icon$first_attack" fi log_line+=" | $url${NC}" echo -e "$log_line" >> "$TEMP_DIR/recent_events" fi fi done & } ################################################################################ # Main Loop ################################################################################ ################################################################################ # SSH Attack Monitoring ################################################################################ monitor_ssh_attacks() { # Monitor SSH brute force attempts from /var/log/secure local secure_log="/var/log/secure" if [ ! -f "$secure_log" ]; then # Try alternative location (Debian/Ubuntu) secure_log="/var/log/auth.log" fi if [ -f "$secure_log" ]; then tail -n 0 -F "$secure_log" 2>/dev/null | while read -r line; do # Detect failed SSH login attempts if echo "$line" | grep -qi "Failed password\|authentication failure\|Invalid user"; then # Extract IP address local ip=$(echo "$line" | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' | head -1) if [ -n "$ip" ]; then # Skip local/private IPs if [[ "$ip" =~ ^127\. ]] || \ [[ "$ip" =~ ^10\. ]] || \ [[ "$ip" =~ ^192\.168\. ]] || \ [[ "$ip" =~ ^172\.(1[6-9]|2[0-9]|3[01])\. ]]; then continue fi # Process as BRUTEFORCE attack local current_data="${IP_DATA[$ip]:-0|0|human||0|0}" IFS='|' read -r score hits bot_type attacks ban_count rep_score <<< "$current_data" # Increment hits hits=$((hits + 1)) # Add BRUTEFORCE to attacks if not already present if [[ ! "$attacks" =~ BRUTEFORCE ]]; then if [ -z "$attacks" ]; then attacks="BRUTEFORCE" else attacks="${attacks},BRUTEFORCE" fi fi # Calculate new score score=$(calculate_attack_score "$attacks") # Update IP_DATA IP_DATA[$ip]="$score|$hits|$bot_type|$attacks|$ban_count|$rep_score" # Log to reputation DB flag_ip_attack "$ip" "BRUTEFORCE" 0 "SSH failed login attempt" >/dev/null 2>&1 & # Log event local time_str=$(date +"%H:%M:%S") local level=$(get_threat_level "$score") local color=$(get_threat_color "$level") local icon=$(get_attack_icon "BRUTEFORCE") echo -e "${color}[${time_str}] $ip | Score:$score [$level] | ${icon}SSH_BRUTEFORCE | Hits:$hits${NC}" >> "$TEMP_DIR/recent_events" fi fi done & fi } ################################################################################ # Firewall Block Monitoring ################################################################################ monitor_firewall_blocks() { # Monitor CSF/iptables blocks in real-time from /var/log/messages local messages_log="/var/log/messages" if [ ! -f "$messages_log" ]; then # Try alternative location messages_log="/var/log/syslog" fi if [ -f "$messages_log" ]; then tail -n 0 -F "$messages_log" 2>/dev/null | while read -r line; do # Detect firewall blocks (CSF, iptables, kernel blocks) if echo "$line" | grep -qiE "Firewall|iptables.*DENY|iptables.*DROP|CSF.*block"; then # Extract IP address local ip=$(echo "$line" | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' | head -1) if [ -n "$ip" ]; then # Skip local/private IPs if [[ "$ip" =~ ^127\. ]] || \ [[ "$ip" =~ ^10\. ]] || \ [[ "$ip" =~ ^192\.168\. ]] || \ [[ "$ip" =~ ^172\.(1[6-9]|2[0-9]|3[01])\. ]]; then continue fi # Log firewall block local time_str=$(date +"%H:%M:%S") echo -e "${LOW_COLOR}[${time_str}] $ip | FIREWALL_BLOCK | Blocked by firewall${NC}" >> "$TEMP_DIR/recent_events" fi fi done & fi } ################################################################################ # cPHulk Monitoring ################################################################################ monitor_cphulk_blocks() { # Monitor cPHulk blocks (cPanel security system) if [ -x "/usr/local/cpanel/bin/cphulk_pam_ctl" ] || command -v whmapi1 &>/dev/null; then ( declare -A SEEN_BLOCKS while true; do # Query cPHulk for blocked IPs whmapi1 cphulkd_list_blocks 2>/dev/null | grep -E "ip:" | while read -r line; do local ip=$(echo "$line" | awk '{print $2}') if [ -n "$ip" ] && [ -z "${SEEN_BLOCKS[$ip]}" ]; then SEEN_BLOCKS[$ip]=1 # Skip local/private IPs if [[ "$ip" =~ ^127\. ]] || \ [[ "$ip" =~ ^10\. ]] || \ [[ "$ip" =~ ^192\.168\. ]] || \ [[ "$ip" =~ ^172\.(1[6-9]|2[0-9]|3[01])\. ]]; then continue fi # Process as BRUTEFORCE attack (cPHulk blocks login attempts) local current_data="${IP_DATA[$ip]:-0|0|human||0|0}" IFS='|' read -r score hits bot_type attacks ban_count rep_score <<< "$current_data" # Add BRUTEFORCE to attacks if [[ ! "$attacks" =~ BRUTEFORCE ]]; then if [ -z "$attacks" ]; then attacks="BRUTEFORCE" else attacks="${attacks},BRUTEFORCE" fi fi # Calculate score score=$(calculate_attack_score "$attacks") hits=$((hits + 1)) # Update IP_DATA IP_DATA[$ip]="$score|$hits|$bot_type|$attacks|$ban_count|$rep_score" # Log event local time_str=$(date +"%H:%M:%S") local level=$(get_threat_level "$score") local color=$(get_threat_color "$level") echo -e "${color}[${time_str}] $ip | Score:$score [$level] | 🔐CPHULK_BLOCK | Blocked by cPHulk${NC}" >> "$TEMP_DIR/recent_events" fi done sleep 10 # Poll every 10 seconds done ) & fi } ################################################################################ # Network Attack Monitoring (SYN floods, port scans, DDoS) ################################################################################ monitor_network_attacks() { # Monitor kernel logs and network statistics for SYN floods, port scans, etc. local kern_log="/var/log/kern.log" # Try different log locations if [ ! -f "$kern_log" ]; then kern_log="/var/log/messages" fi # Monitor kernel/firewall logs for network attacks if [ -f "$kern_log" ]; then tail -n 0 -F "$kern_log" 2>/dev/null | while read -r line; do # Detect SYN flood patterns if echo "$line" | grep -qiE "SYN flood|possible SYN flooding|TCP: Possible SYN flooding"; then local ip=$(echo "$line" | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' | head -1) if [ -n "$ip" ]; then # Skip local/private IPs if [[ "$ip" =~ ^127\. ]] || \ [[ "$ip" =~ ^10\. ]] || \ [[ "$ip" =~ ^192\.168\. ]] || \ [[ "$ip" =~ ^172\.(1[6-9]|2[0-9]|3[01])\. ]]; then continue fi # Process as DDOS attack local current_data="${IP_DATA[$ip]:-0|0|human||0|0}" IFS='|' read -r score hits bot_type attacks ban_count rep_score <<< "$current_data" # Add DDOS to attacks if [[ ! "$attacks" =~ DDOS ]]; then if [ -z "$attacks" ]; then attacks="DDOS" else attacks="${attacks},DDOS" fi fi # Calculate score (DDOS is high severity) score=$(calculate_attack_score "$attacks") hits=$((hits + 1)) # Update IP_DATA IP_DATA[$ip]="$score|$hits|$bot_type|$attacks|$ban_count|$rep_score" # Log to reputation DB flag_ip_attack "$ip" "DDOS" 0 "SYN flood detected" >/dev/null 2>&1 & # Log event local time_str=$(date +"%H:%M:%S") local level=$(get_threat_level "$score") local color=$(get_threat_color "$level") echo -e "${color}[${time_str}] $ip | Score:$score [$level] | 💥SYN_FLOOD | Network attack${NC}" >> "$TEMP_DIR/recent_events" fi fi # Detect port scan attempts if echo "$line" | grep -qiE "port.*scan|stealth scan|SYN-FIN scan|NULL scan"; then local ip=$(echo "$line" | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' | head -1) if [ -n "$ip" ]; then # Skip local/private IPs if [[ "$ip" =~ ^127\. ]] || \ [[ "$ip" =~ ^10\. ]] || \ [[ "$ip" =~ ^192\.168\. ]] || \ [[ "$ip" =~ ^172\.(1[6-9]|2[0-9]|3[01])\. ]]; then continue fi # Process as SCANNER attack local current_data="${IP_DATA[$ip]:-0|0|human||0|0}" IFS='|' read -r score hits bot_type attacks ban_count rep_score <<< "$current_data" # Add PORT_SCAN to attacks (using ADMIN_PROBE for now - 5 points) if [[ ! "$attacks" =~ ADMIN_PROBE ]]; then if [ -z "$attacks" ]; then attacks="ADMIN_PROBE" else attacks="${attacks},ADMIN_PROBE" fi fi # Calculate score score=$(calculate_attack_score "$attacks") hits=$((hits + 1)) # Update IP_DATA IP_DATA[$ip]="$score|$hits|$bot_type|$attacks|$ban_count|$rep_score" # Log event local time_str=$(date +"%H:%M:%S") local level=$(get_threat_level "$score") local color=$(get_threat_color "$level") echo -e "${color}[${time_str}] $ip | Score:$score [$level] | 🔎PORT_SCAN | Network reconnaissance${NC}" >> "$TEMP_DIR/recent_events" fi fi done & fi # Monitor netstat for high connection counts (possible DDoS) if command -v netstat &>/dev/null || command -v ss &>/dev/null; then ( declare -A CONNECTION_COUNT declare -A ALERT_SENT while true; do # Use ss if available (faster), otherwise netstat if command -v ss &>/dev/null; then # Count SYN_RECV connections per IP (sign of SYN flood) while read -r ip count; do if [ "$count" -gt 20 ]; then # More than 20 SYN_RECV connections if [ -z "${ALERT_SENT[$ip]}" ]; then ALERT_SENT[$ip]=1 # Skip local/private IPs if [[ "$ip" =~ ^127\. ]] || \ [[ "$ip" =~ ^10\. ]] || \ [[ "$ip" =~ ^192\.168\. ]] || \ [[ "$ip" =~ ^172\.(1[6-9]|2[0-9]|3[01])\. ]]; then continue fi # Log high connection count local time_str=$(date +"%H:%M:%S") echo -e "${HIGH_COLOR}[${time_str}] $ip | 💥HIGH_CONN_COUNT | $count SYN_RECV connections (possible DDoS)${NC}" >> "$TEMP_DIR/recent_events" fi else # Reset alert if connections drop unset ALERT_SENT[$ip] fi done < <(ss -tn state syn-recv 2>/dev/null | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' | sort | uniq -c | awk '$1 > 5 {print $2, $1}') fi sleep 15 # Check every 15 seconds done ) & fi } ################################################################################ # Email/SMTP Attack Monitoring ################################################################################ monitor_email_attacks() { # Monitor mail logs for SMTP/IMAP/POP3 bruteforce local mail_log="/var/log/maillog" if [ ! -f "$mail_log" ]; then mail_log="/var/log/mail.log" fi if [ -f "$mail_log" ]; then tail -n 0 -F "$mail_log" 2>/dev/null | while read -r line; do # Dovecot authentication failures if echo "$line" | grep -qiE "auth.*failed|authentication failed|password mismatch"; then local ip=$(echo "$line" | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' | head -1) if [ -n "$ip" ]; then # Skip local/private IPs [[ "$ip" =~ ^127\. ]] || [[ "$ip" =~ ^10\. ]] || [[ "$ip" =~ ^192\.168\. ]] || [[ "$ip" =~ ^172\.(1[6-9]|2[0-9]|3[01])\. ]] && continue # Process as BRUTEFORCE attack local current_data="${IP_DATA[$ip]:-0|0|human||0|0}" IFS='|' read -r score hits bot_type attacks ban_count rep_score <<< "$current_data" hits=$((hits + 1)) # Add BRUTEFORCE to attacks if [[ ! "$attacks" =~ BRUTEFORCE ]]; then [ -z "$attacks" ] && attacks="BRUTEFORCE" || attacks="${attacks},BRUTEFORCE" fi score=$(calculate_attack_score "$attacks") IP_DATA[$ip]="$score|$hits|$bot_type|$attacks|$ban_count|$rep_score" # Log to reputation DB flag_ip_attack "$ip" "BRUTEFORCE" 0 "Email authentication failure" >/dev/null 2>&1 & # Log event local time_str=$(date +"%H:%M:%S") local level=$(get_threat_level "$score") local color=$(get_threat_color "$level") echo -e "${color}[${time_str}] $ip | Score:$score [$level] | 📧EMAIL_BRUTEFORCE | Hits:$hits${NC}" >> "$TEMP_DIR/recent_events" fi fi done & fi } ################################################################################ # FTP Attack Monitoring ################################################################################ monitor_ftp_attacks() { # Monitor FTP logs for bruteforce attempts local ftp_log="/var/log/vsftpd.log" if [ ! -f "$ftp_log" ]; then ftp_log="/var/log/xferlog" fi if [ -f "$ftp_log" ]; then tail -n 0 -F "$ftp_log" 2>/dev/null | while read -r line; do # FTP authentication failures if echo "$line" | grep -qiE "FAIL LOGIN|authentication failed|530 Login incorrect"; then local ip=$(echo "$line" | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' | head -1) if [ -n "$ip" ]; then # Skip local/private IPs [[ "$ip" =~ ^127\. ]] || [[ "$ip" =~ ^10\. ]] || [[ "$ip" =~ ^192\.168\. ]] || [[ "$ip" =~ ^172\.(1[6-9]|2[0-9]|3[01])\. ]] && continue # Process as BRUTEFORCE attack local current_data="${IP_DATA[$ip]:-0|0|human||0|0}" IFS='|' read -r score hits bot_type attacks ban_count rep_score <<< "$current_data" hits=$((hits + 1)) # Add BRUTEFORCE to attacks if [[ ! "$attacks" =~ BRUTEFORCE ]]; then [ -z "$attacks" ] && attacks="BRUTEFORCE" || attacks="${attacks},BRUTEFORCE" fi score=$(calculate_attack_score "$attacks") IP_DATA[$ip]="$score|$hits|$bot_type|$attacks|$ban_count|$rep_score" # Log to reputation DB flag_ip_attack "$ip" "BRUTEFORCE" 0 "FTP login failure" >/dev/null 2>&1 & # Log event local time_str=$(date +"%H:%M:%S") local level=$(get_threat_level "$score") local color=$(get_threat_color "$level") echo -e "${color}[${time_str}] $ip | Score:$score [$level] | 📁FTP_BRUTEFORCE | Hits:$hits${NC}" >> "$TEMP_DIR/recent_events" fi fi done & fi } ################################################################################ # Database Attack Monitoring ################################################################################ monitor_database_attacks() { # Monitor MySQL logs for authentication failures local mysql_log="/var/log/mysqld.log" if [ ! -f "$mysql_log" ]; then mysql_log="/var/log/mysql/error.log" fi if [ -f "$mysql_log" ]; then tail -n 0 -F "$mysql_log" 2>/dev/null | while read -r line; do # MySQL authentication failures if echo "$line" | grep -qiE "Access denied for user|Failed password for"; then local ip=$(echo "$line" | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' | head -1) if [ -n "$ip" ]; then # Skip local/private IPs [[ "$ip" =~ ^127\. ]] || [[ "$ip" =~ ^10\. ]] || [[ "$ip" =~ ^192\.168\. ]] || [[ "$ip" =~ ^172\.(1[6-9]|2[0-9]|3[01])\. ]] && continue # Process as SQL_INJECTION attack (database level) local current_data="${IP_DATA[$ip]:-0|0|human||0|0}" IFS='|' read -r score hits bot_type attacks ban_count rep_score <<< "$current_data" hits=$((hits + 1)) # Add SQL_INJECTION to attacks if [[ ! "$attacks" =~ SQL_INJECTION ]]; then [ -z "$attacks" ] && attacks="SQL_INJECTION" || attacks="${attacks},SQL_INJECTION" fi score=$(calculate_attack_score "$attacks") IP_DATA[$ip]="$score|$hits|$bot_type|$attacks|$ban_count|$rep_score" # Log to reputation DB flag_ip_attack "$ip" "SQL_INJECTION" 0 "MySQL authentication failure" >/dev/null 2>&1 & # Log event local time_str=$(date +"%H:%M:%S") local level=$(get_threat_level "$score") local color=$(get_threat_color "$level") echo -e "${color}[${time_str}] $ip | Score:$score [$level] | 🗄️ DB_BRUTEFORCE | Hits:$hits${NC}" >> "$TEMP_DIR/recent_events" fi fi done & fi } ################################################################################ # Distributed Attack Detection ################################################################################ detect_distributed_attacks() { # Run in background, check every 30 seconds ( while true; do sleep 30 # Look for same attack pattern from multiple IPs in short time if [ -f "$TEMP_DIR/recent_events" ]; then # Get recent attacks (last 2 minutes) local recent=$(tail -200 "$TEMP_DIR/recent_events" 2>/dev/null) # Check for same attack type from 5+ different IPs for attack_type in RCE SQL_INJECTION XSS PATH_TRAVERSAL BRUTEFORCE; do local attack_count=$(echo "$recent" | grep -c "$attack_type") if [ "$attack_count" -ge 5 ]; then local unique_ips=$(echo "$recent" | grep "$attack_type" | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' | sort -u | wc -l) 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" # Mark in a file for Quick Actions to see echo "${attack_type}|${unique_ips}|$(date +%s)" >> "$TEMP_DIR/distributed_attacks" fi fi done fi done ) & } ################################################################################ # Automatic Mitigation Engine ################################################################################ auto_mitigation_engine() { # Run in background, check every 10 seconds ( while true; do sleep 10 # Auto-block IPs that reach CRITICAL threshold for ip in "${!IP_DATA[@]}"; do IFS='|' read -r score hits bot_type attacks ban_count rep_score <<< "${IP_DATA[$ip]}" # Auto-block at score >= 80 (CRITICAL) if [ "$score" -ge 80 ]; then # Check if already blocked if ! is_ip_blocked "$ip" 2>/dev/null; then # Auto-block local time_str=$(date +"%H:%M:%S") echo -e "${CRITICAL_COLOR}[${time_str}] AUTO_BLOCK | $ip | Score:$score | ${attacks}${NC}" >> "$TEMP_DIR/recent_events" # Block for 1 hour block_ip_temporary "$ip" 1 "Auto-block: Critical threat score $score - ${attacks}" >/dev/null 2>&1 & # Update ban count ban_count=$((ban_count + 1)) IP_DATA[$ip]="$score|$hits|$bot_type|$attacks|$ban_count|$rep_score" fi fi done done ) & } # Start all log monitoring sources monitor_apache_logs monitor_ssh_attacks monitor_email_attacks monitor_ftp_attacks monitor_database_attacks monitor_firewall_blocks monitor_cphulk_blocks monitor_network_attacks # Start intelligence engines detect_distributed_attacks auto_mitigation_engine # Periodic snapshot saving in background ( while true; do sleep 300 # Save every 5 minutes save_snapshot done ) & # Main dashboard loop LOOP_COUNT=0 while true; do draw_header draw_intelligence_panel draw_attack_breakdown draw_live_feed draw_quick_actions # Periodic cleanup (every 50 loops = ~100 seconds) ((LOOP_COUNT++)) if [ $((LOOP_COUNT % 50)) -eq 0 ]; then # Trim event log to last 1000 lines if [ -f "$TEMP_DIR/recent_events" ]; then tail -1000 "$TEMP_DIR/recent_events" > "$TEMP_DIR/recent_events.tmp" 2>/dev/null mv "$TEMP_DIR/recent_events.tmp" "$TEMP_DIR/recent_events" 2>/dev/null fi fi # Non-blocking input with timeout read -t $REFRESH_INTERVAL -n 1 key case "$key" in b|B) show_blocking_menu ;; c|C) # Run CT_LIMIT optimizer clear "$SCRIPT_DIR/modules/security/optimize-ct-limit.sh" read -p "Press Enter to return to monitor..." ;; i|I) # Show threat intelligence for specific IP clear print_banner "Threat Intelligence Lookup" echo "" read -p "Enter IP address: " lookup_ip if [ -n "$lookup_ip" ]; then echo "" echo "Querying threat intelligence for $lookup_ip..." echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" local threat_intel=$(get_threat_intelligence "$lookup_ip") IFS='|' read -r abuse_conf abuse_rpts country isp geo timing whitelisted <<< "$threat_intel" echo "" echo "${BOLD}Threat Intelligence:${NC}" echo " AbuseIPDB Confidence: ${abuse_conf}%" echo " Total Abuse Reports: $abuse_rpts" echo " Country: ${geo:-$country}" echo " ISP: $isp" echo " Timing Pattern: $timing" echo " Whitelisted: $whitelisted" echo "" if is_high_risk_country "${geo:-XX}"; then echo -e "${HIGH_COLOR} ⚠️ HIGH RISK COUNTRY${NC}" fi if [ "${abuse_conf:-0}" -ge 75 ]; then echo -e "${CRITICAL_COLOR} 🚨 HIGH CONFIDENCE MALICIOUS${NC}" elif [ "${abuse_conf:-0}" -ge 50 ]; then echo -e "${HIGH_COLOR} ⚠️ MEDIUM CONFIDENCE THREAT${NC}" fi echo "" read -p "Generate full incident report? (y/n): " gen_report if [[ "$gen_report" =~ ^[Yy]$ ]]; then local report_file=$(generate_incident_report "$lookup_ip") echo "" echo "Report generated: $report_file" echo "" echo "View report? (y/n): " read -n 1 view_report if [[ "$view_report" =~ ^[Yy]$ ]]; then less "$report_file" fi fi fi echo "" read -p "Press Enter to return to monitor..." ;; p|P) # Show performance impact clear print_banner "Server Performance Monitor" echo "" local load_data=$(get_server_load) IFS='|' read -r load1 load5 load15 cpu_count <<< "$load_data" echo "${BOLD}Current Load:${NC}" echo " 1 min: $load1" echo " 5 min: $load5" echo " 15 min: $load15" echo " CPU cores: $cpu_count" echo "" if is_server_stressed; then echo -e "${CRITICAL_COLOR} 🔥 SERVER UNDER STRESS${NC}" echo "" echo " Recommended Actions:" echo " • Enable aggressive auto-blocking (higher threshold)" echo " • Reduce CT_LIMIT temporarily" echo " • Block high-volume attack IPs immediately" else echo -e "${SAFE_COLOR} ✓ Server load normal${NC}" fi echo "" read -p "Press Enter to return to monitor..." ;; q|Q) cleanup ;; r|R) # Force refresh continue ;; s|S) # Show stats clear show_ip_reputation_stats read -p "Press Enter to continue..." ;; h|H|\?) # Show help clear print_banner "Keyboard Controls" echo "" echo "Available Commands:" echo " ${BOLD}b${NC} - Open IP blocking menu (batch or individual)" echo " ${BOLD}c${NC} - Run CT_LIMIT optimizer (analyze traffic & recommend limit)" echo " ${BOLD}i${NC} - Threat intelligence lookup (AbuseIPDB, geo, incident reports)" echo " ${BOLD}p${NC} - Show performance impact monitor (server load)" echo " ${BOLD}s${NC} - Show IP reputation database statistics" echo " ${BOLD}r${NC} - Force refresh display" echo " ${BOLD}h${NC} - Show this help screen" echo " ${BOLD}q${NC} - Quit and save snapshot" echo "" echo "Features:" echo " • Real-time bot classification (legit/AI/monitor/suspicious)" echo " • Attack vector detection (SQL, XSS, RCE, etc.)" echo " • Threat scoring (0-100 scale)" echo " • Threat intelligence integration (AbuseIPDB, geolocation)" echo " • Attack pattern learning & behavioral analysis" echo " • Automated incident report generation" echo " • Smart whitelisting (CDNs, search engines)" echo " • IP reputation DB integration" echo " • CSF/iptables temporary bans (1 hour default)" echo " • Auto-mitigation at critical threshold (score ≥80)" echo " • Memory protection (max ${MAX_TRACKED_IPS} IPs tracked)" echo " • Auto-save every 5 minutes + on exit" echo "" read -p "Press Enter to continue..." ;; esac done