SSH vor Brute-Force-Angriffen schützen

Mit Open-Source-Tools und wenigen Handgriffen erkennt ein System verdächtige Anmeldeversuche und blockiert sie.

In Pocket speichern vorlesen Druckansicht
Lesezeit: 13 Min.
Von
  • Daniel Bachfeld
Inhaltsverzeichnis

Viele Betreiber eines Servers mit SSH-Zugang und Authentifizierung per Passwort haben ein ungutes Gefühl, was die Sicherheit angeht. Spätestens wenn ein Blick in die Server-Logs zahllose Login-Versuche von automatischen Skripten offenbart, fragt man sich, ob das gut gewählte Passwort weiteren Brute-Force-Angriffe standhalten wird. Zuletzt zeigte sich bei Angriffen auf diverse Sicherheits-Sites, dass die Betreiber die eigenen Ratschläge nicht immer befolgen.

Doch mit einfachen Mitteln kann man die wiederholten Versuche der Cracker ganz einfach ausbremsen. Spezielle Tools zählen die Fehlversuche von einer bestimmten IP-Adresse aus und blockieren ab einer vorgegebenen Schwelle weitere Zugriffe. Bei der Blockade verfolgen die Tools unterschiedliche Ansätze.

Mit sogenannten TCP-Wrappern lassen sich unter Unix-und BSD-Systemen Zugriffskontrollen für TCP-Verbindungen implementieren. Sie schalten sich zwischen den TCP/IP-Stack und den eigentlichen Dienst. Klassisch geschieht dies im Zusammenspiel mit dem Superserver (x)inetd, der ankommende Verbindungen zunächst dem TCP-Wrapper übergibt. Der kann dann beispielsweise Verbindungen protokollieren oder Verbindungsversuche von einzelnen IP-Adresse blockieren. Welche Adressen erlaubt sind und welche nicht, steht in den Dateien /etc/hosts.allow und /etc/hosts.deny. Erst wenn alles passt, startet der Wrapper das Dienstprogramm und übergibt ihm die offene Verbindung. Manche Dienste wie OpenSSH sind bereits gegen die Wrapper-Bibliothek libwrap gelinkt, die dieselbe Funktion übernimmt, und kommen somit ohne explizit zwischengeschalteten Vermittler aus. Ob der eigene OpenSSH-Daemon bereits gegen libwrap gelinkt ist und somit hosts.deny auswertet, kann man mit ldd /usr/sbin/sshd überprüfen.

Wenn das Server-Log mit solchen Meldungen überquillt, wird so manchem Admin Angst und Bange.

Ein anderer Ansatz zum Blockieren ungewünschter Zugriffe unter Linux ist die Firewall netfilter, deren Regeln respektive Tabellen der Anwender über das Userland-Tool iptables konfiguriert. Auch Anwendungen können Regeln hinzufügen und somit Angreifer draußen halten. Darüber hinaus unterscheiden sich die Tools in der Art, wie sie Informationen über verdächtigte Anmeldeversuche sammeln. Einige durchforsten die Log-Dateien in regelmäßigen Abständen nach Meldungen über fehlgeschlagene Authentifizierungsversuche, andere Tools zählen einfach die Verbindungsversuche von einer IP-Adresse mit.

Alle Blockade-Tools, die in regelmäßigen Intervallen Log-Dateien auswerten, haben das Problem, nicht in Echtzeit auf Angriffe reagieren zu können. Solange ein Angreifer Name und Passwort manuell durchprobiert, können sie mithalten. Bei schnellen Attacken mit automatischen Skripten geraten sie unter Umständen ins Hintertreffen und schlagen zu spät zu. In Tests beobachteten wir Angriffe, bei denen im Log innerhalb weniger Sekunden Dutzende von Fehlversuchen auftauchten, die Tools aber erst nach etwa 40 Sekunden anschlugen. Zwar kann man die Intervalle verkürzen, allerdings nimmt das Tool dann unter Umständen zu viel Ressourcen in Anspruch.

Zudem sind sie grundsätzlich für manipulierte Logeinträge anfällig. Ein Angreifer könnte aus der Ferne etwa mit speziellen Nutzernamen oder anderen Aufrufen gezielt Einträge ins Log schleusen, die die Tools dazu bewegen, legitime IP-Adresse zu blockieren (Details dazu in Attacking Log analysis tools).

