Stop SSH Brute‑Force Attacks: 5 Ready‑to‑Use Scripts to Harden Your Server

The article reveals how thousands of SSH brute‑force attempts target servers daily, explains why password‑based root logins are a critical risk, and provides five practical Bash scripts—analysis, auto‑banning, security checks, user audits, and daily reporting—to quickly fortify SSH defenses.

Xiao Liu Lab
Xiao Liu Lab
Xiao Liu Lab
Stop SSH Brute‑Force Attacks: 5 Ready‑to‑Use Scripts to Harden Your Server
Today I logged into a test server and the line below gave me chills. 74744 brute‑force attempts—averaging 10 per minute over 5 days . My server only had a single root password login. This is not a drill; it’s a daily "digital siege".

1. You think you’re not compromised? It’s just luck

Attackers don’t need complex passwords. They use bots to scan the whole Internet on port 22, trying combinations such as root/123456, admin/admin, ubuntu/ubuntu, etc. A single successful login can turn your server into a mining farm, botnet, or jump host. Worse, you may never know it’s been compromised. Many mining bots deliberately limit CPU usage to avoid triggering alerts.

2. Don’t wait for disaster! 5 scripts to immediately strengthen your defenses

All scripts are production‑tested, copy‑and‑paste ready, and should be bookmarked.

Script 1: One‑click analysis of top 10 brute‑force sources

#!/bin/bash
# analyze_ssh_brute.sh - Analyze /var/log/secure for brute‑force sources

echo "=== SSH 暴力破解来源 TOP 10 ==="
grep "Failed password" /var/log/secure* 2>/dev/null |
  awk '{print $(NF-3)}' |
  sort |
  uniq -c |
  sort -nr |
  head -10 |
  awk '{printf "%-5s %s
", $1, $2}'

Example output is shown below. Run it weekly and manually add high‑frequency IPs to the firewall blacklist.

Script 2: Auto‑ban high‑frequency failed IPs (lightweight Fail2ban alternative)

If you don’t want to install Fail2ban, this script provides basic automatic banning.

#!/bin/bash
# auto_ban_ssh.sh - Auto‑ban IPs with >5 failures within 1 hour

LOG_FILE="/var/log/secure"
BAN_TIME=3600  # ban duration in seconds

awk '/Failed password/ {print $(NF-3)}' "$LOG_FILE" |
  sort |
  uniq -c |
  awk '$1 > 5 {print $2}' |
  while read ip; do
    if ! iptables -C INPUT -s "$ip" -j DROP 2>/dev/null; then
      echo "Banning $ip for $BAN_TIME seconds"
      iptables -A INPUT -s "$ip" -j DROP
      (sleep $BAN_TIME && iptables -D INPUT -s "$ip" -j DROP 2>/dev/null) &
    fi
  done

Run it every 5 minutes via crontab.

*/5 * * * * /opt/scripts/auto_ban_ssh.sh

Script 3: Check if password login risk still exists

#!/bin/bash
# check_ssh_security.sh - SSH security audit

echo "=== SSH 安全检查 ==="

# 1. Is password authentication disabled?
if grep -q "^PasswordAuthentication\s*no" /etc/ssh/sshd_config; then
  echo "✅ PasswordAuthentication: disabled"
else
  echo "❌ PasswordAuthentication: ENABLED! (high risk)"
fi

# 2. Is root login prohibited?
if grep -q "^PermitRootLogin\s*no" /etc/ssh/sshd_config; then
  echo "✅ PermitRootLogin: disabled"
else
  echo "❌ PermitRootLogin: ENABLED! (high risk)"
fi

