In early 2026, a misconfigured SSH daemon on an internet-facing Ubuntu 24.04 box led to a credential-stuffing attack that compromised a mid-sized SaaS provider — root access gained in under four minutes. The box had no login rate-limiting, password auth still enabled, and a world-readable /etc/shadow backup sitting in /tmp. None of it was exotic. All of it was preventable.
This checklist skips the theory. Every item has a command you can run right now on prod-web01.example.internal (192.0.2.41) or any server you manage.
1. Lock Down SSH Before Anything Else
SSH is still the most-abused entry point on Linux servers. Before touching anything else, audit your current config and enforce sane defaults.
Run this to see your live, effective SSH settings — not just what’s in the config file:
sshd -T | grep -E 'permitrootlogin|passwordauthentication|maxauthtries|pubkeyauthentication|x11forwarding'
On a freshly provisioned cloud instance, you might see:
permitrootlogin yes
passwordauthentication yes
maxauthtries 6
pubkeyauthentication yes
x11forwarding yes
That output is a four-alarm fire. Root login enabled, password auth on, six attempts before lockout, X11 forwarding open — any automated scanner will find and probe this within minutes of the IP going live. Open /etc/ssh/sshd_config and set these immediately:
PermitRootLogin no
PasswordAuthentication no
MaxAuthTries 3
X11Forwarding no
AllowUsers deploy@192.0.2.0/24
The AllowUsers directive is underused. It restricts SSH to a specific user and source subnet in one line. After saving, reload without dropping your session:
sshd -t && systemctl reload sshd
sshd -t validates the config before applying it. A syntax error here used to lock admins out permanently. Run it every single time.
Next, install fail2ban — a daemon that reads auth logs and bans IPs after repeated failures — and enable the SSH jail:
apt install fail2ban -y
cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
In /etc/fail2ban/jail.local, set maxretry = 3 and bantime = 3600 under [sshd]. Restart fail2ban and verify it’s watching:
fail2ban-client status sshd
2. Audit Running Services and Open Ports
Every open port is an attack surface. Most compromised servers have services nobody remembers enabling. Run a full socket audit with ss — the modern replacement for netstat:
ss -tlnp
Here’s what came back on prod-web01 after a routine check:
State Recv-Q Send-Q Local Address:Port Process
LISTEN 0 128 0.0.0.0:22 users:(("sshd",pid=1042))
LISTEN 0 511 0.0.0.0:80 users:(("nginx",pid=2310))
LISTEN 0 511 0.0.0.0:443 users:(("nginx",pid=2310))
LISTEN 0 128 127.0.0.1:5432 users:(("postgres",pid=3417))
LISTEN 0 128 0.0.0.0:6379 users:(("redis-server",pid=3601))
Postgres is bound to localhost — good. Redis is bound to 0.0.0.0 — catastrophic. An unauthenticated Redis instance on a public IP is a full takeover waiting to happen. CVE-2022-0543 and its predecessors showed exactly how that ends. Fix it immediately:
sed -i 's/^bind 0.0.0.0/bind 127.0.0.1/' /etc/redis/redis.conf
systemctl restart redis-server
Then confirm it’s no longer listening externally:
ss -tlnp | grep 6379
# Expected: 127.0.0.1:6379
For services you don’t recognize, map the PID to a binary fast:
ls -la /proc/3601/exe
If you don’t know what a service is, it probably shouldn’t be there. Disable and mask it:
systemctl disable --now mystery-service
systemctl mask mystery-service
3. Enforce Least Privilege With File Permissions and sudo
Privilege escalation almost always exploits a misconfigured SUID binary or an overly permissive sudoers entry. Find dangerous SUID files first:
find / -perm -4000 -type f 2>/dev/null | sort
Compare your output against a known-good baseline for your distro. Anything unexpected — especially custom binaries or scripts with SUID set — is a red flag. Remove the SUID bit from anything that doesn’t absolutely need it:
chmod u-s /usr/local/bin/suspicious-tool
Now audit sudo access. This command shows every rule currently in effect — not just the file, but all drop-in configs in /etc/sudoers.d/:
sudo -l -U deploy
User deploy may run the following commands on prod-web01:
(ALL) NOPASSWD: ALL
NOPASSWD: ALL for a deploy user is effectively handing out root to anyone who compromises that account. Scope it down to only what deploy actually needs:
# /etc/sudoers.d/deploy
deploy ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart nginx, /usr/bin/systemctl restart app-worker
Specific commands only. No wildcards. Wildcards in sudoers can be bypassed with argument injection.
What To Do Right Now
Pick one server — your most exposed, internet-facing box — and run sshd -T | grep -E 'permitrootlogin|passwordauthentication' right now. If either value comes back as yes, fix it before you close this tab. That single change eliminates the majority of automated SSH attacks targeting your infrastructure today.
