#!/bin/bash
# ============================================================
#  SERVER SECURITY AUDIT SCRIPT
#  For cPanel/WHM Linux Servers
#  Usage: bash server_audit.sh
#  Run as: root
# ============================================================

# --- Colors & Styles ---
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
MAGENTA='\033[0;35m'
WHITE='\033[1;37m'
GRAY='\033[0;37m'
BOLD='\033[1m'
RESET='\033[0m'

# --- Output file ---
REPORT="/root/audit_report_$(hostname)_$(date +%Y%m%d_%H%M%S).txt"
ISSUES=0
WARNINGS=0

# --- Helpers ---
print_header() {
    echo ""
    echo -e "${CYAN}╔══════════════════════════════════════════════════════════════╗${RESET}"
    echo -e "${CYAN}║${WHITE}${BOLD}  $1${RESET}${CYAN}$(printf '%*s' $((62 - ${#1})) '')║${RESET}"
    echo -e "${CYAN}╚══════════════════════════════════════════════════════════════╝${RESET}"
    echo "" 
    echo "=== $1 ===" >> "$REPORT"
}

print_section() {
    echo -e "\n${BLUE}┌─────────────────────────────────────────┐${RESET}"
    echo -e "${BLUE}│${BOLD}  $1${RESET}${BLUE}$(printf '%*s' $((43 - ${#1})) '')│${RESET}"
    echo -e "${BLUE}└─────────────────────────────────────────┘${RESET}"
    echo "" >> "$REPORT"
    echo "--- $1 ---" >> "$REPORT"
}

ok()      { echo -e "  ${GREEN}✔${RESET}  $1"; echo "  [OK]  $1" >> "$REPORT"; }
warn()    { echo -e "  ${YELLOW}⚠${RESET}  ${YELLOW}$1${RESET}"; echo "  [WARN] $1" >> "$REPORT"; ((WARNINGS++)); }
critical(){ echo -e "  ${RED}✘${RESET}  ${RED}${BOLD}$1${RESET}"; echo "  [CRITICAL] $1" >> "$REPORT"; ((ISSUES++)); }
info()    { echo -e "  ${GRAY}ℹ${RESET}  $1"; echo "  [INFO] $1" >> "$REPORT"; }
data()    { echo -e "  ${MAGENTA}→${RESET}  $1"; echo "  $1" >> "$REPORT"; }

divider() { echo -e "  ${GRAY}──────────────────────────────────────────${RESET}"; }

# ============================================================
# BANNER
# ============================================================
clear
echo -e "${CYAN}"
cat << 'EOF'
  ███████╗███████╗ ██████╗
  ██╔════╝██╔════╝██╔════╝
  ███████╗█████╗  ██║
  ╚════██║██╔══╝  ██║
  ███████║███████╗╚██████╗
  ╚══════╝╚══════╝ ╚═════╝
  SERVER SECURITY AUDIT - cPanel Edition
EOF
echo -e "${RESET}"
echo -e "  ${WHITE}Host:${RESET} $(hostname)   ${WHITE}Date:${RESET} $(date '+%Y-%m-%d %H:%M:%S')"
echo -e "  ${WHITE}Report:${RESET} $REPORT"
echo ""
echo "SERVER SECURITY AUDIT REPORT" > "$REPORT"
echo "Host: $(hostname)" >> "$REPORT"
echo "Date: $(date)" >> "$REPORT"
echo "======================================" >> "$REPORT"

sleep 1

# ============================================================
# 1. SYSTEM INFO
# ============================================================
print_header "1. SYSTEM INFORMATION"

print_section "Basic Info"
UPTIME=$(uptime -p 2>/dev/null || uptime)
KERNEL=$(uname -r)
OS=$(cat /etc/redhat-release 2>/dev/null || cat /etc/os-release | grep PRETTY_NAME | cut -d'"' -f2)
data "Hostname  : $(hostname)"
data "OS        : $OS"
data "Kernel    : $KERNEL"
data "Uptime    : $UPTIME"
data "CPU Cores : $(nproc)"
data "RAM Total : $(free -h | awk '/^Mem:/{print $2}')"