Das als Ubuntu-Paket verfügbare Python-Skript DenyHosts durchforstet standardmäßig alle 30 Sekunden die syslog-Datei /var/log/auth.log nach verdächtigen SSH-Fehlversuchen (DAEMON_SLEEP = 30s) und trägt aufällige IP-Adressen in die Datei /etc/hosts.deny ein. Ab wieviel Fehlversuchen eine Adresse dort landet, ist in der Datei /etc/denyhosts.conf festgelegt. Dort kann man etwa Schwellwerte für Login-Versuche mit nicht existierenden Nutzernamen (DENY_THRESHOLD_INVALID) und solchen mit richtigen Nutzernamen aber falschen Passwörter (DENY_THRESHOLD_VALID) getrennt definieren. So ist es möglich, auf das Durchprobieren von Nutzernamen schneller zu reagieren, als auf die Eingabe falsche Passwörter – denn seinen Nutzernamen gibt ein legitimer Anwender in der Regel kaum falsch ein.

Zu den selbst ermittelten IP-Adressen auf Basis von auth.log kann man auch die Ergebnisse anderer Systeme zu seiner Liste der geblockten Rechner hinzufügen. Dieser seit langem bei DenyHosts verfügbare Cloud-Service beruht auf der zentralen Erfassung der von anderen DenyHosts-Clients übermittelten Daten (SYNC_DOWNLOAD = yes). Man selbst kann seine gesammelten ebenfalls an den DenyHost-Server übertragen – muss aber nicht (SYNC_UPLOAD = yes). Im Test übermittelte der Server nach der festgelegten Zeitspanne von 15 Minuten jeweils 50 IP-Adressen, die der Client zu /etc/hosts.deny hinzufügte.

Die Installation der aktuellen Version 2.6 ist mit sudo apt-get install denyhosts schnell erledigt. DenyHosts läuft sofort als Daemon im Hintergrund und startet auch bei späteren Neustarts des Systems automatisch. Grundsätzlich kann man die Standard-Konfiguration so belassen, wir haben nur die Anzahl der erlaubten Fehlversuche für gültigen Konten auf 4 heruntergesetzt. DenyHosts ist nicht auf SSH allein beschränkt, prinzipiell schützt es auch andere Dienste, die ein Login oder eine Authentifizierung erfordern, etwa FTP, Telnet und SMTP. Diese Dienste müssen dann aber entweder via (x)inetd gestartet werden oder gegen libwrap gelinkt sein.

In der Standardkonfiguration wächst die Datei deny.hosts kontinuierlich, was insbesondere bei Nutzung des Cloud-Services natürlich sehr unschön ist. DenyHosts lässt sich jedoch so konfigurieren, dass es in die Liste geratene IP-Adressen nach einer vorgegebenen Zeitspanne wieder löscht und die Verbindungsaufnahme dann wieder möglich ist. Die Option PURGE_DENY = 1d legt beispielsweise die Dauer auf einen Tag fest. Mit der Option DAEMON_PURGE = 1d veranlasst man DenyHosts, automatisch einmal täglich den Löschprozess auszuführen. Alternativ kann man DenyHosts stoppen und mit sudo denyhosts --purge manuell alle älteren Einträge löschen. Anschließend muss man DenyHosts wieder starten.

Falls man DenyHosts auf etwas älteren (Ubuntu)-Systemen ausprobieren möchte: Nicht immer sind die Dateien /etc/hosts.allow und /etc/hosts.deny im System bereits vorhanden, was zu Fehlern beim Ausführen von DenyHosts führen kann. Die Dateien lassen sich mit Root-Rechten aber einfach anlegen (touch /etc/hosts.deny).

