#!/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" # 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)) # Classify bot if unknown if [ "$bot_type" = "unknown" ] && [ -n "$user_agent" ]; then bot_type=$(classify_bot_type "$user_agent") 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 ────────────────────────────────────────────────────────────┐${NC}" # Get blockable IPs (score >= 60, not already blocked) local blockable_count=0 local blockable_ips="" 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 [ "$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 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 immediate threats requiring blocks${NC}" fi echo -e "${INFO_COLOR} Press 'b' to block IPs | 'h' for help | 'q' to 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 ################################################################################ # Start log monitoring monitor_apache_logs # 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 ;; 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}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 " • IP reputation DB integration" echo " • CSF/iptables temporary bans (1 hour default)" 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