SSH Brute-Force Attack Detection

Intermediate Security

Your server is receiving thousands of failed SSH login attempts per hour from one or many external IP addresses. Automated bots are systematically trying common usernames and passwords against your SSH daemon. Left unchecked, a successful credential guess gives the attacker full shell access.

Symptoms

  • Thousands of 'Failed password' or 'Invalid user' entries in /var/log/auth.log
  • High CPU or I/O load on the authentication subsystem (PAM, sshd)
  • Slow legitimate SSH logins due to connection queue saturation
  • Repeated connection attempts from foreign IP ranges in rapid succession
  • Alert from intrusion detection system (fail2ban, OSSEC) about excessive failures
  • New unknown user accounts or unexpected sudo entries if an attempt succeeds

Possible Root Causes

  • SSH port 22 exposed directly to the public internet without IP allowlisting
  • Password authentication enabled for SSH instead of key-only authentication
  • No rate-limiting or account lockout mechanism (fail2ban not installed/configured)
  • Default or weak credentials on system accounts (root, admin, ubuntu, ec2-user)
  • Server IP exposed via DNS, email headers, or public-facing application errors

Diagnosis Steps

1. Confirm brute-force activity in auth log

# Count failed attempts per source IP (last 1000 lines)
grep "Failed password" /var/log/auth.log | awk '{print $(NF-3)}' | sort | uniq -c | sort -rn | head -20

# See invalid usernames being tried
grep "Invalid user" /var/log/auth.log | awk '{print $8}' | sort | uniq -c | sort -rn | head -20

# Count total failed attempts in the last hour
grep "$(date +'%b %e %H')" /var/log/auth.log | grep -c "Failed password"

2. Check current active connections to SSH port

# Show established and time-wait SSH connections
ss -tn state established '( dport = :22 or sport = :22 )'

# Count unique source IPs currently connecting
ss -tn '( dport = :22 or sport = :22 )' | awk 'NR>1 {print $5}' | cut -d: -f1 | sort | uniq -c | sort -rn

3. Check fail2ban jail status

# Is fail2ban running?
sudo systemctl status fail2ban

# See current bans for the SSH jail
sudo fail2ban-client status sshd

# See the last 50 fail2ban log entries
sudo tail -50 /var/log/fail2ban.log

4. Identify top attacker IPs and look them up

# Extract top 10 attacker IPs
grep "Failed password" /var/log/auth.log | awk '{print $(NF-3)}' | sort | uniq -c | sort -rn | head -10

# Whois lookup for the worst offender (replace IP)
whois 203.0.113.42

# Check if IP is on known blocklists
curl -s "https://api.abuseipdb.com/api/v2/check?ipAddress=203.0.113.42" \
  -H "Key: YOUR_API_KEY" -H "Accept: application/json" | python3 -m json.tool

5. Check for any successful logins from suspicious IPs

# Look for successful logins (Accepted) and compare with known good IPs
grep "Accepted" /var/log/auth.log | awk '{print $9, $11}' | sort | uniq -c | sort -rn

# Check last successful logins
last -a | head -30

Solution

Immediate: Block the top attackers

# Manually block the worst offenders with iptables
sudo iptables -A INPUT -s 203.0.113.42 -j DROP

# Or use fail2ban to ban immediately
sudo fail2ban-client set sshd banip 203.0.113.42

Install and configure fail2ban (if not present)

sudo apt-get install fail2ban -y

# Create a local override
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local

Edit /etc/fail2ban/jail.local:

[sshd]
enabled   = true
port      = ssh
logpath   = /var/log/auth.log
maxretry  = 5
findtime  = 600
bantime   = 3600
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd

Disable password authentication (use keys only)

Edit /etc/ssh/sshd_config:

PasswordAuthentication no
PermitRootLogin no
PubkeyAuthentication yes
sudo sshd -t          # Validate config
sudo systemctl restart sshd

Change SSH to a non-standard port (optional defence-in-depth)

Port 2222

Update your firewall rules accordingly and restart sshd.

Prevention

  • Keys only: Disable PasswordAuthentication in sshd_config — brute force becomes computationally infeasible against Ed25519 keys.
  • fail2ban: Configure with maxretry = 3, bantime = 86400 (24h ban). Add recidive jail for repeat offenders.
  • Firewall allowlist: If connecting from known IPs, whitelist those in your security group or iptables and drop all other port 22 traffic.
  • Port obscurity: Move SSH off port 22 to reduce automated scan noise (not a security control by itself).
  • Regular log review: Set up a weekly grep "Accepted" /var/log/auth.log report to catch unexpected successful logins.

Related Protocols

Related Terms

More in Security