#!/bin/bash ################################################################################ # Malware Scanner ################################################################################ # Purpose: Comprehensive malware scanning with multiple engines # Supports: ImunifyAV, ClamAV, Maldet (LMD) # Scan scope: Single domain, user account, or entire server ################################################################################ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" source "$SCRIPT_DIR/lib/common-functions.sh" 2>/dev/null || true source "$SCRIPT_DIR/lib/system-detect.sh" 2>/dev/null || true source "$SCRIPT_DIR/lib/user-manager.sh" 2>/dev/null || true # Arrays for docroots and scanners declare -a docroot_array declare -a sanitized_docroot declare -a remove_docroot declare -a available_scanners # Scanner detection detect_scanners() { available_scanners=() if command -v imunify-antivirus &>/dev/null; then available_scanners+=("imunify") fi if command -v clamscan &>/dev/null; then available_scanners+=("clamav") fi if command -v maldet &>/dev/null; then available_scanners+=("maldet") fi if [ ${#available_scanners[@]} -eq 0 ]; then echo -e "${RED}No malware scanners detected!${NC}" echo "" show_scanner_installation_guide return 1 fi return 0 } # Show installation instructions for missing scanners show_scanner_installation_guide() { echo -e "${YELLOW}Available Malware Scanners:${NC}" echo "" # Check ImunifyAV if ! command -v imunify-antivirus &>/dev/null; then echo -e "${CYAN}ImunifyAV${NC} - Commercial real-time protection" echo " Status: Not installed" echo " Installation:" echo " wget https://repo.imunify360.cloudlinux.com/defence360/imav-deploy.sh" echo " bash imav-deploy.sh" echo " Docs: https://docs.imunify360.com/" echo "" else echo -e "${GREEN}✓ ImunifyAV${NC} - Installed" echo "" fi # Check ClamAV if ! command -v clamscan &>/dev/null; then echo -e "${CYAN}ClamAV${NC} - Open source antivirus engine" echo " Status: Not installed" echo " Installation (cPanel):" echo " /scripts/update_local_rpm_versions --edit target_settings.clamav installed" echo " /scripts/check_cpanel_rpms --fix --targets=clamav" echo " Installation (manual):" echo " yum install clamav clamav-update # RHEL/CentOS" echo " apt-get install clamav clamav-daemon # Debian/Ubuntu" echo " freshclam # Update virus definitions" echo "" else echo -e "${GREEN}✓ ClamAV${NC} - Installed" echo "" fi # Check Maldet if ! command -v maldet &>/dev/null; then echo -e "${CYAN}Maldet (LMD)${NC} - Linux Malware Detect" echo " Status: Not installed" echo " Installation:" echo " cd /tmp" echo " wget http://www.rfxn.com/downloads/maldetect-current.tar.gz" echo " tar -xzf maldetect-current.tar.gz" echo " cd maldetect-*" echo " ./install.sh" echo " Docs: https://www.rfxn.com/projects/linux-malware-detect/" echo "" else echo -e "${GREEN}✓ Maldet${NC} - Installed" echo "" fi echo -e "${YELLOW}Recommendation:${NC} Install at least ClamAV (free) for basic scanning" echo "" } # Detect control panel and gather docroots detect_control_panel() { docroot_array=() # Detect cPanel if [ -f "/etc/userdatadomains" ]; then CONTROL_PANEL="cpanel" export PATH=/usr/local/cpanel/3rdparty/bin/:$PATH while IFS= read -r docroot; do [ -n "$docroot" ] && docroot_array+=("$docroot") done < <(cut -d= -f5 /etc/userdatadomains | sed 's/==/=/g' | sort -u) # Detect Plesk elif [ -f "/usr/local/psa/version" ]; then CONTROL_PANEL="plesk" while IFS= read -r domain; do docroot=$(plesk bin site -i "$domain" 2>/dev/null | grep "WWW-Root" | awk '{print $2}') [ -n "$docroot" ] && docroot_array+=("$docroot") done < <(plesk bin site --list 2>/dev/null) # Detect Interworx elif [ -d "/usr/local/interworx/" ]; then CONTROL_PANEL="interworx" while IFS= read -r docroot; do [ -n "$docroot" ] && docroot_array+=("$docroot") done < <(grep -rh "DocumentRoot" /etc/httpd/conf* 2>/dev/null | grep -Ev '^\s*#|/var/www/html($|$)' | sed 's/DocumentRoot//g' | tr -d " " | sort -u) else CONTROL_PANEL="none" echo -e "${YELLOW}No control panel detected${NC}" echo "Manual path selection required" return 1 fi # Remove subdirectory docroots (avoid scanning same files twice) sanitize_docroots return 0 } # Remove subdirectory docroots from array sanitize_docroots() { remove_docroot=() for search_value in "${docroot_array[@]}"; do # Count how many paths contain this value count=$(printf '%s\n' "${docroot_array[@]}" | grep -c "$search_value" || true) if [ "$count" -gt 1 ]; then # Find subdirectories and mark for removal while IFS= read -r subdir; do if [ "$subdir" != "$search_value" ]; then remove_docroot+=("$subdir") fi done < <(printf '%s\n' "${docroot_array[@]}" | grep "$search_value") fi done # Build sanitized array sanitized_docroot=() for docroot in "${docroot_array[@]}"; do # Check if this docroot is in remove list skip=0 for remove in "${remove_docroot[@]}"; do if [ "$docroot" = "$remove" ]; then skip=1 break fi done if [ $skip -eq 0 ]; then sanitized_docroot+=("$docroot") fi done } # Get docroots for specific user get_user_docroots() { local username="$1" local user_docroots=() if [ "$CONTROL_PANEL" = "cpanel" ]; then while IFS= read -r docroot; do [ -n "$docroot" ] && user_docroots+=("$docroot") done < <(grep "^${username}:" /etc/userdatadomains | cut -d= -f5 | sed 's/==/=/g' | sort -u) else echo -e "${RED}User-specific scanning only supported on cPanel${NC}" return 1 fi echo "${user_docroots[@]}" } # Get docroot for specific domain get_domain_docroot() { local domain="$1" local domain_docroot="" if [ "$CONTROL_PANEL" = "cpanel" ]; then domain_docroot=$(grep "^${domain}:" /etc/userdatadomains | cut -d= -f5 | sed 's/==/=/g') elif [ "$CONTROL_PANEL" = "plesk" ]; then domain_docroot=$(plesk bin site -i "$domain" 2>/dev/null | grep "WWW-Root" | awk '{print $2}') else echo -e "${RED}Domain lookup only supported on cPanel/Plesk${NC}" return 1 fi echo "$domain_docroot" } # Memory check before scanning check_memory() { local total_mem=$(free -m | awk '/^Mem:/{print $2}') local avail_mem=$(free -m | awk '/^Mem:/{print $7}') local min_total=2048 # 2GB local min_avail=512 # 512MB if [ "$total_mem" -lt "$min_total" ] || [ "$avail_mem" -lt "$min_avail" ]; then echo -e "${YELLOW}WARNING: Low memory detected${NC}" echo "Total: ${total_mem}MB | Available: ${avail_mem}MB" echo "" echo "Running a full scan may cause high load or OOM conditions." echo "" read -p "Continue anyway? (yes/no): " confirm if [ "$confirm" != "yes" ]; then echo "Scan cancelled" return 1 fi fi return 0 } # ImunifyAV scanner scan_imunify() { local scan_paths=("$@") if ! command -v imunify-antivirus &>/dev/null; then echo -e "${RED}ImunifyAV not installed${NC}" return 1 fi echo -e "${CYAN}Starting ImunifyAV scan...${NC}" echo "" # Update signatures echo "→ Updating signatures..." imunify-antivirus update 2>/dev/null # Queue scan paths for path in "${scan_paths[@]}"; do if [ -d "$path" ]; then echo "→ Queuing: $path" imunify-antivirus malware on-demand queue put "$path" 2>/dev/null fi done echo "" echo -e "${GREEN}✓ Scan queued${NC}" echo "" echo "Monitor progress:" echo " imunify-antivirus malware on-demand list" } # ClamAV scanner scan_clamav() { local scan_paths=("$@") if ! command -v clamscan &>/dev/null; then echo -e "${RED}ClamAV not installed${NC}" return 1 fi # Create log directory local log_dir="$SCRIPT_DIR/logs/malware-scans" mkdir -p "$log_dir" local log_file="$log_dir/clamav_$(date +%Y%m%d_%H%M%S).log" echo -e "${CYAN}Starting ClamAV scan...${NC}" echo "" # Update signatures if command -v freshclam &>/dev/null; then echo "→ Updating signatures..." freshclam 2>/dev/null || true fi echo "→ Scanning paths..." echo "" # Log scan details { echo "ClamAV Malware Scan" echo "Date: $(date)" echo "Paths:" printf '%s\n' "${scan_paths[@]}" echo "" echo "Results:" echo "========================================" } > "$log_file" # Run scan clamscan --infected --recursive "${scan_paths[@]}" >> "$log_file" 2>&1 & local scan_pid=$! echo "Scan running in background (PID: $scan_pid)" echo "Log file: $log_file" echo "" echo "Monitor with: tail -f $log_file" # Store scan info in reference DB store_reference "malware_scan_clamav_latest" "$log_file" } # Maldet scanner scan_maldet() { local scan_paths=("$@") if ! command -v maldet &>/dev/null; then echo -e "${RED}Maldet not installed${NC}" return 1 fi # Create temp file with paths local path_file="/tmp/maldet_paths_$$.txt" printf '%s\n' "${scan_paths[@]}" > "$path_file" echo -e "${CYAN}Starting Maldet scan...${NC}" echo "" # Update signatures echo "→ Updating signatures..." maldet -u 2>/dev/null || true echo "→ Starting scan..." maldet -b -f "$path_file" rm -f "$path_file" echo "" echo "View results:" echo " maldet -l" } # Run all available scanners sequentially run_all_scanners() { local scan_paths=("$@") if [ ${#scan_paths[@]} -eq 0 ]; then echo -e "${RED}No paths to scan${NC}" return 1 fi # Create session ID for this multi-scanner run local session_id="multiscan_$(date +%Y%m%d_%H%M%S)" local report_file="$SCRIPT_DIR/logs/malware-scans/${session_id}_summary.txt" mkdir -p "$SCRIPT_DIR/logs/malware-scans" echo "" print_header "Multi-Scanner Session: $session_id" echo "Running ${#available_scanners[@]} scanner(s) on ${#scan_paths[@]} path(s)" echo "Session report: $report_file" echo "" # Initialize report { echo "==========================================" echo "Multi-Scanner Malware Detection Report" echo "==========================================" echo "Session ID: $session_id" echo "Date: $(date)" echo "Scanners: ${available_scanners[*]}" echo "Paths: ${#scan_paths[@]}" echo "" printf '%s\n' "${scan_paths[@]}" echo "" echo "==========================================" echo "" } > "$report_file" local scanner_num=1 local total_scanners=${#available_scanners[@]} # Run each scanner for scanner in "${available_scanners[@]}"; do echo -e "${CYAN}[$scanner_num/$total_scanners] Starting ${scanner^} scan...${NC}" echo "" { echo "Scanner: ${scanner^}" echo "Started: $(date)" echo "---" } >> "$report_file" case "$scanner" in imunify) scan_imunify "${scan_paths[@]}" | tee -a "$report_file" ;; clamav) scan_clamav "${scan_paths[@]}" | tee -a "$report_file" ;; maldet) scan_maldet "${scan_paths[@]}" | tee -a "$report_file" ;; esac echo "" | tee -a "$report_file" echo "---" >> "$report_file" echo "" >> "$report_file" ((scanner_num++)) # Wait a moment between scanners if [ $scanner_num -le $total_scanners ]; then echo "" echo "Waiting 3 seconds before next scanner..." sleep 3 echo "" fi done # Finalize report { echo "==========================================" echo "Multi-Scanner Session Complete" echo "Completed: $(date)" echo "==========================================" } >> "$report_file" echo "" echo -e "${GREEN}✓ All scanners completed${NC}" echo "" echo "Session report saved: $report_file" echo "" echo "View individual scanner results using option 5 from main menu" # Store in reference database store_reference "malware_multiscan_latest" "$session_id" store_reference "malware_multiscan_${session_id}" "$report_file" echo "" read -p "Press Enter to continue..." } # Generate standalone malware scan script generate_standalone_scanner() { local scan_paths=("$@") if [ ${#scan_paths[@]} -eq 0 ]; then echo -e "${RED}No paths to scan${NC}" return 1 fi # Create session ID and directory local session_id="malware-$(date +%Y%m%d-%H%M%S)" local session_dir="/opt/${session_id}" echo "" print_header "Generating Standalone Scanner" echo "Session ID: $session_id" echo "Location: $session_dir" echo "" # Create directory structure mkdir -p "$session_dir"/{logs,results} # Create standalone scan script cat > "$session_dir/scan.sh" << 'STANDALONE_EOF' #!/bin/bash ################################################################################ # Standalone Malware Scanner ################################################################################ # Auto-generated by Server Management Toolkit # This script is self-contained and can run independently ################################################################################ # Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' CYAN='\033[0;36m' NC='\033[0m' # Get script directory SCAN_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" LOG_DIR="$SCAN_DIR/logs" RESULTS_DIR="$SCAN_DIR/results" # Session info SESSION_LOG="$LOG_DIR/session.log" SUMMARY_FILE="$RESULTS_DIR/summary.txt" INFECTED_LIST="$RESULTS_DIR/infected_files.txt" # Logging function log_message() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$SESSION_LOG" } # Banner clear echo "========================================" echo "Standalone Malware Scanner" echo "========================================" echo "Session: $(basename $SCAN_DIR)" echo "Started: $(date)" echo "========================================" echo "" log_message "Scan session started" # Detect available scanners AVAILABLE_SCANNERS=() if command -v imunify-antivirus &>/dev/null; then AVAILABLE_SCANNERS+=("imunify") log_message "Detected: ImunifyAV" fi if command -v clamscan &>/dev/null; then AVAILABLE_SCANNERS+=("clamav") log_message "Detected: ClamAV" fi if command -v maldet &>/dev/null; then AVAILABLE_SCANNERS+=("maldet") log_message "Detected: Maldet" fi if [ ${#AVAILABLE_SCANNERS[@]} -eq 0 ]; then log_message "ERROR: No scanners found!" echo -e "${RED}No malware scanners detected!${NC}" exit 1 fi log_message "Found ${#AVAILABLE_SCANNERS[@]} scanner(s): ${AVAILABLE_SCANNERS[*]}" # Scan paths (will be replaced) SCAN_PATHS=() PLACEHOLDER_SCAN_PATHS log_message "Scanning ${#SCAN_PATHS[@]} path(s)" # Initialize summary { echo "==========================================" echo "Malware Scan Summary Report" echo "==========================================" echo "Session: $(basename $SCAN_DIR)" echo "Started: $(date)" echo "Scanners: ${AVAILABLE_SCANNERS[*]}" echo "Paths: ${#SCAN_PATHS[@]}" echo "" printf '%s\n' "${SCAN_PATHS[@]}" echo "" echo "==========================================" echo "" } > "$SUMMARY_FILE" # Track completion SCANNERS_COMPLETED=0 TOTAL_SCANNERS=${#AVAILABLE_SCANNERS[@]} # Run each scanner for scanner in "${AVAILABLE_SCANNERS[@]}"; do SCANNER_NUM=$((SCANNERS_COMPLETED + 1)) echo "" echo -e "${CYAN}[$SCANNER_NUM/$TOTAL_SCANNERS] Starting ${scanner^} scan...${NC}" log_message "Starting ${scanner} scan" { echo "Scanner: ${scanner^}" echo "Started: $(date)" echo "---" } >> "$SUMMARY_FILE" case "$scanner" in imunify) log_message "ImunifyAV: Updating signatures" imunify-antivirus update &>> "$LOG_DIR/imunify.log" for path in "${SCAN_PATHS[@]}"; do if [ -d "$path" ]; then log_message "ImunifyAV: Queuing $path" imunify-antivirus malware on-demand queue put "$path" &>> "$LOG_DIR/imunify.log" fi done echo "✓ ImunifyAV scans queued" | tee -a "$SUMMARY_FILE" log_message "ImunifyAV: Scans queued successfully" ;; clamav) if command -v freshclam &>/dev/null; then log_message "ClamAV: Updating signatures" freshclam &>> "$LOG_DIR/clamav.log" fi log_message "ClamAV: Starting scan" clamscan --infected --recursive "${SCAN_PATHS[@]}" &>> "$LOG_DIR/clamav.log" # Extract infected files grep "FOUND" "$LOG_DIR/clamav.log" | cut -d: -f1 >> "$INFECTED_LIST" 2>/dev/null CLAM_INFECTED=$(grep -c "FOUND" "$LOG_DIR/clamav.log" 2>/dev/null || echo 0) echo "✓ ClamAV scan complete - Found: $CLAM_INFECTED" | tee -a "$SUMMARY_FILE" log_message "ClamAV: Scan complete - $CLAM_INFECTED infected files" ;; maldet) log_message "Maldet: Updating signatures" maldet -u &>> "$LOG_DIR/maldet.log" # Create temp path list TEMP_PATHLIST="/tmp/maldet_paths_$$.txt" printf '%s\n' "${SCAN_PATHS[@]}" > "$TEMP_PATHLIST" log_message "Maldet: Starting scan" maldet -b -f "$TEMP_PATHLIST" &>> "$LOG_DIR/maldet.log" rm -f "$TEMP_PATHLIST" echo "✓ Maldet scan complete" | tee -a "$SUMMARY_FILE" log_message "Maldet: Scan complete" ;; esac echo "" | tee -a "$SUMMARY_FILE" ((SCANNERS_COMPLETED++)) # Wait between scanners if [ $SCANNERS_COMPLETED -lt $TOTAL_SCANNERS ]; then echo "Waiting 3 seconds before next scanner..." sleep 3 fi done # Finalize report { echo "==========================================" echo "Scan Session Complete" echo "Completed: $(date)" echo "==========================================" echo "" if [ -f "$INFECTED_LIST" ] && [ -s "$INFECTED_LIST" ]; then echo "INFECTED FILES DETECTED:" echo "" sort -u "$INFECTED_LIST" else echo "No infected files detected by automated scan." echo "Review individual scanner logs for details." fi } >> "$SUMMARY_FILE" log_message "All scans completed successfully" # Display completion clear echo "==========================================" echo -e "${GREEN}Malware Scan Complete!${NC}" echo "==========================================" echo "Session: $(basename $SCAN_DIR)" echo "Completed: $(date)" echo "" echo "Results saved to:" echo " Summary: $SUMMARY_FILE" echo " Logs: $LOG_DIR/" echo "" # Show summary cat "$SUMMARY_FILE" echo "" echo "==========================================" echo "" # Prompt for cleanup read -p "Delete scan directory and all results? (yes/no): " cleanup_choice if [ "$cleanup_choice" = "yes" ]; then log_message "User requested cleanup - deleting scan directory" echo "" echo "Removing scan directory..." cd / rm -rf "$SCAN_DIR" echo -e "${GREEN}✓ Scan directory deleted${NC}" echo "" echo "This screen session will now close." sleep 2 else log_message "User chose to keep results" echo "" echo "Results preserved at: $SCAN_DIR" echo "" echo "You can:" echo " • Review logs: ls $LOG_DIR" echo " • View summary: cat $SUMMARY_FILE" echo " • Delete manually: rm -rf $SCAN_DIR" echo "" echo "Press Ctrl+A then D to detach from this screen session" echo "" fi log_message "Scan session ended" STANDALONE_EOF # Replace placeholder with actual paths local paths_declaration="SCAN_PATHS=(" for path in "${scan_paths[@]}"; do paths_declaration+="\"$path\" " done paths_declaration+=")" sed -i "s|PLACEHOLDER_SCAN_PATHS|$paths_declaration|" "$session_dir/scan.sh" # Make executable chmod +x "$session_dir/scan.sh" # Check if screen is installed if ! command -v screen &>/dev/null; then echo -e "${YELLOW}Warning: 'screen' not installed${NC}" echo "" echo "Screen allows you to detach from the scan session." echo "" echo "Options:" echo " 1. Auto-install screen (recommended)" echo " 2. Use nohup fallback (run in background without screen)" echo " 3. Cancel" echo "" read -p "Select option: " screen_option case "$screen_option" in 1) echo "" echo "Installing screen..." if command -v yum &>/dev/null; then yum install -y screen elif command -v apt-get &>/dev/null; then apt-get update && apt-get install -y screen else echo -e "${RED}Unable to auto-install. Install manually: yum install screen${NC}" read -p "Press Enter to continue..." return 1 fi if ! command -v screen &>/dev/null; then echo -e "${RED}Installation failed${NC}" read -p "Press Enter to continue..." return 1 fi echo -e "${GREEN}✓ Screen installed successfully${NC}" echo "" ;; 2) # Use nohup fallback echo "" echo "Launching scan with nohup (background mode)..." nohup bash "$session_dir/scan.sh" > "$session_dir/logs/nohup.out" 2>&1 & local scan_pid=$! sleep 1 if ps -p $scan_pid > /dev/null 2>&1; then echo "" echo -e "${GREEN}✓ Standalone scanner started successfully!${NC}" echo "" echo "Session ID: $session_id" echo "Process ID: $scan_pid" echo "Results directory: $session_dir/results/" echo "" echo -e "${CYAN}Monitor the scan:${NC}" echo " tail -f $session_dir/logs/session.log" echo "" echo -e "${CYAN}Check if still running:${NC}" echo " ps -p $scan_pid" echo "" echo -e "${GREEN}You can now safely delete the toolkit.${NC}" echo -e "${GREEN}The scan will continue running independently.${NC}" echo "" # Store session info in reference database store_reference "malware_standalone_latest" "$session_id" store_reference "malware_standalone_${session_id}_dir" "$session_dir" store_reference "malware_standalone_${session_id}_pid" "$scan_pid" read -p "Press Enter to continue..." return 0 else echo -e "${RED}Failed to start scan${NC}" echo "Run manually: bash $session_dir/scan.sh" read -p "Press Enter to continue..." return 1 fi ;; 3) echo "Cancelled." read -p "Press Enter to continue..." return 0 ;; *) echo -e "${RED}Invalid option${NC}" read -p "Press Enter to continue..." return 1 ;; esac fi # Launch in screen session echo "Launching scan in screen session..." screen -dmS "$session_id" bash "$session_dir/scan.sh" sleep 1 # Verify screen started if screen -list | grep -q "$session_id"; then echo "" echo -e "${GREEN}✓ Standalone scanner started successfully!${NC}" echo "" echo "Session ID: $session_id" echo "Screen session: $session_id" echo "Results directory: $session_dir/results/" echo "" echo -e "${CYAN}Monitor the scan:${NC}" echo " screen -r $session_id" echo "" echo -e "${CYAN}Check progress:${NC}" echo " tail -f $session_dir/logs/session.log" echo "" echo -e "${CYAN}Detach from screen:${NC}" echo " Press: Ctrl+A then D" echo "" echo -e "${GREEN}You can now safely delete the toolkit.${NC}" echo -e "${GREEN}The scan will continue running independently.${NC}" echo "" # Store session info in reference database store_reference "malware_standalone_latest" "$session_id" store_reference "malware_standalone_${session_id}_dir" "$session_dir" else echo -e "${RED}Failed to start screen session${NC}" echo "Run manually: bash $session_dir/scan.sh" fi read -p "Press Enter to continue..." } # Compare results from multiple scanners compare_scan_results() { echo "" print_header "Compare Scanner Results" # Get latest multiscan session local latest_session=$(get_reference "malware_multiscan_latest") if [ -z "$latest_session" ]; then echo "No multi-scanner sessions found." echo "" echo "Run a scan with 'All Available Scanners' option first." read -p "Press Enter to continue..." return fi local report_file=$(get_reference "malware_multiscan_${latest_session}") if [ -f "$report_file" ]; then echo "Latest multi-scanner session: $latest_session" echo "" less "$report_file" else echo "Report file not found: $report_file" fi echo "" read -p "Press Enter to continue..." } # Launch standalone scanner menu launch_standalone_scanner_menu() { echo "" print_header "Launch Standalone Scanner" echo "This will create a self-contained scanner in /opt/ that runs" echo "independently in a screen session. You can safely delete the" echo "toolkit after launching - the scan will continue running." echo "" if ! detect_control_panel; then read -p "Press Enter to continue..." return 1 fi echo "Control Panel: ${CONTROL_PANEL^}" echo "Available Scanners: ${available_scanners[*]}" echo "" echo "Select scan scope:" echo " 1. Entire server (all docroots)" echo " 2. Specific user account" echo " 3. Specific domain" echo " 4. Custom path" echo " 0. Cancel" echo "" read -p "Select option: " scope_choice local scan_paths=() local scan_description="" case $scope_choice in 1) # Entire server scan_paths=("${sanitized_docroot[@]}") scan_description="full server scan" if [ ${#scan_paths[@]} -eq 0 ]; then echo -e "${RED}No docroots found!${NC}" read -p "Press Enter to continue..." return 1 fi echo "" echo "Scan paths: ${#scan_paths[@]} docroots" ;; 2) # Specific user echo "" echo "Available users:" select_user_interactive "Select user account to scan" if [ -z "$SELECTED_USER" ]; then echo "No user selected." read -p "Press Enter to continue..." return 1 fi # Get user's docroots for docroot in "${sanitized_docroot[@]}"; do if [[ "$docroot" == *"/$SELECTED_USER/"* ]]; then scan_paths+=("$docroot") fi done if [ ${#scan_paths[@]} -eq 0 ]; then echo -e "${RED}No docroots found for user: $SELECTED_USER${NC}" read -p "Press Enter to continue..." return 1 fi scan_description="user $SELECTED_USER" echo "Found ${#scan_paths[@]} docroots for $SELECTED_USER" ;; 3) # Specific domain echo "" read -p "Enter domain name: " domain if [ -z "$domain" ]; then echo "No domain entered." read -p "Press Enter to continue..." return 1 fi # Find docroot for domain for docroot in "${sanitized_docroot[@]}"; do if [[ "$docroot" == *"/$domain"* ]] || [[ "$docroot" == *"/$domain/"* ]]; then scan_paths+=("$docroot") fi done if [ ${#scan_paths[@]} -eq 0 ]; then echo -e "${RED}No docroot found for domain: $domain${NC}" read -p "Press Enter to continue..." return 1 fi scan_description="domain $domain" echo "Found docroot: ${scan_paths[0]}" ;; 4) # Custom path echo "" read -p "Enter path to scan: " custom_path if [ -z "$custom_path" ]; then echo "No path entered." read -p "Press Enter to continue..." return 1 fi if [ ! -d "$custom_path" ]; then echo -e "${RED}Path does not exist: $custom_path${NC}" read -p "Press Enter to continue..." return 1 fi scan_paths=("$custom_path") scan_description="custom path $custom_path" ;; 0) return 0 ;; *) echo -e "${RED}Invalid option${NC}" sleep 1 return 1 ;; esac # Confirm before generating echo "" echo -e "${YELLOW}Ready to generate standalone scanner${NC}" echo "Scope: $scan_description" echo "Paths: ${#scan_paths[@]}" echo "Scanners: ${available_scanners[*]}" echo "" read -p "Generate and launch? (yes/no): " confirm if [ "$confirm" != "yes" ]; then echo "Cancelled." read -p "Press Enter to continue..." return 0 fi # Generate and launch standalone scanner generate_standalone_scanner "${scan_paths[@]}" } # Main scan menu show_scan_menu() { while true; do print_banner "Malware Scanner" echo "Available Scanners:" for scanner in "${available_scanners[@]}"; do echo " • ${scanner^}" done echo "" echo "Scan Scope:" echo " 1. Scan entire server" echo " 2. Scan specific user" echo " 3. Scan specific domain" echo " 4. Scan custom path" echo "" echo -e "${GREEN}Standalone Scanner:${NC}" echo " 5. Launch standalone scanner (runs in background, toolkit-independent)" echo "" echo "Results & Management:" echo " 6. View scan results" echo " 7. Compare scanner results" echo " 8. Scanner settings" echo "" echo " 0. Back to main menu" echo "" read -p "Select option: " choice case $choice in 1) scan_entire_server ;; 2) scan_user_account ;; 3) scan_domain ;; 4) scan_custom_path ;; 5) launch_standalone_scanner_menu ;; 6) view_scan_results ;; 7) compare_scan_results ;; 8) scanner_settings ;; 0) return 0 ;; *) echo -e "${RED}Invalid option${NC}"; sleep 1 ;; esac done } # Scan entire server scan_entire_server() { echo "" print_header "Full Server Scan" if ! detect_control_panel; then read -p "Press Enter to continue..." return 1 fi echo "Control Panel: ${CONTROL_PANEL^}" echo "Docroots found: ${#sanitized_docroot[@]}" echo "" if ! check_memory; then read -p "Press Enter to continue..." return 1 fi echo "Select scanner:" local i=1 for scanner in "${available_scanners[@]}"; do echo " $i. ${scanner^}" ((i++)) done echo " $i. All Available Scanners (run sequentially)" echo "" read -p "Scanner: " scanner_choice # Check for "All Scanners" option if [ "$scanner_choice" -eq "$i" ]; then run_all_scanners "${sanitized_docroot[@]}" elif [ "$scanner_choice" -lt 1 ] || [ "$scanner_choice" -gt ${#available_scanners[@]} ]; then echo -e "${RED}Invalid choice${NC}" read -p "Press Enter to continue..." return 1 else local selected_scanner="${available_scanners[$((scanner_choice-1))]}" case "$selected_scanner" in imunify) scan_imunify "${sanitized_docroot[@]}" ;; clamav) scan_clamav "${sanitized_docroot[@]}" ;; maldet) scan_maldet "${sanitized_docroot[@]}" ;; esac fi echo "" read -p "Press Enter to continue..." } # Scan user account scan_user_account() { echo "" print_header "Scan User Account" if ! detect_control_panel; then read -p "Press Enter to continue..." return 1 fi # Use user manager to select user select_user_interactive "Select user to scan" if [ -z "$SELECTED_USER" ]; then echo "No user selected" read -p "Press Enter to continue..." return 1 fi echo "" echo "Getting docroots for: $SELECTED_USER" local user_paths=($(get_user_docroots "$SELECTED_USER")) if [ ${#user_paths[@]} -eq 0 ]; then echo -e "${RED}No docroots found for user${NC}" read -p "Press Enter to continue..." return 1 fi echo "Paths to scan: ${#user_paths[@]}" printf ' %s\n' "${user_paths[@]}" echo "" echo "Select scanner:" local i=1 for scanner in "${available_scanners[@]}"; do echo " $i. ${scanner^}" ((i++)) done echo " $i. All Available Scanners (run sequentially)" echo "" read -p "Scanner: " scanner_choice # Check for "All Scanners" option if [ "$scanner_choice" -eq "$i" ]; then run_all_scanners "${user_paths[@]}" elif [ "$scanner_choice" -lt 1 ] || [ "$scanner_choice" -gt ${#available_scanners[@]} ]; then echo -e "${RED}Invalid choice${NC}" read -p "Press Enter to continue..." return 1 else local selected_scanner="${available_scanners[$((scanner_choice-1))]}" case "$selected_scanner" in imunify) scan_imunify "${user_paths[@]}" ;; clamav) scan_clamav "${user_paths[@]}" ;; maldet) scan_maldet "${user_paths[@]}" ;; esac fi echo "" read -p "Press Enter to continue..." } # Scan domain scan_domain() { echo "" print_header "Scan Domain" if ! detect_control_panel; then read -p "Press Enter to continue..." return 1 fi read -p "Enter domain name: " domain if [ -z "$domain" ]; then echo "No domain entered" read -p "Press Enter to continue..." return 1 fi local domain_path=$(get_domain_docroot "$domain") if [ -z "$domain_path" ] || [ ! -d "$domain_path" ]; then echo -e "${RED}Domain not found or docroot doesn't exist${NC}" read -p "Press Enter to continue..." return 1 fi echo "Docroot: $domain_path" echo "" echo "Select scanner:" local i=1 for scanner in "${available_scanners[@]}"; do echo " $i. ${scanner^}" ((i++)) done echo " $i. All Available Scanners (run sequentially)" echo "" read -p "Scanner: " scanner_choice # Check for "All Scanners" option if [ "$scanner_choice" -eq "$i" ]; then run_all_scanners "$domain_path" elif [ "$scanner_choice" -lt 1 ] || [ "$scanner_choice" -gt ${#available_scanners[@]} ]; then echo -e "${RED}Invalid choice${NC}" read -p "Press Enter to continue..." return 1 else local selected_scanner="${available_scanners[$((scanner_choice-1))]}" case "$selected_scanner" in imunify) scan_imunify "$domain_path" ;; clamav) scan_clamav "$domain_path" ;; maldet) scan_maldet "$domain_path" ;; esac fi echo "" read -p "Press Enter to continue..." } # Scan custom path scan_custom_path() { echo "" print_header "Scan Custom Path" read -p "Enter path to scan: " custom_path if [ -z "$custom_path" ] || [ ! -d "$custom_path" ]; then echo -e "${RED}Path doesn't exist${NC}" read -p "Press Enter to continue..." return 1 fi echo "Path: $custom_path" echo "" echo "Select scanner:" local i=1 for scanner in "${available_scanners[@]}"; do echo " $i. ${scanner^}" ((i++)) done echo " $i. All Available Scanners (run sequentially)" echo "" read -p "Scanner: " scanner_choice # Check for "All Scanners" option if [ "$scanner_choice" -eq "$i" ]; then run_all_scanners "$custom_path" elif [ "$scanner_choice" -lt 1 ] || [ "$scanner_choice" -gt ${#available_scanners[@]} ]; then echo -e "${RED}Invalid choice${NC}" read -p "Press Enter to continue..." return 1 else local selected_scanner="${available_scanners[$((scanner_choice-1))]}" case "$selected_scanner" in imunify) scan_imunify "$custom_path" ;; clamav) scan_clamav "$custom_path" ;; maldet) scan_maldet "$custom_path" ;; esac fi echo "" read -p "Press Enter to continue..." } # View scan results view_scan_results() { echo "" print_header "Scan Results" echo "Select results to view:" echo " 1. Toolkit scan results" echo " 2. Standalone scanner results (/opt)" echo " 0. Back" echo "" read -p "Option: " result_type case "$result_type" in 1) # Toolkit scan results echo "" echo "Select scanner to view results:" local i=1 for scanner in "${available_scanners[@]}"; do echo " $i. ${scanner^}" ((i++)) done echo "" read -p "Scanner: " scanner_choice if [ "$scanner_choice" -lt 1 ] || [ "$scanner_choice" -gt ${#available_scanners[@]} ]; then echo -e "${RED}Invalid choice${NC}" read -p "Press Enter to continue..." return 1 fi local selected_scanner="${available_scanners[$((scanner_choice-1))]}" echo "" case "$selected_scanner" in imunify) echo "Recent ImunifyAV scans:" imunify-antivirus malware on-demand list --since $(date --date="7 days ago" '+%s') 2>/dev/null || echo "No scans found" ;; clamav) echo "Recent ClamAV scans:" find "$SCRIPT_DIR/logs/malware-scans" -name "clamav_*.log" -mtime -7 2>/dev/null | sort -r | head -5 || echo "No scans found" ;; maldet) echo "Recent Maldet scans:" maldet -l 2>/dev/null || echo "No scans found" ;; esac ;; 2) # Standalone scanner results echo "" echo "Standalone scanner sessions:" echo "" # Find all malware-* directories in /opt local standalone_dirs=($(find /opt -maxdepth 1 -type d -name "malware-*" 2>/dev/null | sort -r)) if [ ${#standalone_dirs[@]} -eq 0 ]; then echo "No standalone scanner sessions found in /opt" echo "" read -p "Press Enter to continue..." return 0 fi # List sessions local i=1 for dir in "${standalone_dirs[@]}"; do local session_name=$(basename "$dir") local scan_date=$(echo "$session_name" | sed 's/malware-//') # Check if still running local status="completed" if pgrep -f "$dir/scan.sh" > /dev/null 2>&1; then status="running" fi echo " $i. $session_name [$status]" ((i++)) done echo "" read -p "Select session (or 0 to cancel): " session_choice if [ "$session_choice" = "0" ]; then return 0 fi if [ "$session_choice" -lt 1 ] || [ "$session_choice" -gt ${#standalone_dirs[@]} ]; then echo -e "${RED}Invalid choice${NC}" read -p "Press Enter to continue..." return 1 fi local selected_dir="${standalone_dirs[$((session_choice-1))]}" echo "" echo "Session: $(basename $selected_dir)" echo "Location: $selected_dir" echo "" # Show results if [ -f "$selected_dir/results/summary.txt" ]; then echo "=== Summary ===" cat "$selected_dir/results/summary.txt" echo "" else echo "Summary not yet available (scan may still be running)" echo "" fi # Show infected files if any if [ -f "$selected_dir/results/infected_files.txt" ] && [ -s "$selected_dir/results/infected_files.txt" ]; then echo "=== Infected Files ===" cat "$selected_dir/results/infected_files.txt" echo "" fi # Show recent log entries if [ -f "$selected_dir/logs/session.log" ]; then echo "=== Recent Log Entries ===" tail -20 "$selected_dir/logs/session.log" echo "" fi echo "View full logs:" echo " tail -f $selected_dir/logs/session.log" ;; 0) return 0 ;; *) echo -e "${RED}Invalid option${NC}" ;; esac echo "" read -p "Press Enter to continue..." } # Scanner settings scanner_settings() { echo "" print_header "Scanner Settings" echo "Settings (placeholder for future enhancements):" echo " • Auto-quarantine infected files" echo " • Email notifications" echo " • Scheduled scans" echo " • Custom exclusions" echo "" echo "Coming soon..." read -p "Press Enter to continue..." } # Main execution main() { if ! detect_scanners; then exit 1 fi show_scan_menu } # Run if executed directly if [ "${BASH_SOURCE[0]}" = "${0}" ]; then main "$@" fi