SSH-Zombie-Prozesse: Erkennen, Verstehen und Sauber Beheben

SSH-Zombie-Prozesse sind lästig, tendenziell symptomatisch für ein tieferliegendes Problem – und trotzdem relativ leicht zu diagnostizieren und zu beheben, wenn man weiß, wonach man sucht. In diesem Blogpost zeige ich dir:

  • Was SSH-Zombie-Prozesse sind
  • Wie sie entstehen
  • Wie du sie identifizierst
  • Wie du sie sicher und automatisiert bereinigst

🧠 Was sind SSH-Zombie-Prozesse?

Ein „Zombie“ im klassischen Unix-Sinne ist ein Prozess, dessen Elternteil nicht korrekt beendet wurde und deshalb im Prozessbaum hängen bleibt.

Bei SSH-Servern tauchen diese in der Form sshd: root (oder andere Benutzer) auf, die scheinbar unbegrenzt im System laufen, obwohl die eigentliche Session längst beendet ist.

Das passiert nicht, weil SSH kaputt ist – sondern weil die Verbindung nie sauber geschlossen worden ist und der zugehörige Prozess im System weiterexistiert.


🧩 Wie entstehen diese Zombie-Prozesse?

Zombie-SSH-Prozesse entstehen meistens durch eine der folgenden Ursachen:

1. Unsaubere Trennung der Verbindung

Wenn der Client die Verbindung abrupt verliert (Netzwerkunterbrechung, Timeout, erzwungener Kill des Clients), bekommt der SSH-Daemon nicht korrekt mit, dass die Verbindung weg ist.

Beispiel-Situation: Dein Laptop verliert die VPN-Verbindung – aber auf dem Server läuft noch der alte sshd: root Prozess weiter.


2. Brute-Force-Angriffe / Massiver Fehlversuchverkehr

Ein starker Zustrom an SSH-Verbindungen – besonders fehlgeschlagene – kann dazu führen, dass viele Prozesse gestartet werden, aber nicht sauber beendet werden.

  • Firewall antwortet langsam
  • SSHD ist überlastet
  • Verbindungen hängen im Netzwerk

→ Ergebnis: Viele “Kinder” im Prozessbaum, die scheinbar nichts mehr tun.


3. MTU-/Netzwerkprobleme / Paketverlust

Wenn Pakete verloren gehen oder nur teilweise ankommen, kann es passieren, dass TCP-FIN/ACK oder RST nicht korrekt übertragen wird. Der SSH-Server wartet dann einfach auf das Ende …


🧐 Wie erkennst du, dass du SSH-Zombies hast?

1) Systemd-Status

systemctl status ssh

Ein verdächtiger Tree kann so aussehen:

ssh.service
 ├─ 2307 sshd: root
 ├─ 2344 sshd: root
 ├─ 6232 sshd: root
 ...

Wenn dort zig oder hunderte Prozesse auftauchen, obwohl kaum Verbindungen aktiv sind, ist das ein Zombie-Signal.


2) Prozessliste gezielt prüfen

ps -eo pid,etime,cmd | grep "sshd: root"

Wichtig ist die Spalte etime:
→ Sie zeigt, wie lange der Prozess schon läuft.

Beispiel:

1234  12:34 sshd: root
2345  3-05:23:12 sshd: root

Ein Prozess, der seit Tagen läuft, obwohl niemand sich eingeloggt hat → Zombie.


3) Ressourcen-Symptome

  • erhöhte Anzahl von Tasks (top/htop)
  • ungewöhnlich hoher Speicherverbrauch
  • SSH hängt beim neuen Verbindungsaufbau

🧹 Wie du Zombie-Prozesse sauber beendest

Es gibt mehrere Wege – von manuell bis automatisiert.


🛠️ Manuell: gezielt nur alte Prozesse killen

ps -eo pid,etime,cmd | grep "sshd: root" | grep -v grep | awk '$2 ~ /-/ || $2 ~ /^[1-9][0-9]*:/ {print $1}' | xargs -r sudo kill -9

Was passiert hier?

  1. ps listet Prozesse mit Laufzeit.
  2. awk filtert nur Prozesse mit Laufzeit > 1 Stunde (oder mit Tagen).
  3. xargs führt kill -9 auf dieser Liste aus.

💡 Vorteil:
Du tötest nur die Alten, lässt aktive Sessions in Ruhe.


🔁 Automatisiert: Skript + Cronjob

Speichere das folgende Skript als /usr/local/bin/clean-sshd-zombies.sh:

#!/bin/bash
# Alte sshd:root Kinderprozesse beenden, die älter als 10 Minuten sind

TIME_LIMIT=10

ps -eo pid,etime,cmd | grep "sshd: root" | grep -v grep | while read PID ETIME CMD; do
    if [[ "$ETIME" =~ ([0-9]+)-([0-9]+):([0-9]+):([0-9]+) ]]; then
        DAYS=${BASH_REMATCH[1]}
        HOURS=${BASH_REMATCH[2]}
        MINS=${BASH_REMATCH[3]}
        TOTAL_MINS=$((DAYS*24*60 + HOURS*60 + MINS))
    elif [[ "$ETIME" =~ ([0-9]+):([0-9]+):([0-9]+) ]]; then
        HOURS=${BASH_REMATCH[1]}
        MINS=${BASH_REMATCH[2]}
        TOTAL_MINS=$((HOURS*60 + MINS))
    elif [[ "$ETIME" =~ ([0-9]+):([0-9]+) ]]; then
        TOTAL_MINS=${BASH_REMATCH[1]}
    else
        TOTAL_MINS=0
    fi

    if [ "$TOTAL_MINS" -gt "$TIME_LIMIT" ]; then
        sudo kill -9 $PID
        echo "Killed sshd zombie PID $PID (etime $ETIME)"
    fi
done

Dann in cron:

*/5 * * * * /usr/local/bin/clean-sshd-zombies.sh >> /var/log/sshd-zombie-clean.log 2>&1

Das Skript läuft alle 5 Minuten, killt nur Zombie-Prozesse und loggt, was gemacht wurde.


🛡️ Prophylaxe: Wie vermeidest du das Problem?

1) SSH richtig beenden

Wenn möglich:

exit

statt einfach das Terminal zu schließen.


2) Idle-Timeouts setzen

In /etc/ssh/sshd_config:

ClientAliveInterval 300
ClientAliveCountMax 2

→ client wird nach 10 Minuten Inaktivität automatisch beendet.


3) Fail2Ban / Firewall-Regeln

Ein Brute-Force-Angriff erzeugt viele halböffnete Verbindungen:

  • Setze ufw/iptables ein
  • nutze fail2ban, um wiederholte Fehlversuche zu blockieren

🧾 Zusammenfassung

ProblemUrsacheLösung
Viele alte sshd: root Prozesseunsaubere Disconnections, Netzwerkprobleme, Angriffealte Prozesse killen, Automatisierung
SSH hängt beim VerbindungsaufbauRessourcenmatrix überlastetZombie-Cleaner, Idle-Timeouts
Häufige Fehlversuche von außenBrute ForceFirewall + Fail2Ban

🚀 Fazit

Zombie-SSH-Prozesse sind keine Seltenheit – aber sie werden oft übersehen. Mit einem systematischen Vorgehen findest du sie schnell, entfernst sie sicher und sorgst dafür, dass sie nicht wiederkommen.