print_section "Load Average"
LOAD=$(cat /proc/loadavg | awk '{print $1, $2, $3}')
CORES=$(nproc)
LOAD1=$(cat /proc/loadavg | awk '{print $1}' | cut -d. -f1)
data "Load (1/5/15 min): $LOAD"
if [ "$LOAD1" -gt "$((CORES * 2))" ] 2>/dev/null; then
    critical "Server load is very high! ($LOAD1 > $((CORES * 2)) cores)"
elif [ "$LOAD1" -gt "$CORES" ] 2>/dev/null; then
    warn "Server load is elevated ($LOAD1 > $CORES cores)"
else
    ok "Server load is normal"
fi

# ============================================================
# 2. DISK USAGE
# ============================================================
print_header "2. DISK USAGE"

print_section "Filesystem Usage"
while IFS= read -r line; do
    USAGE=$(echo "$line" | awk '{print $5}' | tr -d '%')
    FS=$(echo "$line" | awk '{print $6}')
    data "$line"
    if [ "$USAGE" -ge 100 ] 2>/dev/null; then
        critical "Filesystem $FS is FULL (${USAGE}%) — Services may fail!"
    elif [ "$USAGE" -ge 90 ] 2>/dev/null; then
        critical "Filesystem $FS is critically full (${USAGE}%)"
    elif [ "$USAGE" -ge 80 ] 2>/dev/null; then
        warn "Filesystem $FS usage is high (${USAGE}%)"
    fi
done < <(df -h | grep -v tmpfs | grep -v "Filesystem" | grep -v "udev")

