Scripts for deploying a hardened internal network security scanner on Proxmox VE: - PVE-level firewall and VM creation - System hardening (sysctl, auditd, AIDE) - nftables firewall with dynamic IP blocking - SSH hardening with fail2ban - Security tools (OpenVAS, Nmap, Nuclei, httpx, Nikto, testssl, NetExec) - Monitoring, logging, and Docker autostart
477 lines
14 KiB
Bash
477 lines
14 KiB
Bash
#!/bin/bash
|
|
# =============================================================================
|
|
# Security Scanning Tools Installation
|
|
# Run this inside the VM as root
|
|
# =============================================================================
|
|
set -euo pipefail
|
|
|
|
echo "============================================"
|
|
echo " Security Tools - Installation"
|
|
echo "============================================"
|
|
|
|
# --- 1. Base dependencies ---
|
|
echo "[+] Installing base dependencies..."
|
|
apt install -y \
|
|
curl wget git \
|
|
net-tools iproute2 \
|
|
dnsutils whois \
|
|
python3 python3-pip python3-venv \
|
|
jq tmux htop \
|
|
ca-certificates gnupg
|
|
|
|
# --- 2. Docker (for Greenbone OpenVAS) ---
|
|
if ! command -v docker &>/dev/null; then
|
|
echo "[+] Installing Docker..."
|
|
install -m 0755 -d /etc/apt/keyrings
|
|
curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
|
|
chmod 644 /etc/apt/keyrings/docker.asc
|
|
|
|
# Detect distro (debian or ubuntu)
|
|
. /etc/os-release
|
|
DOCKER_DISTRO="${ID}" # "debian" or "ubuntu"
|
|
DOCKER_CODENAME="${VERSION_CODENAME}"
|
|
echo \
|
|
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] \
|
|
https://download.docker.com/linux/${DOCKER_DISTRO} \
|
|
${DOCKER_CODENAME} stable" | \
|
|
tee /etc/apt/sources.list.d/docker.list > /dev/null
|
|
|
|
apt update
|
|
apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
|
|
systemctl enable docker
|
|
fi
|
|
|
|
# --- 3. Nmap (network scanner) ---
|
|
echo "[+] Installing Nmap..."
|
|
apt install -y nmap
|
|
|
|
# --- Helper: download and verify binary from GitHub ---
|
|
install_github_binary() {
|
|
local REPO="$1" # e.g., projectdiscovery/nuclei
|
|
local NAME="$2" # e.g., nuclei
|
|
local ARCH="linux_amd64"
|
|
|
|
echo "[+] Installing ${NAME}..."
|
|
local VERSION
|
|
VERSION=$(curl -s "https://api.github.com/repos/${REPO}/releases/latest" | jq -r '.tag_name' | sed 's/^v//')
|
|
|
|
local ZIP_URL="https://github.com/${REPO}/releases/download/v${VERSION}/${NAME}_${VERSION}_${ARCH}.zip"
|
|
local CHECKSUM_URL="https://github.com/${REPO}/releases/download/v${VERSION}/${NAME}_${VERSION}_checksums.txt"
|
|
|
|
wget -q "${ZIP_URL}" -O "/tmp/${NAME}.zip"
|
|
wget -q "${CHECKSUM_URL}" -O "/tmp/${NAME}_checksums.txt"
|
|
|
|
# Verify checksum
|
|
local EXPECTED_SHA
|
|
EXPECTED_SHA=$(grep "${ARCH}.zip" "/tmp/${NAME}_checksums.txt" | awk '{print $1}')
|
|
local ACTUAL_SHA
|
|
ACTUAL_SHA=$(sha256sum "/tmp/${NAME}.zip" | awk '{print $1}')
|
|
|
|
if [[ "${EXPECTED_SHA}" != "${ACTUAL_SHA}" ]]; then
|
|
echo "[ERROR] Checksum verification failed for ${NAME}!" >&2
|
|
echo " Expected: ${EXPECTED_SHA}" >&2
|
|
echo " Actual: ${ACTUAL_SHA}" >&2
|
|
rm -f "/tmp/${NAME}.zip" "/tmp/${NAME}_checksums.txt"
|
|
return 1
|
|
fi
|
|
echo " Checksum verified for ${NAME} v${VERSION}"
|
|
|
|
unzip -o "/tmp/${NAME}.zip" -d "/tmp/${NAME}-bin"
|
|
mv "/tmp/${NAME}-bin/${NAME}" "/usr/local/bin/${NAME}"
|
|
chmod +x "/usr/local/bin/${NAME}"
|
|
rm -rf "/tmp/${NAME}.zip" "/tmp/${NAME}-bin" "/tmp/${NAME}_checksums.txt"
|
|
}
|
|
|
|
# --- 4. Nuclei (fast vulnerability scanner) ---
|
|
install_github_binary "projectdiscovery/nuclei" "nuclei"
|
|
|
|
# Update Nuclei templates
|
|
nuclei -update-templates 2>&1 | logger -t nuclei-setup || true
|
|
|
|
# --- 5. httpx (HTTP toolkit) ---
|
|
install_github_binary "projectdiscovery/httpx" "httpx"
|
|
|
|
# --- 6. Nikto (web server scanner) ---
|
|
echo "[+] Installing Nikto..."
|
|
apt install -y nikto
|
|
|
|
# --- 7. testssl.sh (TLS/SSL testing) ---
|
|
echo "[+] Installing testssl.sh..."
|
|
git clone --depth 1 https://github.com/drwetter/testssl.sh.git /opt/testssl
|
|
ln -sf /opt/testssl/testssl.sh /usr/local/bin/testssl
|
|
|
|
# --- 8. CrackMapExec / NetExec (network assessment) ---
|
|
echo "[+] Installing NetExec..."
|
|
python3 -m pip install --break-system-packages netexec 2>/dev/null || \
|
|
pipx install netexec 2>/dev/null || \
|
|
echo "[!] NetExec install failed - install manually if needed"
|
|
|
|
# --- 9. Greenbone OpenVAS (Docker Compose) ---
|
|
echo "[+] Setting up Greenbone OpenVAS..."
|
|
mkdir -p /opt/greenbone
|
|
cat > /opt/greenbone/docker-compose.yml << 'COMPEOF'
|
|
name: greenbone-community-edition
|
|
|
|
services:
|
|
vulnerability-tests:
|
|
image: registry.community.greenbone.net/community/vulnerability-tests
|
|
environment:
|
|
FEED_RELEASE: "24.10"
|
|
KEEP_ALIVE: 1
|
|
volumes:
|
|
- vt_data_vol:/mnt
|
|
|
|
notus-data:
|
|
image: registry.community.greenbone.net/community/notus-data
|
|
environment:
|
|
KEEP_ALIVE: 1
|
|
volumes:
|
|
- notus_data_vol:/mnt
|
|
|
|
scap-data:
|
|
image: registry.community.greenbone.net/community/scap-data
|
|
environment:
|
|
KEEP_ALIVE: 1
|
|
volumes:
|
|
- scap_data_vol:/mnt
|
|
|
|
cert-bund-data:
|
|
image: registry.community.greenbone.net/community/cert-bund-data
|
|
environment:
|
|
KEEP_ALIVE: 1
|
|
volumes:
|
|
- cert_data_vol:/mnt
|
|
|
|
dfn-cert-data:
|
|
image: registry.community.greenbone.net/community/dfn-cert-data
|
|
environment:
|
|
KEEP_ALIVE: 1
|
|
volumes:
|
|
- cert_data_vol:/mnt
|
|
depends_on:
|
|
cert-bund-data:
|
|
condition: service_healthy
|
|
|
|
data-objects:
|
|
image: registry.community.greenbone.net/community/data-objects
|
|
environment:
|
|
FEED_RELEASE: "24.10"
|
|
KEEP_ALIVE: 1
|
|
volumes:
|
|
- data_objects_vol:/mnt
|
|
|
|
report-formats:
|
|
image: registry.community.greenbone.net/community/report-formats
|
|
environment:
|
|
FEED_RELEASE: "24.10"
|
|
KEEP_ALIVE: 1
|
|
volumes:
|
|
- data_objects_vol:/mnt
|
|
depends_on:
|
|
data-objects:
|
|
condition: service_healthy
|
|
|
|
gpg-data:
|
|
image: registry.community.greenbone.net/community/gpg-data
|
|
volumes:
|
|
- gpg_data_vol:/mnt
|
|
|
|
redis-server:
|
|
image: registry.community.greenbone.net/community/redis-server
|
|
restart: on-failure
|
|
volumes:
|
|
- redis_socket_vol:/run/redis/
|
|
|
|
pg-gvm-migrator:
|
|
image: registry.community.greenbone.net/community/pg-gvm-migrator:stable
|
|
restart: "no"
|
|
volumes:
|
|
- psql_data_vol:/var/lib/postgresql
|
|
- psql_socket_vol:/var/run/postgresql
|
|
|
|
pg-gvm:
|
|
image: registry.community.greenbone.net/community/pg-gvm:stable
|
|
restart: on-failure:10
|
|
volumes:
|
|
- psql_data_vol:/var/lib/postgresql
|
|
- psql_socket_vol:/var/run/postgresql
|
|
depends_on:
|
|
pg-gvm-migrator:
|
|
condition: service_completed_successfully
|
|
|
|
gvmd:
|
|
image: registry.community.greenbone.net/community/gvmd:stable
|
|
restart: on-failure
|
|
volumes:
|
|
- gvmd_data_vol:/var/lib/gvm
|
|
- scap_data_vol:/var/lib/gvm/scap-data/
|
|
- cert_data_vol:/var/lib/gvm/cert-data
|
|
- data_objects_vol:/var/lib/gvm/data-objects/gvmd
|
|
- vt_data_vol:/var/lib/openvas/plugins
|
|
- psql_data_vol:/var/lib/postgresql
|
|
- gvmd_socket_vol:/run/gvmd
|
|
- ospd_openvas_socket_vol:/run/ospd
|
|
- psql_socket_vol:/var/run/postgresql
|
|
depends_on:
|
|
pg-gvm:
|
|
condition: service_started
|
|
scap-data:
|
|
condition: service_healthy
|
|
cert-bund-data:
|
|
condition: service_healthy
|
|
dfn-cert-data:
|
|
condition: service_healthy
|
|
data-objects:
|
|
condition: service_healthy
|
|
report-formats:
|
|
condition: service_healthy
|
|
|
|
gsa:
|
|
image: registry.community.greenbone.net/community/gsa:stable-slim
|
|
environment:
|
|
MOUNT_PATH: "/mnt/web"
|
|
KEEP_ALIVE: 1
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "test -e /run/gsa/copying.done"]
|
|
start_period: 5s
|
|
volumes:
|
|
- gsa_data_vol:/mnt/web
|
|
|
|
gsad:
|
|
image: registry.community.greenbone.net/community/gsad:stable
|
|
restart: on-failure
|
|
environment:
|
|
GSAD_ARGS: "--listen=0.0.0.0 --http-only --api-only -f"
|
|
volumes:
|
|
- gvmd_socket_vol:/run/gvmd
|
|
depends_on:
|
|
gvmd:
|
|
condition: service_started
|
|
|
|
gvm-config:
|
|
image: registry.community.greenbone.net/community/gvm-config:latest
|
|
environment:
|
|
ENABLE_NGINX_CONFIG: "true"
|
|
ENABLE_TLS_GENERATION: "true"
|
|
volumes:
|
|
- nginx_config_vol:/mnt/nginx/configs
|
|
- nginx_certificates_vol:/mnt/nginx/certs
|
|
|
|
nginx:
|
|
image: registry.community.greenbone.net/community/nginx:latest
|
|
ports:
|
|
- "0.0.0.0:9392:9392"
|
|
volumes:
|
|
- nginx_config_vol:/etc/nginx/conf.d:ro
|
|
- nginx_certificates_vol:/etc/nginx/certs:ro
|
|
- gsa_data_vol:/usr/share/nginx/html:ro
|
|
depends_on:
|
|
gvm-config:
|
|
condition: service_completed_successfully
|
|
gsa:
|
|
condition: service_healthy
|
|
gsad:
|
|
condition: service_started
|
|
|
|
configure-openvas:
|
|
image: registry.community.greenbone.net/community/openvas-scanner:stable
|
|
volumes:
|
|
- openvas_data_vol:/mnt
|
|
- openvas_log_data_vol:/var/log/openvas
|
|
command:
|
|
- /bin/sh
|
|
- -c
|
|
- |
|
|
printf "table_driven_lsc = yes\nopenvasd_server = http://openvasd:80\n" > /mnt/openvas.conf
|
|
sed "s/127/128/" /etc/openvas/openvas_log.conf | sed 's/gvm/openvas/' > /mnt/openvas_log.conf
|
|
chmod 644 /mnt/openvas.conf
|
|
chmod 644 /mnt/openvas_log.conf
|
|
touch /var/log/openvas/openvas.log
|
|
chmod 666 /var/log/openvas/openvas.log
|
|
|
|
openvas:
|
|
image: registry.community.greenbone.net/community/openvas-scanner:stable
|
|
restart: on-failure
|
|
volumes:
|
|
- openvas_data_vol:/etc/openvas
|
|
- openvas_log_data_vol:/var/log/openvas
|
|
command:
|
|
- /bin/sh
|
|
- -c
|
|
- |
|
|
cat /etc/openvas/openvas.conf
|
|
tail -f /var/log/openvas/openvas.log
|
|
depends_on:
|
|
configure-openvas:
|
|
condition: service_completed_successfully
|
|
|
|
openvasd:
|
|
image: registry.community.greenbone.net/community/openvas-scanner:stable
|
|
restart: on-failure
|
|
environment:
|
|
OPENVASD_MODE: service_notus
|
|
GNUPGHOME: /etc/openvas/gnupg
|
|
LISTENING: 0.0.0.0:80
|
|
volumes:
|
|
- openvas_data_vol:/etc/openvas
|
|
- openvas_log_data_vol:/var/log/openvas
|
|
- gpg_data_vol:/etc/openvas/gnupg
|
|
- notus_data_vol:/var/lib/notus
|
|
depends_on:
|
|
vulnerability-tests:
|
|
condition: service_healthy
|
|
notus-data:
|
|
condition: service_healthy
|
|
configure-openvas:
|
|
condition: service_completed_successfully
|
|
gpg-data:
|
|
condition: service_completed_successfully
|
|
networks:
|
|
default:
|
|
aliases:
|
|
- openvasd
|
|
|
|
ospd-openvas:
|
|
image: registry.community.greenbone.net/community/ospd-openvas:stable
|
|
restart: on-failure
|
|
hostname: ospd-openvas.local
|
|
# SECURITY NOTE: NET_ADMIN, NET_RAW, and seccomp=unconfined are required
|
|
# for raw packet scanning (SYN scans, OS detection). Risk is mitigated by
|
|
# host-level nftables, PVE firewall, and VM-level isolation.
|
|
cap_add:
|
|
- NET_ADMIN
|
|
- NET_RAW
|
|
security_opt:
|
|
- seccomp=unconfined
|
|
- apparmor=unconfined
|
|
command:
|
|
[
|
|
"ospd-openvas",
|
|
"-f",
|
|
"--config",
|
|
"/etc/gvm/ospd-openvas.conf",
|
|
"--notus-feed-dir",
|
|
"/var/lib/notus/advisories",
|
|
"-m",
|
|
"666",
|
|
]
|
|
volumes:
|
|
- gpg_data_vol:/etc/openvas/gnupg
|
|
- vt_data_vol:/var/lib/openvas/plugins
|
|
- notus_data_vol:/var/lib/notus
|
|
- ospd_openvas_socket_vol:/run/ospd
|
|
- redis_socket_vol:/run/redis/
|
|
- openvas_data_vol:/etc/openvas/
|
|
- openvas_log_data_vol:/var/log/openvas
|
|
depends_on:
|
|
redis-server:
|
|
condition: service_started
|
|
gpg-data:
|
|
condition: service_completed_successfully
|
|
configure-openvas:
|
|
condition: service_completed_successfully
|
|
vulnerability-tests:
|
|
condition: service_healthy
|
|
notus-data:
|
|
condition: service_healthy
|
|
|
|
gvm-tools:
|
|
image: registry.community.greenbone.net/community/gvm-tools
|
|
volumes:
|
|
- gvmd_socket_vol:/run/gvmd
|
|
- ospd_openvas_socket_vol:/run/ospd
|
|
depends_on:
|
|
- gvmd
|
|
- ospd-openvas
|
|
|
|
volumes:
|
|
gpg_data_vol:
|
|
scap_data_vol:
|
|
cert_data_vol:
|
|
data_objects_vol:
|
|
gvmd_data_vol:
|
|
psql_data_vol:
|
|
vt_data_vol:
|
|
notus_data_vol:
|
|
psql_socket_vol:
|
|
gvmd_socket_vol:
|
|
ospd_openvas_socket_vol:
|
|
redis_socket_vol:
|
|
openvas_data_vol:
|
|
openvas_log_data_vol:
|
|
gsa_data_vol:
|
|
nginx_config_vol:
|
|
nginx_certificates_vol:
|
|
COMPEOF
|
|
|
|
# --- 10. Create scan scripts directory ---
|
|
mkdir -p /opt/scans/{results,scripts}
|
|
|
|
# Quick scan helper script
|
|
cat > /opt/scans/scripts/quick-scan.sh << 'SCANEOF'
|
|
#!/bin/bash
|
|
# Quick internal network scan
|
|
# Usage: ./quick-scan.sh 192.168.1.0/24
|
|
set -euo pipefail
|
|
|
|
TARGET="${1:?Usage: $0 <target-subnet>}"
|
|
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
|
|
RESULTS_DIR="/opt/scans/results/${TIMESTAMP}"
|
|
mkdir -p "${RESULTS_DIR}"
|
|
|
|
echo "[+] Starting quick scan of ${TARGET}"
|
|
echo "[+] Results will be saved to ${RESULTS_DIR}"
|
|
|
|
# Step 1: Host discovery
|
|
echo "[+] Step 1/4: Host discovery..."
|
|
nmap -sn "${TARGET}" -oG "${RESULTS_DIR}/hosts-alive.gnmap"
|
|
HOSTS=$(grep "Up" "${RESULTS_DIR}/hosts-alive.gnmap" | awk '{print $2}')
|
|
echo "${HOSTS}" > "${RESULTS_DIR}/hosts-alive.txt"
|
|
HOST_COUNT=$(wc -l < "${RESULTS_DIR}/hosts-alive.txt")
|
|
echo " Found ${HOST_COUNT} alive hosts"
|
|
|
|
# Step 2: Port scan top 1000
|
|
echo "[+] Step 2/4: Port scanning (top 1000 ports)..."
|
|
nmap -sV --script=safe -T4 --top-ports 1000 -iL "${RESULTS_DIR}/hosts-alive.txt" \
|
|
-oA "${RESULTS_DIR}/port-scan"
|
|
|
|
# Step 3: HTTP service detection
|
|
echo "[+] Step 3/4: HTTP service detection..."
|
|
grep -oP '\d+\.\d+\.\d+\.\d+' "${RESULTS_DIR}/hosts-alive.txt" | \
|
|
httpx -silent -ports 80,443,8080,8443,9090 -o "${RESULTS_DIR}/http-services.txt" 2>/dev/null || true
|
|
|
|
# Step 4: Nuclei scan on HTTP services
|
|
if [ -s "${RESULTS_DIR}/http-services.txt" ]; then
|
|
echo "[+] Step 4/4: Vulnerability scanning with Nuclei..."
|
|
nuclei -l "${RESULTS_DIR}/http-services.txt" \
|
|
-severity medium,high,critical \
|
|
-o "${RESULTS_DIR}/nuclei-findings.txt" 2>/dev/null || true
|
|
else
|
|
echo "[+] Step 4/4: No HTTP services found, skipping Nuclei."
|
|
fi
|
|
|
|
echo ""
|
|
echo "[+] Scan complete. Results in: ${RESULTS_DIR}"
|
|
echo " - hosts-alive.txt: Live hosts"
|
|
echo " - port-scan.*: Port scan results"
|
|
echo " - http-services.txt: HTTP endpoints"
|
|
echo " - nuclei-findings.txt: Vulnerabilities found"
|
|
SCANEOF
|
|
chmod +x /opt/scans/scripts/quick-scan.sh
|
|
|
|
echo ""
|
|
echo "[+] All security tools installed."
|
|
echo ""
|
|
echo "Tool summary:"
|
|
echo " nmap - Network discovery and port scanning"
|
|
echo " nuclei - Fast vulnerability scanner"
|
|
echo " httpx - HTTP probing"
|
|
echo " nikto - Web server scanner"
|
|
echo " testssl - TLS/SSL testing"
|
|
echo " netexec - Network assessment (SMB, RDP, etc.)"
|
|
echo " OpenVAS (Docker) - Full vulnerability management"
|
|
echo ""
|
|
echo "Quick start:"
|
|
echo " cd /opt/greenbone && docker compose up -d # Start OpenVAS"
|
|
echo " /opt/scans/scripts/quick-scan.sh 192.168.1.0/24 # Quick scan"
|