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: rootProzess 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?
pslistet Prozesse mit Laufzeit.awkfiltert nur Prozesse mit Laufzeit > 1 Stunde (oder mit Tagen).xargsführtkill -9auf 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/iptablesein - nutze
fail2ban, um wiederholte Fehlversuche zu blockieren
🧾 Zusammenfassung
| Problem | Ursache | Lösung |
|---|---|---|
Viele alte sshd: root Prozesse | unsaubere Disconnections, Netzwerkprobleme, Angriffe | alte Prozesse killen, Automatisierung |
| SSH hängt beim Verbindungsaufbau | Ressourcenmatrix überlastet | Zombie-Cleaner, Idle-Timeouts |
| Häufige Fehlversuche von außen | Brute Force | Firewall + 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.