3e97dd86d9
Created new threat intelligence library with extensive monitoring capabilities: Threat Intelligence Integration: - AbuseIPDB API integration with caching (24hr TTL) - Geolocation detection via geoiplookup/whois - High-risk country identification - ISP and country-based risk scoring Smart Whitelisting: - Automatic detection of legitimate services (Google, Cloudflare, Microsoft, Akamai) - CDN IP range recognition - Configurable whitelist management Behavioral Analysis: - Request timing pattern analysis (human vs bot detection) - Attack pattern learning and recording - Pattern matching for repeat attackers Performance Monitoring: - Server load tracking integration - Stress detection for adaptive mitigation - CPU and load average monitoring Incident Response: - Automated incident report generation - Comprehensive threat intelligence summaries - Attack history tracking - Recommended action suggestions Multi-Server Coordination: - Shared threat data logging - Cross-server attack correlation preparation Live Monitor Integration: - Auto-enrichment on first IP encounter - AbuseIPDB confidence scoring boost (30pts for 75%+, 15pts for 50%+) - High-risk country detection adds 5pts - Attack pattern recording for learning - New keyboard commands: i) Threat intelligence lookup with incident reports p) Performance impact monitor All features use existing system tools only (no new services installed)
1426 lines
55 KiB
Bash
Executable File
1426 lines
55 KiB
Bash
Executable File
#!/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
|