Das ebenfalls in Python geschriebene fail2ban nutzt das Linux-Firewall-Tool iptables, um IP-Adressen von missliebigen Rechnern zu blockieren. Dazu fügt es eine neue Regel in die INPUT-Chain ein und legt eine neue Chain an mit einer DROP-Regel zu jedem blockierten Host. Das Tool unterstützt aber trotzdem von Haus aus die Wrapper-Technik sowie ipfw. Zudem kann es nicht nur SSH vor zu vielen Login-Versuchen schützen, sondern auch FTP- und Mailserver. Zur Installation genügt unter Ubuntu ein sudo apt-get install fail2ban. Standardmäßig sind aber nur Regeln für SSH aktiv. In der Konfigurationsdatei jail.conf im Verzeichnis /etc/fail2ban sind aber Regeln für weitere Dienste vordefiniert, die man bei Bedarf nur noch aktivieren muss.

Erscheint im Log "messages repeated x times" hat fail2ban Probleme, die richtige Zahl der Loginversuche zu ermitteln.

Wie DenyHost sucht auch fail2ban mittels regulärer Ausdrücke nach Hinweisen auf fehlgeschlagene Anmeldeversuche in /var/log/auth.log. Leider macht ihm auf Ubuntu-Systemen der syslog-Daemon einen Strich durch die Rechnung. Der schreibt nämlich in den meisten Fällen einen Login-Fehlversuch nur einmal in voller Länge in die Logdatei und dann bei den folgenden Versuchen nur noch "last message repeated x times". Damit kann fail2ban aber nicht viel anfangen, sodass es nur den ersten Versuch zählt. Ein Angreifer kann so erheblich öfter sein Glück versuchen, als es die in der Konfiguration eingestellten sechs Fehlversuche suggerieren.

Das Problem ist in Kombination mit Ubuntu bekannt. Abhilfe könnte das Deaktivieren der Syslog-Kompression bringen, die dafür verantwortlich ist, dass viele gleichlautende Log-Einträge zu einer Zeile zusammengefasst sind. Allerdings unterstützt der Standard-Syslog-Dienst das Abschalten nicht. Aufgrund ausgefeilterer regulärer Ausdrücke hat DenyHosts mit diesem Problem nicht zu kämpfen.

Zur Not kann man in der Konfiguration des SSH-Daemons die Zahl der erlaubten Fehlversuche beispielsweise auf 2 heruntersetzen und in den fail2ban-Einstellungen die Zahl der maximalen Wiederholungen ebenfalls auf 2 heruntersetzen. Nach zwei erfolglosen Logins baut der SSH-Dienst die Verbindung ab, sodass bei einer erneuten Verbindung der Dienst eine neue Zeile im Log instanziiert, welche fail2ban dann als zweiten Versuch erkennt. Insgesamt hat ein Angreifer somit auch nur vier Versuche, bevor die Firewall ihn blockiert.

Gegenüber DenyHosts hat fail2ban indes den Vorteil, dass es gesperrte Hosts automatisch entsperren kann. Die Option bantime = 600 löscht die blockierende iptables-Regel nach 10 Minuten automatisch.

Mit dem iptables-Modul "recent" lassen sich auf Paketebene TCP-Verbindungsversuche auf Dienste in Echtzeit mitzählen und ab einem Schwellwert weitere Angriffe von einer IP-Adresse blockieren, ohne dass man Logs durchsuchen muss. Das Modul ist Bestandteil des Linux-Kernels und wird zur Laufzeit geladen.

Recent kann allerdings prinzipbedingt nicht zwischen erfolgreichen und fehlgeschlagenen Logins unterscheiden. Da sich aber kein Anwender ständig anmeldet und sofort wieder abmeldet, kann ein Fenster von drei SSH-Verbindungsaufbauversuchen innerhalb von 60 Sekunden als Grenze gelten, ab der man den Vorgang als Brute-Force-Angriff werten darf. Die individuellen Einstellungen hängen aber von Risiko für mögliche gezielte Angriffe auf den eigenen Server ab. Mit nur zwei Versuchen pro Minute kann ein Angreifer über den Tag verteilt aber immer noch 2880 Passwörter probieren. Hier hilft es gegebenenfalls, ein Tageslimit festsetzen, beispielsweise auf 30.

In unseren Tests hat folgende Konfiguration gut funktioniert. Man setzt man in /etc/ssh/sshd_config die Option MaxAuthTries 3 und definiert folgende iptables-Regeln (gelten für ein System ohne bereits vorhandene iptables-Regeln):