print_section "Top 10 Largest Home Directories"
du -sh /home/* 2>/dev/null | sort -rh | head -10 | while read -r line; do
    data "$line"
done

print_section "Large Log Files (>500MB)"
find /var/log -size +500M -type f 2>/dev/null | while read -r f; do
    SIZE=$(du -sh "$f" 2>/dev/null | awk '{print $1}')
    warn "Large log file: $f ($SIZE)"
done || ok "No oversized log files found"

# ============================================================
# 3. USER ACCOUNT SECURITY
# ============================================================
print_header "3. USER ACCOUNT SECURITY"

print_section "UID 0 (Root-level) Accounts"
UID0=$(awk -F: '($3==0){print $1}' /etc/passwd)
UID0_COUNT=$(echo "$UID0" | wc -l)
for user in $UID0; do
    if [ "$user" = "root" ]; then
        ok "root (expected)"
    else
        critical "BACKDOOR ACCOUNT with UID 0: $user"
        data "Entry: $(grep "^$user" /etc/passwd)"
    fi
done

print_section "Root SSH Authorized Keys"
KEYS=$(cat /root/.ssh/authorized_keys 2>/dev/null)
if [ -z "$KEYS" ]; then
    ok "No SSH authorized keys (good if using password auth)"
else
    KEY_COUNT=$(echo "$KEYS" | grep -c "ssh-" 2>/dev/null || echo 0)
    warn "$KEY_COUNT SSH key(s) found in /root/.ssh/authorized_keys"
    echo "$KEYS" | while IFS= read -r line; do
        [ -n "$line" ] && data "  $line"
    done
fi

print_section "Users with Login Shell"
info "Non-system users with bash/sh shell:"
awk -F: '($7=="/bin/bash" || $7=="/bin/sh") && $3>=1000 {print $1" (UID:"$3")"}' /etc/passwd | while read -r u; do
    data "$u"
done

print_section "Recently Modified /etc/passwd"
PASSWD_AGE=$(find /etc/passwd -mmin -1440 2>/dev/null)
if [ -n "$PASSWD_AGE" ]; then
    warn "/etc/passwd was modified in the last 24 hours!"
    data "Modified: $(stat -c '%y' /etc/passwd)"
else
    ok "/etc/passwd not recently modified"
fi

# ============================================================
# 4. SSH & LOGIN SECURITY
# ============================================================
print_header "4. SSH & LOGIN SECURITY"

print_section "SSH Configuration"
PERMIT_ROOT=$(grep "^PermitRootLogin" /etc/ssh/sshd_config 2>/dev/null | awk '{print $2}')
PASS_AUTH=$(grep "^PasswordAuthentication" /etc/ssh/sshd_config 2>/dev/null | awk '{print $2}')
SSH_PORT=$(grep "^Port" /etc/ssh/sshd_config 2>/dev/null | awk '{print $2}')

[ -z "$SSH_PORT" ] && SSH_PORT="22 (default)"
data "SSH Port            : $SSH_PORT"
data "PermitRootLogin     : ${PERMIT_ROOT:-yes (default)}"
data "PasswordAuthentication: ${PASS_AUTH:-yes (default)}"

[ "$PERMIT_ROOT" = "yes" ] || [ -z "$PERMIT_ROOT" ] && warn "Root SSH login is permitted — consider restricting"
[ "$SSH_PORT" = "22 (default)" ] && warn "SSH is on default port 22 — consider changing"
[ "$PASS_AUTH" != "no" ] && warn "Password authentication enabled — key-only is safer"

print_section "Recent Root SSH Logins (Last 30 Days)"
KNOWN_IPS="${KNOWN_IPS:-103.65.134 103.169.161 103.96.70}"
grep "Accepted.*for root" /var/log/secure 2>/dev/null | tail -20 | while IFS= read -r line; do
    IP=$(echo "$line" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | head -1)
    DATE=$(echo "$line" | awk '{print $1,$2,$3}')
    KNOWN=false
    for known in $KNOWN_IPS; do
        [[ "$IP" == $known* ]] && KNOWN=true && break
    done
    if $KNOWN; then
        ok "$DATE — $IP (known)"
    else
        critical "$DATE — $IP (UNKNOWN IP — verify!)"
    fi
done

print_section "Failed Login Attempts (Last 50)"
FAIL_COUNT=$(grep "Failed password" /var/log/secure 2>/dev/null | wc -l)
data "Total failed login attempts in log: $FAIL_COUNT"
TOP_FAIL=$(grep "Failed password" /var/log/secure 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | sort | uniq -c | sort -rn | head -5)
if [ -n "$TOP_FAIL" ]; then
    warn "Top attacking IPs:"
    echo "$TOP_FAIL" | while read -r line; do data "  $line attempts"; done
else
    ok "No failed login attempts found in logs"
fi

print_section "Currently Logged In Users"
who | while IFS= read -r line; do
    data "$line"
done

# ============================================================
# 5. CPANEL/WHM SECURITY
# ============================================================
print_header "5. CPANEL/WHM SECURITY"

print_section "Active WHM/cPanel Sessions"
SESSION_COUNT=$(ls /var/cpanel/sessions/raw/ 2>/dev/null | wc -l)
if [ "$SESSION_COUNT" -gt 0 ]; then
    warn "$SESSION_COUNT active session(s) found"
    ls -la /var/cpanel/sessions/raw/ 2>/dev/null | tail -10 | while IFS= read -r line; do
        data "$line"
    done
else
    ok "No active sessions"
fi

print_section "Reseller Accounts"
if [ -f /var/cpanel/resellers ]; then
    RESELLER_COUNT=$(wc -l < /var/cpanel/resellers)
    data "Total resellers: $RESELLER_COUNT"
    cat /var/cpanel/resellers | while IFS= read -r line; do
        data "  $line"
    done
else
    ok "No reseller accounts found"
fi

print_section "Recent WHM Access Log (Suspicious)"
grep -E "passwd|removeacct|listresellers" /usr/local/cpanel/logs/access_log 2>/dev/null | \
    grep -v "403\|401" | tail -10 | while IFS= read -r line; do
    IP=$(echo "$line" | awk '{print $1}')
    critical "Suspicious WHM action from $IP: $line"
done

# ============================================================
# 6. MALWARE & FILE INTEGRITY
# ============================================================
print_header "6. MALWARE & FILE INTEGRITY"

print_section "Imunify360 Malware Detections"
if command -v imunify360-agent &>/dev/null; then
    MALWARE=$(imunify360-agent malware malicious list --limit 50 2>/dev/null)
    if [ -n "$MALWARE" ]; then
        MALWARE_COUNT=$(echo "$MALWARE" | grep -c "True" 2>/dev/null || echo "unknown")
        critical "Imunify360 detected $MALWARE_COUNT malicious file(s)"
        imunify360-agent malware malicious list --limit 10 2>/dev/null | \
            awk -F'  +' '{print $8, $16}' | grep -v "^FILE" | while IFS= read -r line; do
            [ -n "$line" ] && data "  $line"
        done
    else
        ok "No malware detected by Imunify360"
    fi
else
    warn "Imunify360 not installed"
fi

print_section "Suspicious Files in /tmp and /var/tmp"
SUSP=$(find /tmp /var/tmp /dev/shm -type f \
    \( -name "*.sh" -o -name "*.py" -o -name "*.pl" -o -perm /111 \) \
    2>/dev/null)
if [ -n "$SUSP" ]; then
    critical "Suspicious executable files found in temp directories:"
    echo "$SUSP" | while IFS= read -r f; do
        SIZE=$(du -sh "$f" 2>/dev/null | awk '{print $1}')
        data "  $f ($SIZE)"
    done
else
    ok "No suspicious files in temp directories"
fi

print_section "Recently Modified System Files (Last 24h)"
RECENT=$(find /etc /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin \
    -newer /proc/1 -type f 2>/dev/null | grep -v ".pyc" | head -20)
if [ -n "$RECENT" ]; then
    warn "Recently modified system files:"
    echo "$RECENT" | while IFS= read -r f; do
        data "  $f ($(stat -c '%y' "$f" 2>/dev/null | cut -d. -f1))"
    done
else
    ok "No suspicious recently modified system files"
fi

print_section "World-Writable Files in /home (PHP)"
WW=$(find /home/*/public_html -type f -perm -o+w -name "*.php" 2>/dev/null | head -10)
if [ -n "$WW" ]; then
    warn "World-writable PHP files found:"
    echo "$WW" | while IFS= read -r f; do data "  $f"; done