# 3. Scan authorized_keys for suspicious entries
for user_dir in /home/*; do
  key_file="$user_dir/.ssh/authorized_keys"
  if [ -f "$key_file" ]; then
    echo "🔍 Checking $key_file ..."
    if grep -lqiE "(miner|bot|backdoor|test)" "$key_file" 2>/dev/null; then
      echo "⚠️ $key_file may contain suspicious public keys!"
    fi
  fi
done

Script 4: Audit system users to find "ghost accounts"

Attackers often create hidden users to maintain access. This script helps you identify them.

#!/bin/bash
# audit_users.sh - Audit non‑system users

echo "=== Non‑system users (UID >= 1000) ==="
awk -F: '$3 >= 1000 && $1 != "nobody" {print "User: " $1 " | Shell: " $7}' /etc/passwd

echo -e "
=== Users without passwords ==="
passwd -S | awk '$2 == "NP" {print "No‑password user: " $1}'

echo -e "
=== Login‑capable users (shell not nologin/false) ==="
awk -F: '($3 >= 1000) && ($7 !~ /nologin|false/) {print "Loginable user: " $1}' /etc/passwd

Real case: We once discovered a user named support with /bin/bash as its shell, whose origin was unknown—exactly an attacker‑left backdoor.

Script 5: Daily SSH security report (DingTalk version)

#!/bin/bash
# daily_ssh_report.sh - Generate daily SSH security report and send via DingTalk

# Configuration
DINGTALK_WEBHOOK="https://oapi.dingtalk.com/robot/send?access_token=YOUR_TOKEN"
HOSTNAME=$(hostname)
DATE=$(date '+%Y-%m-%d %H:%M:%S')
REPORT_FILE="/tmp/ssh_security_report_$(date +%Y%m%d).txt"

{
  echo "Recent 24‑hour failed login count:"
  FAIL_COUNT=$(lastb | wc -l)
  echo "$FAIL_COUNT"

  echo -e "
Top attacking IPs (TOP 5):"
  TOP_IPS=$(grep "Failed password" /var/log/secure* 2>/dev/null | awk '{print $(NF-3)}' | sort | uniq -c | sort -nr | head -5 | sed 's/^/ - /')
  echo "$TOP_IPS"

  echo -e "
Current SSH configuration risks:"
  RISK_OUTPUT=$(/opt/scripts/check_ssh_security.sh 2>&1)
  echo "$RISK_OUTPUT"
} > "$REPORT_FILE"

# Build DingTalk markdown payload
MESSAGE=$(cat <<EOF
{
  "msgtype": "markdown",
  "markdown": {
    "title": "【SSH安全日报】$HOSTNAME",
    "text": "### 🔒 【SSH安全日报】$HOSTNAME
**时间**:$DATE

**🚨 最近24小时失败登录次数**:$FAIL_COUNT 次

**🔥 高频攻击 IP(TOP 5)**:
$TOP_IPS

**⚠️ SSH 配置风险检查**:
\`
$RISK_OUTPUT
\`"
  },
  "at": {"isAtAll": false}
}
EOF
)

curl -s -X POST "$DINGTALK_WEBHOOK" \
  -H 'Content-Type: application/json' \
  -d "$MESSAGE" > /dev/null

# Keep report files for 7 days
find /tmp -name "ssh_security_report_*.txt" -mtime +7 -delete

Add to crontab to run each morning:

0 9 * * * /opt/scripts/daily_ssh_report.sh

3 Principles to Guard the SSH Door

Never use password login → enforce SSH keys

Never allow direct root login → use regular user + sudo

Never trust any public IP → restrict sources + auto‑ban

Conclusion

The line " 74744 failed login attempts " is not just a log entry; it’s the attacker’s footprints at your doorstep. Don’t wait for the 74745 th success to regret. Spend 10 minutes today hardening your SSH – it’s far better than spending 10 hours tomorrow firefighting.

LinuxSSHbrute forceSecurity Scripts
Xiao Liu Lab
Written by

Xiao Liu Lab

An operations lab passionate about server tinkering 🔬 Sharing automation scripts, high-availability architecture, alert optimization, and incident reviews. Using technology to reduce overtime and experience to avoid major pitfalls. Follow me for easier, more reliable operations!

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.