# Security hardening commands for Linux VPS # Each function returns a bash command string that app.py executes via ssh_run() def ssh_harden_cmd(port=22, disable_root=True, disable_password=True): """Return bash command to harden SSH config. Backs up sshd_config first.""" root_login = "no" if disable_root else "yes" password_auth = "no" if disable_password else "yes" return ( "cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%Y%m%d_%H%M%S) && " f"sed -i 's/^#\\?Port .*/Port {port}/' /etc/ssh/sshd_config && " f"sed -i 's/^#\\?PermitRootLogin .*/PermitRootLogin {root_login}/' /etc/ssh/sshd_config && " f"sed -i 's/^#\\?PasswordAuthentication .*/PasswordAuthentication {password_auth}/' /etc/ssh/sshd_config && " "sed -i 's/^#\\?PubkeyAuthentication .*/PubkeyAuthentication yes/' /etc/ssh/sshd_config && " "sed -i 's/^#\\?X11Forwarding .*/X11Forwarding no/' /etc/ssh/sshd_config && " "sed -i 's/^#\\?MaxAuthTries .*/MaxAuthTries 3/' /etc/ssh/sshd_config && " "sed -i 's/^#\\?AllowAgentForwarding .*/AllowAgentForwarding no/' /etc/ssh/sshd_config && " "grep -q '^Port ' /etc/ssh/sshd_config || echo 'Port {port}' >> /etc/ssh/sshd_config && ".format(port=port) + "grep -q '^PermitRootLogin ' /etc/ssh/sshd_config || echo 'PermitRootLogin {root}' >> /etc/ssh/sshd_config && ".format(root=root_login) + "grep -q '^PasswordAuthentication ' /etc/ssh/sshd_config || echo 'PasswordAuthentication {pw}' >> /etc/ssh/sshd_config && ".format(pw=password_auth) + "grep -q '^PubkeyAuthentication ' /etc/ssh/sshd_config || echo 'PubkeyAuthentication yes' >> /etc/ssh/sshd_config && " "sshd -t 2>&1 && " "systemctl restart sshd 2>&1 && " "echo 'SSH hardened: Port={port}, RootLogin={root}, PasswordAuth={pw}'".format( port=port, root=root_login, pw=password_auth ) ) def kernel_harden_cmd(): """Return bash command to apply kernel hardening via sysctl.""" sysctl_conf = ( "# Setec Labs kernel hardening\\n" "net.ipv4.tcp_syncookies = 1\\n" "net.ipv4.conf.all.rp_filter = 1\\n" "net.ipv4.icmp_echo_ignore_broadcasts = 1\\n" "net.ipv4.conf.all.accept_redirects = 0\\n" "net.ipv4.conf.all.send_redirects = 0\\n" "net.ipv4.conf.all.accept_source_route = 0\\n" "net.ipv6.conf.all.accept_redirects = 0\\n" "kernel.randomize_va_space = 2\\n" "net.ipv4.tcp_max_syn_backlog = 2048\\n" "net.ipv4.tcp_synack_retries = 2\\n" "fs.protected_hardlinks = 1\\n" "fs.protected_symlinks = 1" ) return ( "cp /etc/sysctl.d/99-hardening.conf /etc/sysctl.d/99-hardening.conf.bak.$(date +%Y%m%d_%H%M%S) 2>/dev/null; " f"echo -e '{sysctl_conf}' > /etc/sysctl.d/99-hardening.conf && " "sysctl --system 2>&1 && " "echo 'Kernel hardening applied via /etc/sysctl.d/99-hardening.conf'" ) def auto_updates_cmd(): """Return bash cmd to install and configure unattended-upgrades.""" return ( "DEBIAN_FRONTEND=noninteractive apt-get install -y unattended-upgrades apt-listchanges 2>&1 && " "cat > /etc/apt/apt.conf.d/20auto-upgrades << 'EOF'\n" 'APT::Periodic::Update-Package-Lists "1";\n' 'APT::Periodic::Unattended-Upgrade "1";\n' 'APT::Periodic::AutocleanInterval "7";\n' "EOF\n" "cat > /etc/apt/apt.conf.d/50unattended-upgrades << 'EOF'\n" "Unattended-Upgrade::Allowed-Origins {\n" ' \"${distro_id}:${distro_codename}\";\n' ' \"${distro_id}:${distro_codename}-security\";\n' ' \"${distro_id}ESMApps:${distro_codename}-apps-security\";\n' ' \"${distro_id}ESM:${distro_codename}-infra-security\";\n' "};\n" 'Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";\n' 'Unattended-Upgrade::Remove-Unused-Dependencies "true";\n' 'Unattended-Upgrade::Automatic-Reboot "false";\n' "EOF\n" "systemctl enable unattended-upgrades 2>&1 && " "systemctl restart unattended-upgrades 2>&1 && " "echo 'Unattended upgrades configured and enabled'" ) def firewall_status_cmd(): """Return bash cmd to get UFW status verbose.""" return "ufw status verbose 2>&1" def firewall_enable_cmd(ssh_port=22): """Return bash cmd to enable UFW with sensible defaults.""" return ( "apt-get install -y ufw 2>&1 && " "ufw default deny incoming 2>&1 && " "ufw default allow outgoing 2>&1 && " f"ufw allow {ssh_port}/tcp comment 'SSH' 2>&1 && " "ufw allow 80/tcp comment 'HTTP' 2>&1 && " "ufw allow 443/tcp comment 'HTTPS' 2>&1 && " "echo 'y' | ufw enable 2>&1 && " "ufw status verbose 2>&1" ) def firewall_add_rule_cmd(rule): """Return bash cmd to add a UFW rule (e.g. 'allow 8080/tcp').""" return f"ufw {rule} 2>&1 && ufw status numbered 2>&1" def firewall_delete_rule_cmd(rule): """Return bash cmd to delete a UFW rule.""" return f"echo 'y' | ufw delete {rule} 2>&1 && ufw status numbered 2>&1" def firewall_preset_cmd(preset): """Return bash cmd for common firewall presets.""" presets = { "webserver": ( "ufw default deny incoming 2>&1 && " "ufw default allow outgoing 2>&1 && " "ufw allow 22/tcp comment 'SSH' 2>&1 && " "ufw allow 80/tcp comment 'HTTP' 2>&1 && " "ufw allow 443/tcp comment 'HTTPS' 2>&1 && " "echo 'y' | ufw enable 2>&1 && " "echo 'Webserver preset applied' && ufw status verbose 2>&1" ), "mailserver": ( "ufw default deny incoming 2>&1 && " "ufw default allow outgoing 2>&1 && " "ufw allow 22/tcp comment 'SSH' 2>&1 && " "ufw allow 25/tcp comment 'SMTP' 2>&1 && " "ufw allow 80/tcp comment 'HTTP' 2>&1 && " "ufw allow 443/tcp comment 'HTTPS' 2>&1 && " "ufw allow 465/tcp comment 'SMTPS' 2>&1 && " "ufw allow 587/tcp comment 'Submission' 2>&1 && " "ufw allow 993/tcp comment 'IMAPS' 2>&1 && " "echo 'y' | ufw enable 2>&1 && " "echo 'Mailserver preset applied' && ufw status verbose 2>&1" ), "lockdown": ( "ufw default deny incoming 2>&1 && " "ufw default deny outgoing 2>&1 && " "ufw allow out 53 comment 'DNS' 2>&1 && " "ufw allow out 80/tcp comment 'HTTP out' 2>&1 && " "ufw allow out 443/tcp comment 'HTTPS out' 2>&1 && " "ufw allow 22/tcp comment 'SSH' 2>&1 && " "echo 'y' | ufw enable 2>&1 && " "echo 'Lockdown preset applied - SSH only inbound' && ufw status verbose 2>&1" ), } if preset not in presets: return f"echo 'Unknown preset: {preset}. Available: webserver, mailserver, lockdown'" return presets[preset] def user_audit_cmd(): """Return bash cmd to audit users, SUID binaries, world-writable files, sudoers, recent logins.""" return ( "echo '=== USERS WITH SHELLS ===' && " "grep -v '/nologin\\|/false\\|/sync' /etc/passwd | cut -d: -f1,6,7 && " "echo '' && echo '=== SUDOERS ===' && " "getent group sudo 2>/dev/null | cut -d: -f4 && " "cat /etc/sudoers.d/* 2>/dev/null | grep -v '^#' | grep -v '^$' && " "echo '' && echo '=== UID 0 ACCOUNTS ===' && " "awk -F: '$3 == 0 {print $1}' /etc/passwd && " "echo '' && echo '=== SUID BINARIES ===' && " "find / -perm -4000 -type f 2>/dev/null | head -30 && " "echo '' && echo '=== WORLD-WRITABLE FILES (non /proc /sys /dev) ===' && " "find / -xdev -type f -perm -0002 2>/dev/null | head -20 && " "echo '' && echo '=== RECENT LOGINS ===' && " "last -n 15 2>/dev/null && " "echo '' && echo '=== FAILED LOGIN ATTEMPTS ===' && " "lastb -n 15 2>/dev/null || journalctl _SYSTEMD_UNIT=sshd.service --no-pager -n 15 2>/dev/null" ) def port_scan_cmd(): """Return bash cmd to scan open ports with ss.""" return ( "echo '=== LISTENING PORTS ===' && " "ss -tlnp 2>&1 && " "echo '' && echo '=== UDP LISTENERS ===' && " "ss -ulnp 2>&1 && " "echo '' && echo '=== ESTABLISHED CONNECTIONS ===' && " "ss -tnp state established 2>&1 | head -30" ) def ssh_status_cmd(): """Return bash cmd to show current SSH config settings.""" return ( "echo '=== SSHD CONFIG ===' && " "grep -E '^(Port|PermitRootLogin|PasswordAuthentication|PubkeyAuthentication|" "X11Forwarding|MaxAuthTries|AllowUsers|AllowGroups|Protocol|LoginGraceTime)' " "/etc/ssh/sshd_config 2>/dev/null && " "echo '' && echo '=== SSHD STATUS ===' && " "systemctl status sshd --no-pager -l 2>&1 | head -15 && " "echo '' && echo '=== AUTHORIZED KEYS ===' && " "for u in $(awk -F: '$3>=1000{print $1}' /etc/passwd) root; do " " f=\"/home/$u/.ssh/authorized_keys\"; " " [ \"$u\" = 'root' ] && f='/root/.ssh/authorized_keys'; " " if [ -f \"$f\" ]; then echo \"$u: $(wc -l < \"$f\") keys\"; fi; " "done" ) def kernel_status_cmd(): """Return bash cmd to show current sysctl security settings.""" return ( "echo '=== SYSCTL SECURITY SETTINGS ===' && " "sysctl net.ipv4.tcp_syncookies " "net.ipv4.conf.all.rp_filter " "net.ipv4.icmp_echo_ignore_broadcasts " "net.ipv4.conf.all.accept_redirects " "net.ipv4.conf.all.send_redirects " "net.ipv4.conf.all.accept_source_route " "net.ipv6.conf.all.accept_redirects " "kernel.randomize_va_space " "net.ipv4.tcp_max_syn_backlog " "net.ipv4.tcp_synack_retries " "fs.protected_hardlinks " "fs.protected_symlinks 2>&1 && " "echo '' && echo '=== HARDENING CONFIG FILE ===' && " "cat /etc/sysctl.d/99-hardening.conf 2>/dev/null || echo 'No hardening config found'" )