else
    ok "No world-writable PHP files found"
fi

# ============================================================
# 7. CRON JOB AUDIT
# ============================================================
print_header "7. CRON JOB AUDIT"

print_section "Root Crontab"
ROOT_CRON=$(crontab -l 2>/dev/null)
if [ -z "$ROOT_CRON" ]; then
    ok "Root crontab is empty"
else
    warn "Root has cron jobs:"
    echo "$ROOT_CRON" | while IFS= read -r line; do data "  $line"; done
fi

print_section "Suspicious Cron Patterns (All Users)"
SUSP_CRON=$(grep -r "wget\|curl\|bash\|nc \|ncat\|python\|perl\|base64" \
    /var/spool/cron/* /etc/cron.d/* 2>/dev/null | \
    grep -v "^#" | grep -v "cpanel\|imunify\|cloudlinux\|softaculous\|jetbackup\|lfd\|csf")
if [ -n "$SUSP_CRON" ]; then
    critical "Suspicious cron jobs found:"
    echo "$SUSP_CRON" | while IFS= read -r line; do data "  $line"; done
else
    ok "No obviously suspicious cron patterns found"
fi

# ============================================================
# 8. NETWORK & FIREWALL
# ============================================================
print_header "8. NETWORK & FIREWALL"

print_section "CSF Firewall Status"
if command -v csf &>/dev/null; then
    CSF_TEST=$(grep "^TESTING" /etc/csf/csf.conf 2>/dev/null | awk '{print $3}' | tr -d '"')
    SMTP_BLOCK=$(grep "^SMTP_BLOCK" /etc/csf/csf.conf 2>/dev/null | awk '{print $3}' | tr -d '"')
    LF_TRIGGER=$(grep "^LF_TRIGGER " /etc/csf/csf.conf 2>/dev/null | awk '{print $3}' | tr -d '"')
    CT_LIMIT=$(grep "^CT_LIMIT" /etc/csf/csf.conf 2>/dev/null | awk '{print $3}' | tr -d '"')

    data "TESTING mode  : ${CSF_TEST:-unknown}"
    data "SMTP_BLOCK    : ${SMTP_BLOCK:-0}"
    data "LF_TRIGGER    : ${LF_TRIGGER:-0}"
    data "CT_LIMIT      : ${CT_LIMIT:-0}"

    [ "$CSF_TEST" = "1" ] && critical "CSF is in TESTING MODE — firewall rules not enforced!"
    [ "$SMTP_BLOCK" = "0" ] && warn "SMTP_BLOCK is disabled — scripts can send spam directly"
    [ "$LF_TRIGGER" = "0" ] && warn "LF_TRIGGER is disabled — login failures not auto-blocking"
    [ "$CT_LIMIT" = "0" ] && warn "CT_LIMIT is disabled — no connection flood protection"
    ok "CSF is installed"
else
    critical "CSF firewall not installed!"
fi

print_section "Listening Ports"
ss -tlnp 2>/dev/null | grep LISTEN | while IFS= read -r line; do
    data "$line"
done

print_section "Currently Blocked IPs (CSF)"
if command -v csf &>/dev/null; then
    BLOCKED=$(grep -c "^" /etc/csf/csf.deny 2>/dev/null || echo 0)
    data "Total blocked IPs: $BLOCKED"
fi

# ============================================================
# 9. SERVICE STATUS
# ============================================================
print_header "9. SERVICE STATUS"

print_section "Critical Services"
SERVICES=("sshd" "mysqld mariadbd" "exim" "dovecot" "lfd" "imunify360" "litespeed lshttpd")
SERVICE_NAMES=("SSH" "MySQL/MariaDB" "Exim Mail" "Dovecot IMAP" "LFD (CSF)" "Imunify360" "LiteSpeed Web")

for i in "${!SERVICE_NAMES[@]}"; do
    NAME="${SERVICE_NAMES[$i]}"
    for svc in ${SERVICES[$i]}; do
        if systemctl is-active --quiet "$svc" 2>/dev/null || \
           pgrep -x "$svc" &>/dev/null || \
           pgrep -f "$svc" &>/dev/null; then
            ok "$NAME is running"
            break
        fi
    done
    # If none matched
    if ! systemctl is-active --quiet ${SERVICES[$i]%% *} 2>/dev/null && \
       ! pgrep -f "${SERVICES[$i]%% *}" &>/dev/null; then
        : # already printed above
    fi
done

print_section "cPanel Service Check"
if [ -f /usr/local/cpanel/cpanel ]; then
    CPANEL_VER=$(cat /usr/local/cpanel/version 2>/dev/null)
    ok "cPanel installed (v$CPANEL_VER)"
    SESSION_COUNT=$(ls /var/cpanel/sessions/raw/ 2>/dev/null | wc -l)
    data "Active sessions: $SESSION_COUNT"
else
    warn "cPanel not found on this server"
fi

# ============================================================
# 10. MEMORY & PROCESS CHECK
# ============================================================
print_header "10. MEMORY & PROCESS CHECK"

print_section "Memory Usage"
MEM_TOTAL=$(free -h | awk '/^Mem:/{print $2}')
MEM_USED=$(free -h | awk '/^Mem:/{print $3}')
MEM_PCT=$(free | awk '/^Mem:/{printf "%.0f", $3/$2*100}')
SWAP_USED=$(free -h | awk '/^Swap:/{print $3}')
data "RAM: $MEM_USED / $MEM_TOTAL (${MEM_PCT}%)"
data "Swap Used: $SWAP_USED"
[ "$MEM_PCT" -gt 90 ] 2>/dev/null && critical "Memory usage critical (${MEM_PCT}%)"
[ "$MEM_PCT" -gt 80 ] 2>/dev/null && warn "Memory usage high (${MEM_PCT}%)"

print_section "Top 5 CPU-Consuming Processes"
ps aux --sort=-%cpu | head -6 | tail -5 | while IFS= read -r line; do
    data "$line"
done

print_section "Top 5 Memory-Consuming Processes"
ps aux --sort=-%mem | head -6 | tail -5 | while IFS= read -r line; do
    data "$line"
done

# ============================================================
# SUMMARY
# ============================================================
echo ""
echo -e "${CYAN}╔══════════════════════════════════════════════════════════════╗${RESET}"
echo -e "${CYAN}║${BOLD}${WHITE}                    AUDIT SUMMARY                              ${RESET}${CYAN}║${RESET}"
echo -e "${CYAN}╠══════════════════════════════════════════════════════════════╣${RESET}"
echo -e "${CYAN}║${RESET}  Host    : $(hostname)$(printf '%*s' $((49 - ${#HOSTNAME})) '')${CYAN}║${RESET}"
echo -e "${CYAN}║${RESET}  Date    : $(date '+%Y-%m-%d %H:%M:%S')                         ${CYAN}║${RESET}"
echo -e "${CYAN}║${RESET}  Report  : $REPORT  ${CYAN}║${RESET}"
echo -e "${CYAN}╠══════════════════════════════════════════════════════════════╣${RESET}"

if [ "$ISSUES" -gt 0 ]; then
    echo -e "${CYAN}║${RESET}  ${RED}${BOLD}✘ CRITICAL ISSUES : $ISSUES${RESET}$(printf '%*s' $((41 - ${#ISSUES})) '')${CYAN}║${RESET}"
else
    echo -e "${CYAN}║${RESET}  ${GREEN}✔ CRITICAL ISSUES : 0${RESET}                                       ${CYAN}║${RESET}"
fi

if [ "$WARNINGS" -gt 0 ]; then
    echo -e "${CYAN}║${RESET}  ${YELLOW}⚠ WARNINGS        : $WARNINGS${RESET}$(printf '%*s' $((41 - ${#WARNINGS})) '')${CYAN}║${RESET}"
else
    echo -e "${CYAN}║${RESET}  ${GREEN}✔ WARNINGS        : 0${RESET}                                       ${CYAN}║${RESET}"
fi

echo -e "${CYAN}╚══════════════════════════════════════════════════════════════╝${RESET}"

if [ "$ISSUES" -gt 0 ]; then
    echo -e "\n  ${RED}${BOLD}⚠  ACTION REQUIRED — Check the report for critical issues!${RESET}"
elif [ "$WARNINGS" -gt 0 ]; then
    echo -e "\n  ${YELLOW}⚠  Review warnings in the report for potential issues.${RESET}"
else
    echo -e "\n  ${GREEN}✔  Server looks clean. Stay vigilant!${RESET}"
fi

echo ""
echo -e "  ${GRAY}Full report saved to: ${WHITE}$REPORT${RESET}"
echo ""

# Save summary to report
echo "" >> "$REPORT"
echo "======================================" >> "$REPORT"
echo "SUMMARY" >> "$REPORT"
echo "Critical Issues : $ISSUES" >> "$REPORT"
echo "Warnings        : $WARNINGS" >> "$REPORT"
echo "Report saved    : $REPORT" >> "$REPORT"
