Sync all scripts from website downloads — 352 scripts total
Includes updated JS challenge scripts with Claude-User whitelist, same-site referer bypass, Blackbox-Exporter allowed bot, and all new exporters, cheat sheets, and automation scripts.
This commit is contained in:
@@ -0,0 +1,658 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
#########################################################################################
|
||||
#### apache-security-auditor.sh — Audit Apache httpd configuration for security issues####
|
||||
#### Checks server info, TLS, headers, directories, modules, and file permissions ####
|
||||
#### Requires: bash 4+, root access ####
|
||||
#### ####
|
||||
#### Author: Phil Connor ####
|
||||
#### Contact: contact@mylinux.work ####
|
||||
#### License: MIT ####
|
||||
#### Version 1.01 ####
|
||||
#### ####
|
||||
#### Usage: ####
|
||||
#### sudo ./apache-security-auditor.sh --full ####
|
||||
#### ####
|
||||
#### See --help for all options. ####
|
||||
#########################################################################################
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# ── Colors (pre-initialized) ─────────────────────────────────────────
|
||||
RED="" GREEN="" YELLOW="" BLUE="" CYAN="" BOLD="" DIM="" RESET=""
|
||||
|
||||
setup_colors() {
|
||||
if [[ "${COLOR:-auto}" == "never" ]]; then
|
||||
return
|
||||
fi
|
||||
if [[ "${COLOR:-auto}" == "always" ]] || [[ -t 1 ]]; then
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[0;33m'
|
||||
BLUE='\033[0;34m'
|
||||
CYAN='\033[0;36m'
|
||||
BOLD='\033[1m'
|
||||
DIM='\033[2m'
|
||||
RESET='\033[0m'
|
||||
fi
|
||||
}
|
||||
|
||||
# ── Logging ───────────────────────────────────────────────────────────
|
||||
log() { echo -e "${BLUE}[INFO]${RESET} $*"; }
|
||||
warn() { echo -e "${YELLOW}[WARN]${RESET} $*" >&2; }
|
||||
err() { echo -e "${RED}[ERROR]${RESET} $*" >&2; }
|
||||
verbose() { if [[ "$VERBOSE" == "true" ]]; then echo -e "${DIM}[DEBUG]${RESET} $*"; fi; }
|
||||
die() { err "$*"; exit 1; }
|
||||
|
||||
# ── Severity counters ────────────────────────────────────────────────
|
||||
TOTAL_CRIT=0
|
||||
TOTAL_WARN=0
|
||||
TOTAL_INFO=0
|
||||
TOTAL_OK=0
|
||||
|
||||
flag_crit() { ((TOTAL_CRIT++)) || true; }
|
||||
flag_warn() { ((TOTAL_WARN++)) || true; }
|
||||
flag_info() { ((TOTAL_INFO++)) || true; }
|
||||
flag_ok() { ((TOTAL_OK++)) || true; }
|
||||
|
||||
# ── Defaults ──────────────────────────────────────────────────────────
|
||||
RUN_MODE=""
|
||||
VERBOSE="${VERBOSE:-false}"
|
||||
COLOR="${COLOR:-auto}"
|
||||
APACHE_CONF=""
|
||||
APACHECTL=""
|
||||
APACHE_CONF_DIR=""
|
||||
APACHE_RUN_USER=""
|
||||
PLATFORM=""
|
||||
|
||||
# ── State ─────────────────────────────────────────────────────────────
|
||||
SCRIPT_NAME="$(basename "$0")"
|
||||
readonly SCRIPT_NAME
|
||||
START_TIME=""
|
||||
|
||||
# ── Platform detection ───────────────────────────────────────────────
|
||||
detect_platform() {
|
||||
if [[ -n "$APACHE_CONF" ]]; then
|
||||
if command -v apache2ctl &>/dev/null; then
|
||||
APACHECTL="apache2ctl"
|
||||
APACHE_CONF_DIR="$(dirname "$APACHE_CONF")"
|
||||
APACHE_RUN_USER="www-data"
|
||||
PLATFORM="Debian/Ubuntu (apache2)"
|
||||
elif command -v httpd &>/dev/null; then
|
||||
APACHECTL="httpd"
|
||||
APACHE_CONF_DIR="$(dirname "$APACHE_CONF")"
|
||||
APACHE_RUN_USER="apache"
|
||||
PLATFORM="RHEL/CentOS (httpd)"
|
||||
else
|
||||
die "Cannot find apache2ctl or httpd"
|
||||
fi
|
||||
return
|
||||
fi
|
||||
|
||||
if command -v apache2ctl &>/dev/null && [[ -f /etc/apache2/apache2.conf ]]; then
|
||||
APACHECTL="apache2ctl"
|
||||
APACHE_CONF="/etc/apache2/apache2.conf"
|
||||
APACHE_CONF_DIR="/etc/apache2"
|
||||
APACHE_RUN_USER="www-data"
|
||||
PLATFORM="Debian/Ubuntu (apache2)"
|
||||
elif command -v httpd &>/dev/null && [[ -f /etc/httpd/conf/httpd.conf ]]; then
|
||||
APACHECTL="httpd"
|
||||
APACHE_CONF="/etc/httpd/conf/httpd.conf"
|
||||
APACHE_CONF_DIR="/etc/httpd"
|
||||
APACHE_RUN_USER="apache"
|
||||
PLATFORM="RHEL/CentOS (httpd)"
|
||||
else
|
||||
die "Cannot detect Apache installation — use --config to specify config path"
|
||||
fi
|
||||
|
||||
verbose "Platform: ${PLATFORM}"
|
||||
verbose "Config: ${APACHE_CONF}"
|
||||
verbose "Config dir: ${APACHE_CONF_DIR}"
|
||||
}
|
||||
|
||||
# ── Get all config files ─────────────────────────────────────────────
|
||||
get_config_files() {
|
||||
local files=()
|
||||
|
||||
if [[ -f "$APACHE_CONF" ]]; then
|
||||
files+=("$APACHE_CONF")
|
||||
fi
|
||||
|
||||
local included
|
||||
included=$($APACHECTL -t -D DUMP_INCLUDES 2>/dev/null | grep -oP '\(\*\) \K.*|^ *\K/.*' || true)
|
||||
if [[ -n "$included" ]]; then
|
||||
while IFS= read -r f; do
|
||||
[[ -f "$f" ]] && files+=("$f")
|
||||
done <<< "$included"
|
||||
fi
|
||||
|
||||
for d in "${APACHE_CONF_DIR}/sites-enabled" "${APACHE_CONF_DIR}/conf-enabled" \
|
||||
"${APACHE_CONF_DIR}/conf.d" "${APACHE_CONF_DIR}/conf.modules.d"; do
|
||||
if [[ -d "$d" ]]; then
|
||||
while IFS= read -r f; do
|
||||
files+=("$f")
|
||||
done < <(find "$d" -name '*.conf' -type f 2>/dev/null)
|
||||
fi
|
||||
done
|
||||
|
||||
printf '%s\n' "${files[@]}" | sort -u
|
||||
}
|
||||
|
||||
# ── Search across all config files ───────────────────────────────────
|
||||
search_config() {
|
||||
local pattern="$1"
|
||||
local config_files
|
||||
config_files=$(get_config_files)
|
||||
|
||||
while IFS= read -r f; do
|
||||
[[ -z "$f" ]] && continue
|
||||
grep -iP "$pattern" "$f" 2>/dev/null || true
|
||||
done <<< "$config_files"
|
||||
}
|
||||
|
||||
# ── Table header ─────────────────────────────────────────────────────
|
||||
print_table_header() {
|
||||
printf " %-32s %-14s %s\n" "CHECK" "STATUS" "SEVERITY"
|
||||
printf " %s\n" "$(printf '%.0s─' {1..65})"
|
||||
}
|
||||
|
||||
# ── Table row ────────────────────────────────────────────────────────
|
||||
print_row() {
|
||||
local check="$1" status="$2" severity="$3"
|
||||
local color=""
|
||||
case "$severity" in
|
||||
CRITICAL) color="$RED"; flag_crit ;;
|
||||
WARN) color="$YELLOW"; flag_warn ;;
|
||||
INFO) color="$CYAN"; flag_info ;;
|
||||
OK) color="$GREEN"; flag_ok ;;
|
||||
esac
|
||||
printf " %-32s %-14s %b%s%b\n" "$check" "$status" "$color" "$severity" "$RESET"
|
||||
}
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# SERVER INFO AUDIT
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
audit_server_info() {
|
||||
log "Auditing server information exposure..."
|
||||
echo ""
|
||||
print_table_header
|
||||
|
||||
# ServerTokens
|
||||
local tokens
|
||||
tokens=$(search_config '^\s*ServerTokens' | tail -1 | awk '{print $2}')
|
||||
if [[ -z "$tokens" ]]; then
|
||||
print_row "ServerTokens" "Full (default)" "CRITICAL"
|
||||
elif [[ "${tokens,,}" == "prod" || "${tokens,,}" == "productonly" ]]; then
|
||||
print_row "ServerTokens" "Prod" "OK"
|
||||
elif [[ "${tokens,,}" == "major" ]]; then
|
||||
print_row "ServerTokens" "Major" "WARN"
|
||||
else
|
||||
print_row "ServerTokens" "$tokens" "CRITICAL"
|
||||
fi
|
||||
|
||||
# ServerSignature
|
||||
local sig
|
||||
sig=$(search_config '^\s*ServerSignature' | tail -1 | awk '{print $2}')
|
||||
if [[ -z "$sig" ]]; then
|
||||
print_row "ServerSignature" "On (default)" "CRITICAL"
|
||||
elif [[ "${sig,,}" == "off" ]]; then
|
||||
print_row "ServerSignature" "Off" "OK"
|
||||
else
|
||||
print_row "ServerSignature" "$sig" "CRITICAL"
|
||||
fi
|
||||
|
||||
# TraceEnable
|
||||
local trace
|
||||
trace=$(search_config '^\s*TraceEnable' | tail -1 | awk '{print $2}')
|
||||
if [[ -z "$trace" ]]; then
|
||||
print_row "TraceEnable" "On (default)" "WARN"
|
||||
elif [[ "${trace,,}" == "off" ]]; then
|
||||
print_row "TraceEnable" "Off" "OK"
|
||||
else
|
||||
print_row "TraceEnable" "$trace" "WARN"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
}
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# TLS AUDIT
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
audit_tls() {
|
||||
log "Auditing TLS configuration..."
|
||||
echo ""
|
||||
print_table_header
|
||||
|
||||
# Check if mod_ssl is loaded
|
||||
if ! $APACHECTL -M 2>/dev/null | grep -q ssl_module; then
|
||||
print_row "mod_ssl" "not loaded" "INFO"
|
||||
echo ""
|
||||
return
|
||||
fi
|
||||
print_row "mod_ssl" "loaded" "OK"
|
||||
|
||||
# SSLProtocol
|
||||
local proto
|
||||
proto=$(search_config '^\s*SSLProtocol' | tail -1)
|
||||
if [[ -z "$proto" ]]; then
|
||||
print_row "SSLProtocol" "not set (default)" "WARN"
|
||||
else
|
||||
if echo "$proto" | grep -iqP '(\+SSLv3|\+TLSv1\.0|\+TLSv1[^.]|[^-]TLSv1[^.23])'; then
|
||||
print_row "SSLProtocol (legacy)" "enabled" "CRITICAL"
|
||||
elif echo "$proto" | grep -iqP '(\+TLSv1\.1|[^-]TLSv1\.1)'; then
|
||||
print_row "SSLProtocol (TLSv1.1)" "enabled" "CRITICAL"
|
||||
else
|
||||
print_row "SSLProtocol" "modern only" "OK"
|
||||
fi
|
||||
fi
|
||||
|
||||
# SSLCipherSuite
|
||||
local ciphers
|
||||
ciphers=$(search_config '^\s*SSLCipherSuite' | tail -1)
|
||||
if [[ -z "$ciphers" ]]; then
|
||||
print_row "SSLCipherSuite" "not set" "WARN"
|
||||
else
|
||||
print_row "SSLCipherSuite" "configured" "OK"
|
||||
fi
|
||||
|
||||
# SSLHonorCipherOrder
|
||||
local honor
|
||||
honor=$(search_config '^\s*SSLHonorCipherOrder' | tail -1 | awk '{print $2}')
|
||||
if [[ -z "$honor" ]]; then
|
||||
print_row "SSLHonorCipherOrder" "not set" "WARN"
|
||||
elif [[ "${honor,,}" == "on" ]]; then
|
||||
print_row "SSLHonorCipherOrder" "on" "OK"
|
||||
else
|
||||
print_row "SSLHonorCipherOrder" "$honor" "WARN"
|
||||
fi
|
||||
|
||||
# HSTS
|
||||
local hsts
|
||||
hsts=$(search_config 'Strict-Transport-Security')
|
||||
if [[ -z "$hsts" ]]; then
|
||||
print_row "HSTS Header" "missing" "WARN"
|
||||
else
|
||||
print_row "HSTS Header" "set" "OK"
|
||||
fi
|
||||
|
||||
# OCSP Stapling
|
||||
local ocsp
|
||||
ocsp=$(search_config '^\s*SSLUseStapling' | tail -1 | awk '{print $2}')
|
||||
if [[ -z "$ocsp" ]]; then
|
||||
print_row "OCSP Stapling" "not configured" "WARN"
|
||||
elif [[ "${ocsp,,}" == "on" ]]; then
|
||||
print_row "OCSP Stapling" "on" "OK"
|
||||
else
|
||||
print_row "OCSP Stapling" "$ocsp" "WARN"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
}
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# SECURITY HEADERS AUDIT
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
audit_headers() {
|
||||
log "Auditing security headers..."
|
||||
echo ""
|
||||
print_table_header
|
||||
|
||||
# Check if mod_headers is loaded
|
||||
if ! $APACHECTL -M 2>/dev/null | grep -q headers_module; then
|
||||
print_row "mod_headers" "not loaded" "WARN"
|
||||
echo ""
|
||||
return
|
||||
fi
|
||||
|
||||
local headers=(
|
||||
"X-Content-Type-Options"
|
||||
"X-Frame-Options"
|
||||
"Content-Security-Policy"
|
||||
"Referrer-Policy"
|
||||
"Permissions-Policy"
|
||||
)
|
||||
|
||||
for header in "${headers[@]}"; do
|
||||
local found
|
||||
found=$(search_config "Header.*set.*${header}")
|
||||
if [[ -n "$found" ]]; then
|
||||
print_row "$header" "set" "OK"
|
||||
else
|
||||
print_row "$header" "missing" "WARN"
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
}
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# DIRECTORY AUDIT
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
audit_directories() {
|
||||
log "Auditing directory and file restrictions..."
|
||||
echo ""
|
||||
print_table_header
|
||||
|
||||
# Options Indexes (enabled = bad)
|
||||
local indexes_on
|
||||
indexes_on=$(search_config '^\s*Options\b.*\bIndexes\b' | grep -v '\-Indexes' || true)
|
||||
if [[ -n "$indexes_on" ]]; then
|
||||
print_row "Options Indexes" "enabled" "WARN"
|
||||
else
|
||||
print_row "Options Indexes" "disabled" "OK"
|
||||
fi
|
||||
|
||||
# AllowOverride All
|
||||
local override_all
|
||||
override_all=$(search_config '^\s*AllowOverride\s+All' || true)
|
||||
if [[ -n "$override_all" ]]; then
|
||||
print_row "AllowOverride" "All (permissive)" "WARN"
|
||||
else
|
||||
print_row "AllowOverride" "restricted" "OK"
|
||||
fi
|
||||
|
||||
# Sensitive file protection (.git, .env, .htpasswd)
|
||||
local sensitive_protection
|
||||
sensitive_protection=$(search_config '(FilesMatch|Files|Directory).*(\\.git|\\.env|\\.htpasswd)' || true)
|
||||
if [[ -n "$sensitive_protection" ]]; then
|
||||
print_row "Sensitive file blocking" "configured" "OK"
|
||||
else
|
||||
print_row "Sensitive file blocking" "not configured" "CRITICAL"
|
||||
fi
|
||||
|
||||
# Check for root directory restriction
|
||||
local root_deny
|
||||
root_deny=$(search_config '^\s*Require\s+all\s+denied' || true)
|
||||
if [[ -n "$root_deny" ]]; then
|
||||
print_row "Root directory denied" "yes" "OK"
|
||||
else
|
||||
print_row "Root directory denied" "not found" "WARN"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
}
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# MODULES AUDIT
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
audit_modules() {
|
||||
log "Auditing modules..."
|
||||
echo ""
|
||||
print_table_header
|
||||
|
||||
local loaded_modules
|
||||
loaded_modules=$($APACHECTL -M 2>/dev/null || true)
|
||||
|
||||
# mod_security
|
||||
if echo "$loaded_modules" | grep -q "security2_module"; then
|
||||
print_row "mod_security" "loaded" "OK"
|
||||
else
|
||||
print_row "mod_security" "not loaded" "INFO"
|
||||
fi
|
||||
|
||||
# mod_status
|
||||
if echo "$loaded_modules" | grep -q "status_module"; then
|
||||
local status_restricted
|
||||
status_restricted=$(search_config '(<Location\s+/server-status)' || true)
|
||||
if [[ -n "$status_restricted" ]]; then
|
||||
local has_require
|
||||
has_require=$(search_config 'Require\s+(ip|local|host)' || true)
|
||||
if [[ -n "$has_require" ]]; then
|
||||
print_row "mod_status" "restricted" "OK"
|
||||
else
|
||||
print_row "mod_status" "unrestricted" "CRITICAL"
|
||||
fi
|
||||
else
|
||||
print_row "mod_status" "loaded (no location)" "WARN"
|
||||
fi
|
||||
else
|
||||
print_row "mod_status" "not loaded" "OK"
|
||||
fi
|
||||
|
||||
# mod_info
|
||||
if echo "$loaded_modules" | grep -q "info_module"; then
|
||||
print_row "mod_info" "loaded" "WARN"
|
||||
else
|
||||
print_row "mod_info" "not loaded" "OK"
|
||||
fi
|
||||
|
||||
# mod_autoindex
|
||||
if echo "$loaded_modules" | grep -q "autoindex_module"; then
|
||||
print_row "mod_autoindex" "loaded" "WARN"
|
||||
else
|
||||
print_row "mod_autoindex" "not loaded" "OK"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
}
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# PERMISSIONS AUDIT
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
audit_permissions() {
|
||||
log "Auditing file permissions..."
|
||||
echo ""
|
||||
print_table_header
|
||||
|
||||
# Main config file
|
||||
if [[ -f "$APACHE_CONF" ]]; then
|
||||
local conf_perms
|
||||
conf_perms=$(stat -c '%a' "$APACHE_CONF" 2>/dev/null)
|
||||
if [[ "$conf_perms" -le 644 ]]; then
|
||||
print_row "Config ($APACHE_CONF)" "$conf_perms" "OK"
|
||||
else
|
||||
print_row "Config ($APACHE_CONF)" "$conf_perms" "WARN"
|
||||
fi
|
||||
fi
|
||||
|
||||
# .htpasswd files
|
||||
local htpasswd_files
|
||||
htpasswd_files=$(find "$APACHE_CONF_DIR" /var/www -name '.htpasswd' -type f 2>/dev/null || true)
|
||||
if [[ -n "$htpasswd_files" ]]; then
|
||||
while IFS= read -r f; do
|
||||
local perms
|
||||
perms=$(stat -c '%a' "$f" 2>/dev/null)
|
||||
if [[ "$perms" -le 640 ]]; then
|
||||
print_row ".htpasswd ($f)" "$perms" "OK"
|
||||
else
|
||||
print_row ".htpasswd ($f)" "$perms" "WARN"
|
||||
fi
|
||||
done <<< "$htpasswd_files"
|
||||
else
|
||||
verbose "No .htpasswd files found"
|
||||
fi
|
||||
|
||||
# Document root world-writable check
|
||||
local docroots
|
||||
docroots=$(search_config '^\s*DocumentRoot' | awk '{print $2}' | tr -d '"' | sort -u)
|
||||
if [[ -n "$docroots" ]]; then
|
||||
while IFS= read -r dr; do
|
||||
[[ -z "$dr" || ! -d "$dr" ]] && continue
|
||||
local dr_perms
|
||||
dr_perms=$(stat -c '%a' "$dr" 2>/dev/null)
|
||||
if [[ "${dr_perms: -1}" -ge 6 ]]; then
|
||||
print_row "Docroot ($dr)" "${dr_perms} (world-writable)" "CRITICAL"
|
||||
else
|
||||
print_row "Docroot ($dr)" "$dr_perms" "OK"
|
||||
fi
|
||||
done <<< "$docroots"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
}
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# SUMMARY
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
print_summary() {
|
||||
local elapsed
|
||||
elapsed=$(( $(date +%s) - START_TIME ))
|
||||
|
||||
echo ""
|
||||
echo " ══════════════════════════════════════════"
|
||||
echo " Apache Security Audit Summary"
|
||||
echo " ══════════════════════════════════════════"
|
||||
printf " %-20s %b%d%b\n" "CRITICAL:" "$RED" "$TOTAL_CRIT" "$RESET"
|
||||
printf " %-20s %b%d%b\n" "WARN:" "$YELLOW" "$TOTAL_WARN" "$RESET"
|
||||
printf " %-20s %b%d%b\n" "INFO:" "$CYAN" "$TOTAL_INFO" "$RESET"
|
||||
printf " %-20s %b%d%b\n" "OK:" "$GREEN" "$TOTAL_OK" "$RESET"
|
||||
echo " ──────────────────────────────────────────"
|
||||
printf " Completed in %ds\n" "$elapsed"
|
||||
echo ""
|
||||
|
||||
if [[ "$TOTAL_CRIT" -gt 0 ]]; then
|
||||
echo -e " ${RED}${BOLD}Action required:${RESET} ${TOTAL_CRIT} critical finding(s)"
|
||||
echo ""
|
||||
echo " Top recommendations:"
|
||||
echo " • Set ServerTokens Prod and ServerSignature Off"
|
||||
echo " • Disable SSLv3, TLSv1, and TLSv1.1"
|
||||
echo " • Restrict mod_status to localhost with Require ip 127.0.0.1"
|
||||
echo " • Block access to .git, .env, and .htpasswd files"
|
||||
echo " • Fix world-writable document root permissions"
|
||||
echo ""
|
||||
elif [[ "$TOTAL_WARN" -gt 0 ]]; then
|
||||
echo -e " ${YELLOW}Review recommended:${RESET} ${TOTAL_WARN} warning(s)"
|
||||
echo ""
|
||||
echo " Suggestions:"
|
||||
echo " • Add security headers (CSP, X-Frame-Options, HSTS)"
|
||||
echo " • Enable OCSP stapling for TLS"
|
||||
echo " • Disable mod_info and mod_autoindex in production"
|
||||
echo " • Set TraceEnable Off"
|
||||
echo ""
|
||||
else
|
||||
echo -e " ${GREEN}All checks passed${RESET}"
|
||||
echo ""
|
||||
fi
|
||||
}
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# USAGE
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
show_help() {
|
||||
cat <<EOF
|
||||
${BOLD}${SCRIPT_NAME}${RESET} — Apache Security Auditor
|
||||
|
||||
Audit Apache httpd configuration for common security misconfigurations.
|
||||
Read-only — never modifies any files.
|
||||
|
||||
${BOLD}MODES${RESET}
|
||||
--full Run all audit checks
|
||||
--server-info Check ServerTokens, ServerSignature, TraceEnable
|
||||
--tls Check TLS protocols, ciphers, HSTS, OCSP
|
||||
--headers Check security response headers
|
||||
--directories Check directory listing, AllowOverride, sensitive files
|
||||
--modules Check mod_security, mod_status, mod_info, mod_autoindex
|
||||
--permissions Check file permissions on configs and document roots
|
||||
|
||||
${BOLD}OPTIONS${RESET}
|
||||
--config PATH Path to main Apache config file (auto-detect if omitted)
|
||||
--verbose Debug output
|
||||
--no-color Disable colored output
|
||||
--help Show this help message
|
||||
|
||||
${BOLD}EXAMPLES${RESET}
|
||||
# Full audit
|
||||
sudo ${SCRIPT_NAME} --full
|
||||
|
||||
# Check only server info exposure
|
||||
sudo ${SCRIPT_NAME} --server-info
|
||||
|
||||
# Custom config path
|
||||
sudo ${SCRIPT_NAME} --full --config /opt/apache/conf/httpd.conf
|
||||
|
||||
# Pipe-friendly output
|
||||
sudo ${SCRIPT_NAME} --full --no-color
|
||||
|
||||
${BOLD}EXIT CODES${RESET}
|
||||
0 All checks passed
|
||||
1 Warnings found (review recommended)
|
||||
2 Critical findings (action required)
|
||||
EOF
|
||||
}
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# PARSE ARGS
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
parse_args() {
|
||||
local modes=()
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--full)
|
||||
modes=(server-info tls headers directories modules permissions)
|
||||
shift ;;
|
||||
--server-info)
|
||||
modes+=(server-info); shift ;;
|
||||
--tls)
|
||||
modes+=(tls); shift ;;
|
||||
--headers)
|
||||
modes+=(headers); shift ;;
|
||||
--directories)
|
||||
modes+=(directories); shift ;;
|
||||
--modules)
|
||||
modes+=(modules); shift ;;
|
||||
--permissions)
|
||||
modes+=(permissions); shift ;;
|
||||
--config)
|
||||
APACHE_CONF="${2:?--config requires a value}"; shift 2 ;;
|
||||
--verbose)
|
||||
VERBOSE="true"; shift ;;
|
||||
--no-color)
|
||||
COLOR="never"; shift ;;
|
||||
--help|-h)
|
||||
setup_colors; show_help; exit 0 ;;
|
||||
*)
|
||||
die "Unknown option: $1 (see --help)" ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ ${#modes[@]} -eq 0 ]]; then
|
||||
err "No audit mode specified"
|
||||
echo "Run ${SCRIPT_NAME} --help for usage" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
RUN_MODE="${modes[*]}"
|
||||
}
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
# MAIN
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
main() {
|
||||
parse_args "$@"
|
||||
setup_colors
|
||||
detect_platform
|
||||
|
||||
START_TIME=$(date +%s)
|
||||
|
||||
echo ""
|
||||
echo -e "${BOLD}Apache Security Auditor${RESET}"
|
||||
echo -e "Host: $(hostname)"
|
||||
echo -e "Config: ${APACHE_CONF}"
|
||||
echo -e "Platform: ${PLATFORM}"
|
||||
echo -e "Mode: ${RUN_MODE}"
|
||||
echo -e "Time: $(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||
echo ""
|
||||
|
||||
for mode in $RUN_MODE; do
|
||||
case "$mode" in
|
||||
server-info) audit_server_info ;;
|
||||
tls) audit_tls ;;
|
||||
headers) audit_headers ;;
|
||||
directories) audit_directories ;;
|
||||
modules) audit_modules ;;
|
||||
permissions) audit_permissions ;;
|
||||
esac
|
||||
done
|
||||
|
||||
print_summary
|
||||
|
||||
if [[ "$TOTAL_CRIT" -gt 0 ]]; then
|
||||
exit 2
|
||||
elif [[ "$TOTAL_WARN" -gt 0 ]]; then
|
||||
exit 1
|
||||
fi
|
||||
exit 0
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user