a51d968185
- Complete security menu restructure (3-mode: Analysis/Actions/Live) - Intelligent cPHulk enablement with CSF whitelist import - Live network security monitoring dashboard - Multi-source threat detection and classification - 50+ organized security tools across 4-level menu hierarchy - System health diagnostics with cPanel/WHM integration - Reference database for cross-module intelligence sharing
369 lines
12 KiB
Bash
Executable File
369 lines
12 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
################################################################################
|
|
# cPHulk Enablement Script with CSF Whitelist Import
|
|
################################################################################
|
|
# Purpose: Enable cPHulk brute force protection and import CSF allowed IPs
|
|
# Requirements: cPanel server with CSF installed
|
|
# Author: Server Toolkit
|
|
#
|
|
# IMPORTANT NOTES:
|
|
# - cPHulk operates SYSTEM-WIDE (not per-user or per-domain)
|
|
# - Protects all authentication services: cPanel, WHM, SSH, FTP, Email
|
|
# - This script intelligently discovers ALL CSF whitelist files including:
|
|
# * Standard files (/etc/csf/csf.allow, cpanel.allow, etc.)
|
|
# * Include directives (follows recursively)
|
|
# * Hosting panel integrations (LiquidWeb, cPanel, InterWorx, etc.)
|
|
# * Custom locations configured in csf.conf
|
|
# - Supports multiple IP formats: simple IPs, s=IP, d=IP, CIDR notation
|
|
################################################################################
|
|
|
|
# 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"
|
|
|
|
# Require root
|
|
if [ "$EUID" -ne 0 ]; then
|
|
print_error "This script must be run as root"
|
|
exit 1
|
|
fi
|
|
|
|
print_banner "cPHulk Enablement with CSF Whitelist Import"
|
|
|
|
# Check if cPanel
|
|
if [ "$SYS_CONTROL_PANEL" != "cpanel" ]; then
|
|
print_error "This script is for cPanel servers only"
|
|
print_info "Detected control panel: ${SYS_CONTROL_PANEL:-none}"
|
|
exit 1
|
|
fi
|
|
|
|
# Check if cPHulk exists
|
|
if [ ! -x "/usr/local/cpanel/bin/cphulk_pam_ctl" ]; then
|
|
print_error "cPHulk not found. This may not be a standard cPanel installation."
|
|
exit 1
|
|
fi
|
|
|
|
# Check if CSF is installed
|
|
if [ ! -x "/usr/sbin/csf" ]; then
|
|
print_warning "CSF not found - will skip CSF whitelist import"
|
|
CSF_AVAILABLE=false
|
|
else
|
|
CSF_AVAILABLE=true
|
|
fi
|
|
|
|
print_section "Current cPHulk Status"
|
|
|
|
# Get current status
|
|
CPHULK_STATUS=$(/usr/local/cpanel/bin/cphulk_pam_ctl --status 2>/dev/null)
|
|
if echo "$CPHULK_STATUS" | grep -qi "enabled"; then
|
|
print_success "cPHulk is currently ENABLED"
|
|
ALREADY_ENABLED=true
|
|
else
|
|
print_info "cPHulk is currently DISABLED"
|
|
ALREADY_ENABLED=false
|
|
fi
|
|
|
|
# Show current whitelist count
|
|
CURRENT_WHITELIST=$(/usr/local/cpanel/scripts/cphulkdwhitelist --list 2>/dev/null | grep -v "^$" | wc -l)
|
|
print_info "Current cPHulk whitelist entries: $CURRENT_WHITELIST"
|
|
|
|
if [ "$CSF_AVAILABLE" = true ]; then
|
|
print_section "CSF Whitelist Analysis"
|
|
|
|
# Get CSF allowed IPs
|
|
echo "Scanning CSF allow files and following Include directives..."
|
|
echo ""
|
|
|
|
# Start with main CSF allow file and follow all includes recursively
|
|
declare -A PROCESSED_FILES # Track processed files to avoid duplicates
|
|
CSF_FILES=()
|
|
|
|
# Function to recursively find included files
|
|
find_csf_files() {
|
|
local current_file="$1"
|
|
|
|
# Skip if already processed or doesn't exist
|
|
[ -n "${PROCESSED_FILES[$current_file]}" ] && return
|
|
[ ! -f "$current_file" ] && return
|
|
|
|
# Mark as processed
|
|
PROCESSED_FILES["$current_file"]=1
|
|
CSF_FILES+=("$current_file")
|
|
|
|
# Look for Include directives
|
|
while IFS= read -r line; do
|
|
if [[ "$line" =~ ^Include[[:space:]]+(.+)$ ]]; then
|
|
local included_file="${BASH_REMATCH[1]}"
|
|
# Trim whitespace
|
|
included_file=$(echo "$included_file" | xargs)
|
|
# Recursively process included file
|
|
find_csf_files "$included_file"
|
|
fi
|
|
done < "$current_file"
|
|
}
|
|
|
|
# Method 1: Start with main csf.allow and follow all includes
|
|
if [ -f "/etc/csf/csf.allow" ]; then
|
|
find_csf_files "/etc/csf/csf.allow"
|
|
fi
|
|
|
|
# Method 2: Scan for all .allow files in /etc/csf/ (catches files not included)
|
|
while IFS= read -r file; do
|
|
find_csf_files "$file"
|
|
done < <(find /etc/csf/ -maxdepth 1 -type f -name "*.allow" 2>/dev/null)
|
|
|
|
# Method 3: Check csf.conf for ALLOWIPS_INCLUDE directive
|
|
# This directive can point to custom include directories
|
|
if [ -f "/etc/csf/csf.conf" ]; then
|
|
ALLOWIPS_INCLUDE=$(grep "^ALLOWIPS_INCLUDE" /etc/csf/csf.conf | cut -d'=' -f2 | tr -d '"' | tr -d ' ')
|
|
if [ -n "$ALLOWIPS_INCLUDE" ] && [ -d "$ALLOWIPS_INCLUDE" ]; then
|
|
echo "Found ALLOWIPS_INCLUDE directory: $ALLOWIPS_INCLUDE"
|
|
while IFS= read -r file; do
|
|
find_csf_files "$file"
|
|
done < <(find "$ALLOWIPS_INCLUDE" -type f 2>/dev/null)
|
|
fi
|
|
fi
|
|
|
|
# Method 4: Common custom CSF include locations (hosting panel integrations)
|
|
COMMON_CSF_LOCATIONS=(
|
|
"/usr/local/lp/etc/csf" # LiquidWeb
|
|
"/usr/local/cpanel/etc/csf" # cPanel custom
|
|
"/usr/local/interworx/etc/csf" # InterWorx
|
|
"/var/cpanel/csf" # cPanel var
|
|
"/root/.csf" # Custom user location
|
|
)
|
|
|
|
for location in "${COMMON_CSF_LOCATIONS[@]}"; do
|
|
if [ -d "$location" ]; then
|
|
# Look for all .allow files in these locations
|
|
while IFS= read -r file; do
|
|
find_csf_files "$file"
|
|
done < <(find "$location" -type f -name "*allow*" 2>/dev/null)
|
|
fi
|
|
done
|
|
|
|
# Method 5: Parse all Include directives from csf.conf CUSTOM variables
|
|
if [ -f "/etc/csf/csf.conf" ]; then
|
|
# Some systems use CUSTOM1_LOG through CUSTOM9_LOG which may reference allow files
|
|
while IFS= read -r include_path; do
|
|
if [ -f "$include_path" ]; then
|
|
find_csf_files "$include_path"
|
|
fi
|
|
done < <(grep -E "^(CUSTOM|GENERIC).*Include" /etc/csf/csf.conf 2>/dev/null | grep -oE '\/[^"]+' || true)
|
|
fi
|
|
|
|
if [ ${#CSF_FILES[@]} -eq 0 ]; then
|
|
print_warning "No CSF .allow files found"
|
|
CSF_AVAILABLE=false
|
|
else
|
|
echo "Found ${#CSF_FILES[@]} CSF allow files (including includes):"
|
|
for file in "${CSF_FILES[@]}"; do
|
|
if [[ "$file" == /etc/csf/* ]]; then
|
|
echo " • $(basename "$file")"
|
|
else
|
|
echo " • $file"
|
|
fi
|
|
done
|
|
echo ""
|
|
fi
|
|
|
|
# Extract IPs from all CSF files
|
|
CSF_ALLOW_IPS=()
|
|
declare -A IP_SOURCE_COUNT # Track which files contributed IPs
|
|
|
|
if [ ${#CSF_FILES[@]} -gt 0 ]; then
|
|
for csf_file in "${CSF_FILES[@]}"; do
|
|
file_ip_count=0
|
|
file_display_name=""
|
|
|
|
if [[ "$csf_file" == /etc/csf/* ]]; then
|
|
file_display_name="$(basename "$csf_file")"
|
|
else
|
|
file_display_name="$csf_file"
|
|
fi
|
|
|
|
while IFS= read -r line; do
|
|
# Skip comments and empty lines
|
|
[[ "$line" =~ ^#.*$ ]] && continue
|
|
[[ -z "$line" ]] && continue
|
|
|
|
# Skip Include directives (already processed)
|
|
[[ "$line" =~ ^Include ]] && continue
|
|
|
|
# Try multiple IP extraction methods:
|
|
ip=""
|
|
|
|
# Method 1: Simple IP format (IP at start of line)
|
|
# Example: 192.168.100.1 # comment
|
|
# Also handles CIDR: 10.20.4.0/22 # comment (strip /CIDR, just get IP)
|
|
if [ -z "$ip" ]; then
|
|
ip=$(echo "$line" | awk '{print $1}' | grep -oE '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}')
|
|
fi
|
|
|
|
# Method 2: CSF source format (s=IP)
|
|
# Example: tcp|in|d=4|s=208.74.123.2 # cPanel Auth Server
|
|
if [ -z "$ip" ]; then
|
|
ip=$(echo "$line" | grep -oE 's=[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | cut -d'=' -f2)
|
|
fi
|
|
|
|
# Method 3: CSF destination format (d=IP)
|
|
# Example: tcp|out|d=443|d=45.11.128.61/32
|
|
if [ -z "$ip" ]; then
|
|
# Extract last d= parameter that contains an IP (not a port)
|
|
ip=$(echo "$line" | grep -oE 'd=[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | tail -1 | cut -d'=' -f2)
|
|
fi
|
|
|
|
if [ -n "$ip" ]; then
|
|
# Check if not already in array (deduplicate)
|
|
if [[ ! " ${CSF_ALLOW_IPS[@]} " =~ " ${ip} " ]]; then
|
|
CSF_ALLOW_IPS+=("$ip")
|
|
file_ip_count=$((file_ip_count + 1))
|
|
fi
|
|
fi
|
|
done < "$csf_file"
|
|
|
|
# Track count per file
|
|
if [ $file_ip_count -gt 0 ]; then
|
|
IP_SOURCE_COUNT["$file_display_name"]=$file_ip_count
|
|
fi
|
|
done
|
|
|
|
# Show breakdown by file
|
|
echo "IP breakdown by source file:"
|
|
for file in $(printf '%s\n' "${!IP_SOURCE_COUNT[@]}" | sort); do
|
|
printf " • %-45s %3d IPs\n" "$file" "${IP_SOURCE_COUNT[$file]}"
|
|
done
|
|
echo ""
|
|
|
|
print_success "Found ${#CSF_ALLOW_IPS[@]} total unique IPs across all CSF files"
|
|
fi
|
|
|
|
if [ ${#CSF_ALLOW_IPS[@]} -gt 0 ]; then
|
|
echo ""
|
|
echo "Sample IPs to be imported:"
|
|
for i in {0..4}; do
|
|
if [ -n "${CSF_ALLOW_IPS[$i]}" ]; then
|
|
echo " • ${CSF_ALLOW_IPS[$i]}"
|
|
fi
|
|
done
|
|
if [ ${#CSF_ALLOW_IPS[@]} -gt 5 ]; then
|
|
echo " ... and $((${#CSF_ALLOW_IPS[@]} - 5)) more"
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
echo ""
|
|
print_section "Actions to Perform"
|
|
|
|
if [ "$ALREADY_ENABLED" = false ]; then
|
|
echo " 1. Enable cPHulk brute force protection"
|
|
else
|
|
echo " 1. cPHulk already enabled (skip)"
|
|
fi
|
|
|
|
if [ "$CSF_AVAILABLE" = true ] && [ ${#CSF_ALLOW_IPS[@]} -gt 0 ]; then
|
|
echo " 2. Import ${#CSF_ALLOW_IPS[@]} IPs from CSF to cPHulk whitelist"
|
|
else
|
|
echo " 2. No CSF IPs to import (skip)"
|
|
fi
|
|
|
|
echo " 3. Display final configuration"
|
|
|
|
echo ""
|
|
read -p "Proceed with these actions? (yes/no): " confirm
|
|
|
|
if [ "$confirm" != "yes" ]; then
|
|
print_info "Operation cancelled"
|
|
exit 0
|
|
fi
|
|
|
|
echo ""
|
|
print_section "Execution"
|
|
|
|
# Step 1: Enable cPHulk
|
|
if [ "$ALREADY_ENABLED" = false ]; then
|
|
print_info "Enabling cPHulk..."
|
|
if /usr/local/cpanel/bin/cphulk_pam_ctl --enable 2>&1; then
|
|
print_success "cPHulk enabled successfully"
|
|
else
|
|
print_error "Failed to enable cPHulk"
|
|
exit 1
|
|
fi
|
|
else
|
|
print_info "cPHulk already enabled, skipping"
|
|
fi
|
|
|
|
# Step 2: Import CSF whitelist
|
|
if [ "$CSF_AVAILABLE" = true ] && [ ${#CSF_ALLOW_IPS[@]} -gt 0 ]; then
|
|
print_info "Importing CSF whitelist to cPHulk..."
|
|
|
|
IMPORTED=0
|
|
SKIPPED=0
|
|
FAILED=0
|
|
|
|
for ip in "${CSF_ALLOW_IPS[@]}"; do
|
|
# Check if already in cPHulk whitelist
|
|
if /usr/local/cpanel/scripts/cphulkdwhitelist --list 2>/dev/null | grep -q "$ip"; then
|
|
SKIPPED=$((SKIPPED + 1))
|
|
echo " [SKIP] $ip (already whitelisted)"
|
|
else
|
|
# Add to cPHulk whitelist
|
|
if whmapi1 cphulkd_add_whitelist ip="$ip" 2>&1 | grep -q "success.*1"; then
|
|
IMPORTED=$((IMPORTED + 1))
|
|
echo " [OK] $ip"
|
|
else
|
|
FAILED=$((FAILED + 1))
|
|
echo " [FAIL] $ip"
|
|
fi
|
|
fi
|
|
done
|
|
|
|
echo ""
|
|
print_success "Import complete:"
|
|
echo " • Imported: $IMPORTED"
|
|
echo " • Skipped (already whitelisted): $SKIPPED"
|
|
if [ $FAILED -gt 0 ]; then
|
|
print_warning "Failed: $FAILED"
|
|
fi
|
|
fi
|
|
|
|
# Step 3: Display final status
|
|
echo ""
|
|
print_section "Final Configuration"
|
|
|
|
# Check status
|
|
FINAL_STATUS=$(/usr/local/cpanel/bin/cphulk_pam_ctl --status 2>/dev/null)
|
|
if echo "$FINAL_STATUS" | grep -qi "enabled"; then
|
|
print_success "cPHulk Status: ENABLED"
|
|
else
|
|
print_error "cPHulk Status: DISABLED (unexpected)"
|
|
fi
|
|
|
|
# Count whitelist
|
|
FINAL_WHITELIST=$(/usr/local/cpanel/scripts/cphulkdwhitelist --list 2>/dev/null | grep -v "^$" | wc -l)
|
|
print_info "cPHulk whitelist entries: $FINAL_WHITELIST"
|
|
|
|
echo ""
|
|
print_section "Next Steps"
|
|
|
|
echo "1. Configure cPHulk settings in WHM:"
|
|
echo " WHM → Security Center → cPHulk Brute Force Protection"
|
|
echo ""
|
|
echo "2. Recommended settings:"
|
|
echo " • Brute Force Protection Period: 5 minutes"
|
|
echo " • Maximum Failures per Account: 5"
|
|
echo " • Maximum Failures per IP: 10"
|
|
echo ""
|
|
echo "3. Add your own IPs to whitelist:"
|
|
echo " whmapi1 cphulkd_add_whitelist ip=YOUR.IP.ADDRESS"
|
|
echo ""
|
|
echo "4. View currently blocked IPs:"
|
|
echo " whmapi1 cphulkd_list_blocks"
|
|
echo ""
|
|
echo "5. Remove a blocked IP:"
|
|
echo " whmapi1 cphulkd_remove_block ip=IP.TO.UNBLOCK"
|
|
|
|
echo ""
|
|
print_success "cPHulk setup complete!"
|