iptables -A INPUT -p tcp --dport 22 -i eth0 -m state --state NEW -m recent --set
iptables -A INPUT -p tcp --dport 22 -i eth0 -m state --state ESTABLISHED -m recent --update --seconds 60 --hitcount 2 -j REJECT --reject-with tcp-reset

Die erste Regel schreibt mit der Option --set die IP-Adresse einer neuen Verbindung auf Port 22 nebst Zeitstempel in die Proc-Datei /proc/net/ipt_recent/DEFAULT. Die zweite Regel fügt mit --update einen weiteren Zeitstempel ein und prüft, ob zwei Zeitstempel innerhalb der letzten 60 Sekunden liegen. Ist dies der Fall, wird die Verbindung zurückgesetzt. Erst nach Ablauf einer Minute ist wieder eine Verbindung zum SSH-Server und drei weitere Login-Versuche möglich. Anders als bei der Wrapper-Methode blockieren diese Regeln nur den SSH-Zugang, alle anderen Dienste sind für den Angreifer weiter erreichbar.

Im /proc-Dateisystem kann man die vom Recent-Modul registrierten Pakete mit Zeitstempel einsehen.

Die Kombination von NEW und ESTABLISHED verringert die Gefahr von Spoofing-Angriffen, bei denen ein Spaßvogel mit gefälschten IP-Absender-Adresse die Recent-Liste füllt und somit unter Umständen legitime Adressen darin landen und die Firewall sie blockiert. Welche Adresse die Firewall wie oft gesehen hat, lässt sich mit cat /proc/net/ipt_recent/DEFAULT abfragen. Die gesamte Liste lässt sich mit echo clear > proc/net/ipt_recent/DEFAULT löschen. Einzelne Adressen kann man mit echo - > proc/net/ipt_recent/DEFAULT] entfernen. Grundsätzlich ließen sich diese Funktionen mit Log-Analyse verknüpfen.

Auf einem über mehrere Monate mit DenyHosts geschützten System nahm die Zahl der Einbruchsversuche zwar nicht ab, deren Dauer verkürzte es aber auf unter eine Minute. Danach zog der Angreifer vermutlich zum nächsten System weiter. Stabilitätsprobleme zeigten sich nicht. Für den schnellen Schutz ist DenyHosts also durchaus geeignet. Grundsätzlich ist die Realisierung eines Blockers mit dem iptables-Modul recent aber deterministischer und zuverlässiger. Allerdings kann die Integration in bestehenden Firewall-Regelsätze mitunter etwas schwierig sein.

Angreifer versuchen jedoch immer häufiger, der Limitierung für Logins von einzelnen IP-Adressen zu entgehen, indem sie Botnetze für ihre Brute-Force-Angriffe verwenden. Dabei kann jeder Bot die maximale Anzahl der erlaubten Fehl-Logins durchprobieren, bevor das System ihn blockt. Die einzelnen Bots können sowohl parallel als auch hintereinander die Passwörter für ein Konto oder sogar mehrere testen. Bei einem beispielsweise aus 10.000 PCs bestehendem Botnetz könnte ein Angreifer bei drei erlaubten Versuchen 30.000 Passwörter ausprobieren. Daher bleibt es wichtig, ein schwer erratbares Passwort zu wählen.

Mit dem sshd-Parameter MaxStartups kann man die Zahl paralleler Verbindungen begrenzen, was zumindest zahlreiche gleichzeitige Logins verhindert. Sofern die Bots jedoch nacheinander ihr Glück versuchen, nutzt die Limitierung nicht mehr. Damit muss der Angreifer aber erheblich mehr Zeit aufwenden.

Alternativ oder auch auch zusätzlich kann man seinen SSH-Server aus der Schusslinie bringen, indem man ihn vom Standard-TCP-Port 22 auf einen ungewöhnlichen Port wie 54321 umzieht. Mit dem Wechsel auf die Authentifizierung per Public Key eliminiert man die Gefahr durch Brute-Force-Angriffe ganz; dies ist schlichtweg die sicherste Methode zur Authentifizierung. Allerdings ist es auch die unflexibelste, da man immer den Key dabei haben muss. Einen Mittelweg könnten Einmalpasswörter bieten. Der Artikel "Einmalpasswörter für den Heimgebrauch" beschreibt, wie man seinen Server dafür einrichtet. (dab)