Loseblatt-Sammlung

SSH-Schutz mit nftables und Scripts

Hier ist die vollständige, eigenständige Implementierung für die /24-Sperre. Getestet auf einem Debian 13 System. Sinnvoll für kleine Server wo fail2ban Overkill wäre.

Bei mir wird extremst aus verschiedenen IP-Bereichen, oft aus /24 Netzen an der Tür gerüttelt. Dank Zertifikaten und gesperrter passwortbasierten Zugang keine Chance. Aber sie müllen das Log zu und sind auch sonst recht penetrant. Diese Bots finden auch direkt versteckte SSH-Ports.

1. Firewall (nftables) konfigurieren

Wir müssen nftables so einstellen, dass es das Set block_24 bereithält und eingehende SSH-Verbindungen (Port 22) aus diesen Subnetzen verwirft.

Backup der aktuellen Konfiguration erstellen:

cp /etc/nftables.conf /etc/nftables.conf.bak

Datei bearbeiten:

nano /etc/nftables.conf

Folgenden vollständigen Inhalt einfügen (überschreibt die alte Konfiguration):

Gegebenenfalls Konfigurationen aus der Originaldatei hinzufügen.

#!/usr/sbin/nft -f

flush ruleset

table inet filter {


    # Set für gebannte /24 Subnetze
    set block_24 {
        type ipv4_addr
        flags interval, timeout
        timeout 24h
    }

    chain input {
        type filter hook input priority filter; policy drop;

        # --- PORTSCAN MITIGATION ---
        # Ungültige Verbindungszustände sofort verwerfen
        ct state invalid drop
        # Ungültige TCP-Flags verwerfen (Schutz vor Stealth Scans)
        tcp flags & (fin|syn|rst|psh|ack|urg) == 0 drop
        tcp flags & (fin|psh|urg) == fin|psh|urg drop
        tcp flags & (syn|rst) == syn|rst drop
        tcp flags & (fin|rst) == fin|rst drop
        tcp flags & (fin|syn) == fin|syn drop
        # ---------------------------

        # Loopback erlauben
        iif "lo" accept

        # Etablierte und zugehörige Verbindungen erlauben
        ct state established,related accept

        # Gebannte Subnetze sofort auf dem SSH-Port blockieren
        ip saddr @block_24 tcp dport 22 drop

        # SSH-Zugang auf Port 22 generell erlauben
        tcp dport 22 accept

        # Webserver (LAMP) & GotoSocial Ports erlauben
        tcp dport { 80, 443 } accept

        # ICMP (Ping) erlauben (Wichtig für Netzwerkdiagnose)
        ip protocol icmp accept
        ip6 nexthdr icmpv6 accept
    }

    chain forward {
        type filter hook forward priority filter; policy drop;
    }

    chain output {
        type filter hook output priority filter; policy accept;
    }
}

Firewall neu laden und Dienst beim Booten aktivieren:

systemctl enable --now nftables.service
systemctl restart nftables.service

2. Das Bash-Script erstellen

Dieses Script liest das Journal aus, wertet die IPs aus und übergibt sie an das soeben erstellte nftables-Set.

Script-Datei anlegen:

nano /usr/local/sbin/ssh-block-24.sh

Folgenden Code vollständig einfügen:

#!/bin/bash
# /usr/local/sbin/ssh-block-24.sh
# Blockiert /24 Subnetze nach >= 2 fehlerhaften SSH-Versuchen der letzten 5 Minuten.

TMP_FILE="/tmp/ssh_bots_24.txt"

# Log der letzten 5 Minuten lesen, nach dem exakten String filtern und IPs extrahieren
/usr/bin/journalctl -u ssh.service --since "5 minutes ago" | \
/usr/bin/grep "Connection closed by invalid user" | \
/usr/bin/grep -oP '\b([0-9]{1,3}\.){3}[0-9]{1,3}\b' > "$TMP_FILE"

# Beenden, wenn keine IPs gefunden wurden
if [ ! -s "$TMP_FILE" ]; then
    /usr/bin/rm -f "$TMP_FILE"
    exit 0
fi

# In /24 konvertieren, zählen und bei Bedarf zu nftables hinzufügen
/usr/bin/awk -F. '{print $1"."$2"."$3".0/24"}' "$TMP_FILE" | \
/usr/bin/sort | \
/usr/bin/uniq -c | while read -r count subnet; do
    if [ "$count" -ge 2 ]; then
        # Subnetz zum nftables Set hinzufügen
        /usr/sbin/nft add element inet filter block_24 { "$subnet" } 2>/dev/null
    fi
done

# Aufräumen
/usr/bin/rm -f "$TMP_FILE"

Berechtigungen restriktiv setzen (nur root darf ausführen und lesen):

chmod 700 /usr/local/sbin/ssh-block-16.sh

3. Cronjob einrichten

Zuletzt muss das Script automatisiert alle 5 Minuten aufgerufen werden.

Crontab für root öffnen:

crontab -e

Folgende Zeile am Ende anfügen:

*/5 * * * * /usr/local/sbin/ssh-block-24.sh >/dev/null 2>&1

Damit ist das System vollständig implementiert und einsatzbereit. Du kannst die gebannten Subnetze zur Kontrolle jederzeit abfragen mit:

 nft list set inet filter block_24

4. Dich selbst entsperren

Führe diesen Befehl aus, um deine IP-Range sofort wieder freizugeben:

nft delete element inet filter block_16 { "xxx.yyy.zzz.0/24" }