PHPGangsta - Der praktische PHP Blog

PHP Blog von PHPGangsta


„Klopf-Klopf“ … wer da?

with 6 comments

Gastartikel von Oliver Sperke.

Ich bin 35 Jahre alt und seit 11 Jahren selbständiger Webentwickler. Mein Fokus liegt dabei auf der Erstellung, Beratung und Optimierung in den Bereichen High Performance, Usability und Sicherheit in den gängisten Internetsprachen: PHP, HTML, Javascript und CSS. Besucht auch mein GPlus Profil oder mein aktuelles Projekt.

Vor langer Zeit fand ich einen Artikel, indem einige Möglichkeiten genannt wurden, seinen OpenSSH Server abzusichern. Da auch hier das Thema Sicherheit sehr komplex ist und es oftmals nicht leicht ist zwischen echtem Nutzen und „Security through obscurity“ zu unterscheiden, möchte ich hier speziell über Portknocking sprechen. Portknocking, auch in seiner Basisfunktion dürfte vielen noch unbekannt sein, obwohl sie sehr effektiv ist. In diesem Tutorial möchte ich noch einmal kurz die Grundlagen erklären und einige interessante Möglichkeiten aufzeigen, wie man das Prinzip weiter spinnen kann.

Wichtiger Hinweis und Ausgangssituation

Lest bitte erst den ganzen Text, damit Ihr nicht in der Mitte stecken bleibt. Wenn Ihr nicht regelmäßig auf Linuxsystemen arbeitet, dann richtet euch eine virtuelle Maschine ein, die Ihr nach Lust und Laune kaputt konfigurieren könnt. Das Verfahren nutze ich genau so auf meinen Servern, wenn Ihr Euch trotzdem aussperrt, dann ist das nicht meine Schuld. Diese Anleitung hat trotz aller Vorsichtsmaßnahmen das Potential, Euch von Eurem eigenem System auszusperren. Sie richtet sich eindeutig an erfahrende Nutzer und ist nichts für Hobbyadmins und „Menschen mit schwachem Herz“. Ich gehe hier von einem aktuellem Debian Squeeze aus mit funktionierendem SSH Server. Die Werte für Sequenzen, Ports und Benutzernamen sind nur Vorschläge und sollten natürlich geändert werden. Ausserdem müsst Ihr natürlich Domains/IPs und E-Mail Adressen entsprechend anpassen.

Portänderungen vs. Portknocking

Versteckt man Ports oder ändert Standardports ab macht man sich erst mal für einen Angreifer interessant, denn kein Linuxserver lässt sich effektiv ohne Konsole warten. Ist kein SSH Zugang auf Port 22 vorhanden, ist dies ein sicheres Zeichen, dass dort noch etwas versteckt ist, was u. U. im Glauben falscher Sicherheit nicht so gut geschützt ist, wie es sein sollte. Bei einfachen Portänderungen kann man dies leicht herausfinden, indem man den Server nacheinander auf allen Ports befragt. In einem einen nicht repräsentativem einwöchigem Selbsttest habe ich den SSH Port von 22 auf 9922 geändert mit dem Effekt, dass die Anzahl der Angriffe, die Fail2ban erkannt hat, sich quasi nicht verändert hat. Von vorher 6 bis 8 Sperrungen am Tag, sind die Zahlen nur auf 5 bis 7 Sperrungen zurück gegangen. Ein sicheres Zeichen, dass automatische Angriffstools besser geworden sind. Was wäre aber, wenn der SSH Server selbst ganz regulär antwortet, aber keinen Zugang zum eigentlichen System gestattet? Erhöht das die Sicherheit? Ich denke, Ja!

Ich möchte gern zeigen, wie man alle Benutzer auf dem Standardport SFTP aufzwingt oder ihn für manche Benutzer ganz nutzlos macht und gleichzeitig einen zweiten versteckten Eingang hinterlegen, der nur priviligierten Konsolennutzern zugänglich ist. Jeder Login auf Port 22 soll den Benutzer an den internen SFTP Dienst weiterleiten und ihn gleichzeitig in eine chroot, eine Art Gefängnis auf dem Server einsperren, so dass er dem System nicht schaden, aber trotzdem seine persönlichen Dateien bearbeiten kann. Dieses Verfahren schafft uns einige Vorteile. Ein Angreifer muss wissen, dass er an der falschen Tür steht und er muss gezielt nach einem anderem Eingang suchen. Wenn der Standardport aber erreichbar ist und sich der SSH Server meldet dürfte er da nicht ohne weiteres drauf kommen. Aber und das ist das Wichtige, selbst wenn er darauf kommen sollte, ist der Weg zu dieser Hintertür sehr lang und steinig.

Ein weiterer Vorteil ist, dass selbst wenn ein Brute Force Angriff erfolgreich wäre oder Euer Passwort bzw. Euer Schlüssel kompromittiert ist, kann ein Angreifer dem System nicht schaden und damit war seine ganze Arbeit umsonst. Ihr habt genug Zeit, Euch einen neuen Schlüssel anzulegen. Dieses Verfahren ist eine echte Verbesserung gegenüber einem regulärem Zugang und wesentlich effektiver als nur den SSH Port zu ändern. Selbst wenn Ihr aus irgendeinem Grund gezwungen seid, Euren SSH Zugang heraus zu geben, könnt Ihr dies erstmal bedenkenlos tun, denn ein echter Zugang ist das nicht.

Vielleicht zwei Zahlen, die das Sicherheitspotential von Portknocking demonstrieren. Wenn wir davon ausgehen, dass uns bei den Ports ein 16 Bit Bereich zur Verfügung steht, also 216 => 65.536 mögliche Ports minus den ersten 1.024, da diese reserviert sind, dann kommen wir inkl. UDP bei 3 aufeinanderfolgenden Klopfzeichen auf ((65.536-1.024)*2)3 => 2,148 Billiarden Möglichkeiten. Genug Potential, um einen Angreifer eine Weile zu beschäftigen. Bei 5 Sequenzen, wie ich es am Ende dieses Artikel demonstriere sind wir im Quadrillionenbereich (1025). Ist ein Signal falsch, wird die Sequenz zurück gesetzt, was den Angriff massiv erschwert. Ein weiterer Vorteil von Portknocking: Es bietet dem Angreifer kein Feedback. Die einzige Möglichkeit für einen Angriff ist es, eine Sequenz zu probieren und sämtliche Ports auf Veränderungen zu scannen. Das ist je nach Anzahl der Knocks und Auswahl der Ports ein sehr langwieriges Unterfangen.

Schritt: 1 Iptables

Zunächst ist es immer eine gute Idee, seinen Server mit Iptables zu schützen. Ein Computersystem kann sich mit Hilfe von Ports untereinander verbinden. Wird ein Server auf Port 22 angesprochen, meldet sich normalerweise der OpenSSH Server und nimmt Befehle entgegen. Dienste müssen nicht auf einzelne Ports beschränkt sein und können auch auf mehreren Ports parallel lauschen.

Iptables kann den Netzwerkverkehr auf diesen Ports erlauben, verbieten oder anders regulieren. Das kann u. a. dann nützlich sein, wenn ich den Dienst nur bestimmten Adressbereichen zugänglich machen möchte. Mit Iptables kann ein Administrator effektiv entscheiden, wie mit einer offenen oder einer geschlossenen Verbindung umgegangen werden soll. Dies geschieht völlig unabhängig vom dahinter liegenden Dienst, so dass keine Konfigurationen geändert werden müssen. Falls noch nicht geschehen installieren wir zunächst Iptables auf unserem System.

sudo apt-get install iptables

Iptables arbeitet alle Anweisungen von oben nach unten ab. Im ersten Teil werden erst einmal alle bestehenden Regeln gelöscht. Danach werden offene Verbindungen gehalten, d. h. sobald eine Verbindung besteht, wird diese nicht getrennt. Dann werden die Ports freigegeben, die man benötigt, also unser SSH Zugang (Port 22), danach der SMTP (Port 25) usw. Am Ende erlaube ich noch Pings, um im Zweifel nachmessen zu können, ob der Server gut oder schlecht erreichbar ist und alle übrigen Verbindungen werden mit einem tcp-reset zurück gewiesen. Man könnte die Verbindung mit DROP auch fallen lassen, wie es öfter vorgeschlagen wird, aber ich finde das sehr unschön. Klares Abweisen ist besser. Zur Konfiguration habe ich folgende Datei /usr/local/bin/iptable_rules angelegt.

sudo nano /usr/local/bin/iptable_rules

 

#!/bin/sh

# Flush all Rules and Chains
iptables -F
iptables -X
iptables -t nat -F
iptables -t nat -X
iptables -t mangle -F
iptables -t mangle -X
iptables -P INPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -P OUTPUT ACCEPT

# Basic rules
iptables -I INPUT 1 -i lo -j ACCEPT

# Keep established connections
iptables -A INPUT -i eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT

# The rules
iptables -A INPUT -i eth0 -p tcp --dport ssh -j ACCEPT
iptables -A INPUT -i eth0 -p tcp --dport smtp -j ACCEPT
iptables -A INPUT -i eth0 -p tcp --dport ssmtp -j ACCEPT
iptables -A INPUT -i eth0 -p tcp --dport www -j ACCEPT
iptables -A INPUT -i eth0 -p tcp --dport https -j ACCEPT
iptables -A INPUT -i eth0 -p tcp --dport imaps -j ACCEPT
iptables -A INPUT -i eth0 -p icmp --icmp-type 8 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT

# Reject the rest
iptables -A INPUT -i eth0 -p tcp -j REJECT --reject-with tcp-reset
iptables -A INPUT -i eth0 -j REJECT

Mit chmod +x /usr/local/bin/iptable_rules machen wir die Datei ausführbar. Ein Aufruf von sudo iptable_rules wendet alle Regeln an. Die Datei können wir zum Start des Systems ausführen, z. B. über die Startup Routine. Das ist natürlich kein Muss. Vor allem für anfängliche Tests kann es günstig sein, diese Datei nur manuell aufzurufen, um durch einen Reboot, alle Ports zu öffnen. Ein einfaches Regelwerk mit iptables ist damit hinterlegt. ACHTUNG! Dies ist meine absolute Minimalkonfiguration. Weitere Dienste müssen natürlich hinzugefügt werden.

Schritt 2: Knockd

Unter Portknocking versteht man, dass ein Benutzer eine festgelegte Reihenfolge von Ports anspricht und so einen Systembefehl startet, z. B. einen Port, der angesprochen werden soll freischaltet. Klingt einfach, ist es auch. Ein Aufruf bspw. von Port 1234, 2345, 3456 wird von einem speziellem Daemon erkannt und darauf hin wird der hinterlegte Befehl ausgeführt. Um diese Technik auf unserem System zu nutzen, nehme ich knockd, dass genau für diesen Zweck konzipiert wurde. Da iptables alle Aufrufe auf diesen Ports von aussen blockiert, lauscht knockd auf der Ebene vor iptables (link-layer level) und kann so trotzdem auf die Aufrufe reagieren. Um knockd zu nutzen, müssen wir es zunächst mal installieren.

sudo apt-get install knockd

Um das Portknocking zu aktivieren müssen wir noch ein paar Schritte durchgehen. Ich habe die Konfiguration so geändert, dass beim Aufruf von Port 1234, 2345, 3456 der Port 9922 geöffnet wird. Das -I INPUT innerhalb der iptables Regel ist wichtig, damit die Regel angewandt wird. Hätte ich die Regel mit -A INPUT hinzugefügt wie in der iptable_rules oben, wäre sie nicht zur Anwendung gekommen, denn sie wäre einfach unten angehängt worden und wäre vorher von REJECT Regel abgelehnt worden.

Der Eintrag start_command öffnet also unseren Port und der Eintrag stop_command, der nach cmd_timeout ausgeführt wird, also nach 10 Sekunden schliesst den offenen Port wieder. Der Platzhalter %IP% steht für Eure Adresse. Es werden also nur Pakete von Euch empfangen und verarbeitet. Die Verbindung kann nach 10 Sekunden bedenklos wieder geschlossen werden denn in den iptables Regeln steht ja, dass bestehende Verbindungen erhalten bleiben sollen. Wir öffnen also die Konfigurationsdatei und ändern die Einträge wie folgt ab.

sudo nano /etc/knockd.conf

 

[options]
        UseSyslog

[openSSH]
        sequence    = 1234,2345,3456
        seq_timeout = 10
        tcpflags    = syn
        start_command = /sbin/iptables -I INPUT -s %IP% -p tcp --syn --dport 9922 -j ACCEPT
        cmd_timeout   = 10
        stop_command  = /sbin/iptables -D INPUT -s %IP% -p tcp --syn --dport 9922 -j ACCEPT

Damit der Daemon jetzt gestartet werden kann, muss noch hinterlegt sein, dass er auch starten darf. Das erledigen wir in einer anderen Datei, wo wir den den Eintrag START_KNOCKD auf den Wert 1 setzen.

sudo nano /etc/default/knockd

 

START_KNOCKD=1

Nun können wir den Dienst starten.

sudo /etc/init.d/knockd start

Schritt 3: Telnet (optional)

Dieses Kapitel ist optional, dennoch würde ich es empfehlen, denn wir werden gleich eine „Operation am offenen Herzen“, sprich OpenSSH vornehmen. Da es dort viel Potential gibt, sich auszusperren, sollten wir auf Nummer sicher gehen und uns temporär einen kleinen Telnetdienst aufsetzen.

sudo apt-get install telnetd

Und danach starten.

sudo /etc/init.d/openbsd-initd start

Solltet Ihr für gewöhnlich Publickeys oder Zertifikate benutzen, solltet Ihr einem priviligiertem User oder root ein Passwort verpassen, damit Ihr Euch mit telnet einloggen könnt. Vorher sollten wir den Port in Iptables noch freischalten.

sudo /sbin/iptables -I INPUT -p tcp --dport 23 -j ACCEPT
sudo passwd

Machen wir einen kurzen Test, ob alles funktioniert, indem Ihr Euch von Eurem lokalem System über Telnet anmeldet.

telnet anonsphere.com

Nach Eingabe von Benutzernamen und Passwort solltet Ihr eigentlich angemeldet sein. Telnet ist keine gute Alternative zu OpenSSH, denn das Protokoll ist im Vergleich sehr unsicher. Nachdem Ihr OpenSSH installiert habt und alles funktioniert, könnt Ihr telnet wieder stoppen, entfernen und das Passwort löschen, sofern Ihr andere Authentifizierungsmechanismen nutzt. Für den Noteingang soll uns das aber einfach mal reichen.

So entfernt Ihr telnet wieder:

sudo /etc/init.d/openbsd-initd stop
sudo iptables -D INPUT -p tcp --dport 23 -j ACCEPT
sudo apt-get remove telnetd
sudo passwd -d login

Schritt 4: OpenSSH

Wenn wir eh schon am OpenSSH Server schrauben, können wir uns auch gleich die aktuellste Version besorgen, dazu besuchen wir die Downloadseiten von OpenSSH und laden die letzte Version mittels wget auf den Server. Dann entpacken wir das Archiv und wechseln in den Ordner.

wget http://openbsd.cs.fau.de/pub/OpenBSD/OpenSSH/portable/openssh-5.9p1.tar.gz
tar -xzvf openssh-5.9p1.tar.gz
cd openssh-5.9p1/

Damit OpenSSH unterscheiden kann, welcher Port gerade angesprochen wird, müssen wir die Quellen patchen, d. h. einige Änderungen einspielen. Dazu habe ich den Patch von Xavier Mertens so umgeschrieben, dass er mit der aktuellen Version 5.9 funktioniert.

wget https://secure.anonsphere.com/files/openssh-5.9-localport.patch
patch -p1 < openssh-5.9-localport.patch

Update: Der Artikel ist schon einige Monate alt. Der Patch funktioniert auch problemlos mit Version 6.0.

Da wir mit unserem Paket die Originalquellen überschreiben, würde eine Installation scheitern. Daher müssen wir zuerst die alten openssh (Server und Client) Pakete entfernen. Bereits offene SSH Verbindungen bleiben erhalten, allerdings können wir uns ab hier nicht mehr neu verbinden, weshalb ich unbedingt zur o. g. temporären Alternative telnet raten würde. Wenn durch Murphys Gesetz gerade jetzt Eure Verbindung getrennt werden würde, wäre das … hm … schlecht.

sudo apt-get remove openssh-server openssh-client

Nun installieren wir zunächst die nötigen Quellpakete zum Kompilieren. Danach können wir das OpenSSH Paket kompilieren und installieren. Evtl. müsst Ihr die Zeile mit ./configure noch anpassen, wenn Ihr z. B. PAM benutzen möchtet. Mehr Infos gibt es mit ./configure --help.

sudo apt-get install build-essentials libwrap-dev zlib1g-dev libssl-dev libpam0g-dev
./configure --exec-prefix=/usr --sysconfdir=/etc/ssh
make
sudo checkinstall

Checkinstall erzeugt uns ein Binärpaket, dass sich auf Wunsch auch wieder deinstallieren lässt, ohne Dateien auf dem Zielsystem zu hinterlassen. Die Werte für Beschreibung und Versionsnummer können ausgefüllt werden, müssen aber nicht. Jetzt können unsere neuen SSH Server starten.

sudo /etc/init.d/ssh restart

Jetzt kommt der Clou der Sache. Wahrscheinlich benutzt Ihr schon ein Konstrukt mit Match Group sftpuser oder Ähnlichem, dass Eure Benutzer auf den internen SFTP Server schickt bzw. ihn einsperrt. Das ist gut, aber wir wollen ja einen speziellen Eingang, der auf dem Port basiert. Zunächst setze ich diese zusätzlichen Regeln, in denen der reguläre OpenSSH Dienst an möglichst allen Schnittstellen lauscht, der Port 9922 aber nur auf einer Domain bzw. an der IP Adresse. Auch das erschwert einem Angreifer zumindest ein bißchen das Leben, denn er muss im Zweifel mehrere IP Adressen ausprobieren.

sudo nano /etc/ssh/sshd_config

 

Listen Address 0.0.0.0:22
Listen Address anonsphere.com:9922

Diese Zeilen besagen, dass jeder, der sich auf dem Standardport von SSH verbindet, automatisch in einer chroot landet und an den internen SFTP Server geleitet wird. Ein Login auf die Konsole ist so nicht möglich. Selbst wenn jemand Euren Privatekey oder Euer Zertifikat stiehlt, kann Euch nicht viel passieren, denn er kann nur auf einen bestimmten Bereich zugreifen und nicht auf das Hauptsystem.

Match LocalPort 22
        ChrootDirectory /var/jail
        ForceCommand internal-sftp
        X11Forwarding no
        AllowTcpForwarding no

Damit die Änderungen wirksam werden, müssen wir jetzt noch den SSH Server neu starten.

sudo /etc/init.d/ssh restart

Eine zusätzliche Möglichkeit ist es, den Login für priviligierte Benutzer nur noch auf Port 9922 zu erlauben, indem wir die Authentifizierung ins Nirvana laufen lassen. Ein Beispiel mit SSH Zertifikaten sähe so aus, dass wir mit dem User login oder mit einer bestimmten Gruppe auf Port 22 die vertrauten Zertifikate aus /dev/null lesen lassen, so dass die Authentifizierung immer fehl schlägt.

Match User login LocalPort 22
        TrustedUserCAKeys /dev/null

Danach muss SSH noch mal neu gestartet werden. Ein Login auf Port 22 für den Benutzer login wird jetzt verweigert als wäre der Publickey falsch.

„Klopf klopf“

Nun müssen wir uns als Admin natürlich noch verbinden können. Dafür öffnen wir eine Konsole und testen einfach mal, was funktioniert.

ssh login@anonsphere.com
This service allows sftp connections only.
Connection to anonsphere.com closed.

Wie wir sehen, die Verbindung schlägt fehl, denn wir können uns auf Port 22 nur noch per SFTP verbinden. Versuchen wir es auf unserem Port.

ssh -p 9922 login@anonsphere.com
ssh: connect to host anonsphere.com port 9922: Connection refused

Die Verbindung wird abgelehnt, denn iptables hat diesen Port nicht freigegeben. So funktioniert es jetzt.

nc -w1 anonsphere.com 1234 ; nc -w1 anonsphere.com 2345 ; nc -w1 anonsphere.com 3456 ; ssh -p 9922 login@anonsphere.com

Diese Zeile tippt man natürlich nicht ein, sondern hinterlegt sie entweder als alias in Eurer .bashrc oder in einer eigenen Bash-Datei. Unser root Zugang ist jetzt zusätzlich abgesichert, ohne dass SFTP Benutzer eingeschränkt werden oder der zusätzliche Zugang nach aussen sichtbar wäre. Neben dem einfachen Ansprechen des TCP Ports über nc gibt es noch die Möglichkeit, knock zu nutzen. Dieser einfache Client wird mit knockd mitgeliefert und kann Ports über tcp und udp ansprechen. Mit einem Kommando kann man ihm eine einfach Sequenz übergeben, die dann ausgeführt wird.

Auf dem Client

apt-get install knockd

 

knock anonsphere.com 1234 2345 3456

„Klopf-Klopf … Klopf“

Der Schutz ist schon gut, nutzt uns aber wenig, wenn ein „schlimmer Finger“ unsere Leitung abhört. Da sich die Reihenfolge der „Klopfer“ nicht ändert, müsste man nur kurze Zeit Eure Verbindung belauschen, um den Code heraus zu finden. Um das zu verhindern gibt uns knockd die Möglichkeit eine Liste mit Codes abzuarbeiten. Dieses Verfahren ist besonders sicher, weil jede herausgefunde Information sofort wertlos wird ähnlich einer TAN Liste.

Als Hilfsmittel benutze ich knock-once, dass wir per wget auf den Server und unseren lokalen Rechner übertragen.

wget http://downloads.sourceforge.net/project/knockonce/knock-once-1.2.tar.gz?r=http%3A%2F%2Fsourceforge.net%2Fprojects%2Fknockonce%2Ffiles%2F&ts=1315593859&use_mirror=switch

Das Archiv entpacken wir und kopieren die Datei knock-once z. B. in den Ordner /usr/local/bin und geben ihm Auführungsrechte. Dies machen wir sowohl auf dem Server als auch auf dem Client. Knockd muss auf beiden Systemen installiert sein.

tar -xzvf knock-once.tar.gz
sudo cp knock-once/knock-once /usr/local/bin/
sudo chmod +x /usr/local/bin/knock-once

Auf dem Server oder Client erzeugen wir uns jetzt eine Liste mit zufälligen Ports. Diese Ports werden in einer Datei knock-once_sequences abgespeichert. Diese übertragen wir auf den anderen Rechner. Dieses Kommando erzeugt uns eine Liste mit 100 Einträgen mit je 3 Sequenzen.

knock-once -g

Auf dem Server müssen wir in der Datei /etc/knockd.conf unsere Änderungen eintragen. Der Einfachheit halber nehme ich den Ort, wo wir die Datei erzeugt haben, sprich das Benutzerverzeichnis. Man kann dafür sicher auch einen anderen Platz finden, aber uns soll das reichen.

[openSSH]
        one_time_sequences	= /home/login/knock-once_sequences
        seq_timeout		= 10
        tcpflags		= syn
        start_command		= /sbin/iptables -I INPUT -s %IP% -p tcp --syn --dport 9922 -j ACCEPT
        cmd_timeout		= 10
        stop_command		= /sbin/iptables -D INPUT -s %IP% -p tcp --syn --dport 9922 -j ACCEPT

Das Kommando sagt knockd, dass die Daten aus der knock-once_sequences Datei gelesen und nacheinander „abgehakt“ werden. Wichtig dabei ist, dass beide Dateien synchron sind. Es wird immer nur der erste nicht auskommentierte Eintrag überprüft und danach eine Raute vorgesetzt. Damit ist diese Zeile nicht mehr benutzbar. Dieses Verfahren kann auch von mehreren Benutzern angewandt werden, indem man weitere Einträge unter anderem Namen in die knockd.conf schreibt für verschiedene Benutzer. Jeder arbeitet dann seine eigene Liste ab. Dieses Verfahren ist sehr sicher, denn die Ports sind zufällig erzeugt. Den nächsten Eintrag kann man nur schwer raten. Vom Client aus wird knock-once so aufgerufen. Der Pfad der knock-once_sequences muss evtl. angepasst werden.

knock-once  --comment-sequence ~/knock-once_sequences anonsphere.com

Der Schlüssel im Blumentopf

Dieses Prinzip hat einen einen großen Nachteil. Sobald die Liste aufgebraucht ist, funktioniert das Klopfen und damit auch das Öffnen des Ports nicht mehr. Um trotzdem ruhig zu schlafen, können einen weiteren Bereich anlegen, der uns immer über eine feste Sequenz auf unseren Port zugreifen lässt. Dazu fügen wir einfach folgende Passage an.

[openSSH_Notlogin]
        sequence    = 1234,2345,3456,4567,5678
        seq_timeout = 10
        tcpflags    = syn
        start_command = /sbin/iptables -I INPUT -s %IP% -p tcp --syn --dport 9922 -j ACCEPT
        cmd_timeout   = 10
        stop_command  = /sbin/iptables -D INPUT -s %IP% -p tcp --syn --dport 9922 -j ACCEPT

Diese Methode ist dann ungeheuer nützlich, wenn wir nicht am eigenen Rechner sitzen, aus anderen Gründen unsere Liste nicht verwenden können oder wenn diese Liste aufgebraucht ist. Der Sicherheit tut es keinen großen Abbruch, denn wir benutzen diesen speziellen Code ja nur im Not- und niemals im Regelfall. Ein einmaliger Login schadet der Gesamtsicherheit wenig, denn ein Angreifer müsste schon über einen sehr langen Zeitraum und evtl. an verschiedenen Standorten unsere Verbindung protokollieren, um ausgerechnet diese Sequenz zu erkennen.

Neue Liste auf Befehl

Eine zweite, bessere Idee kam mir beim Login auf Google. Jeder Webseite, die einen Login erfordert, hat eine Funktion, um das Passwort zurück zu setzen. Natürlich kann das auch knockd selbst. Dazu benötigen wir eine bash Datei. Diese lege ich in /usr/local/bin/reset-knockd an und füge folgendes ein.

#!/bin/sh
export FPATH="/home/login"
/usr/bin/sudo /bin/rm $FPATH/knock-once_sequences $FPATH/knock-once_sequences.gpg
/usr/bin/sudo /usr/local/bin/knock-once -g -n 1000 -l 5 -o $FPATH/knock-once_sequences
/usr/bin/sudo /bin/chmod 600 $FPATH/knock-once_sequences
/usr/bin/sudo /etc/init.d/knockd restart
/usr/bin/sudo /usr/bin/gpg --yes --trust-model always -e -r 8F6E14DE $FPATH/knock-once_sequences
/usr/bin/sudo /usr/bin/mutt -a $FPATH/knock-once_sequences.gpg -s "Neue Liste" -- oliver@mail.anonsphere.com < /dev/null

Ein Aufruf von reset-knockd löscht die alten Dateien, erzeugt eine neue Liste im angegebenen Verzeichnis (diesmal 1000 Zeilen mit je 5 Sequenzen), verschlüsselt diese mit gnupg und mailt das ganze als Anhang an unsere E-Mail Adresse. Falls Ihr mutt noch nicht installiert habt, sollten wir das als erstes tun. Ich gehe mal davon aus, dass ihr einen gültigen gpg Schlüssel habt und damit umgehen könnt. Falls ihr keine Verschlüsselung wünscht, entfernt alle Einträge, die mit gpg zu tun haben.

sudo apt-get install mutt

Um knockd dieses Kommando ausführen zu lassen, können wir diesen Abschnitt in /etc/knockd.conf hinterlegen. Das abkapseln vom knockd Prozess ist wichtig, weil der Daemon sonst auf das Feedback wartet und dabei abstürzt.

[openSSHReset]
        sequence    = 1111,2222,3333,4444,5555
        seq_timeout = 10
        tcpflags    = syn
        command    = /usr/local/bin/reset-knockd &> /dev/null

Neue Liste beim Login

Eine andere Idee kam mir mit dem Login auf dem Server selbst. Wenn wir uns einloggen und es sind nicht mehr genug Einträge vorhanden, können wir uns automatisiert eine neue Liste erzeugen und an uns selbst mailen. Dazu gehen wir noch mal auf unseren Server, loggen uns ein und bearbeiten unsere .bashrc im home Ordner des Benutzers, der sich anmeldet. Die erste Zeile überprüft erstmal, ob noch mindestens 3 Einträge vorhanden sind und wenn nicht, dann wird unsere reset-knockd ausgeführt.

nano .bashrc

 

if [ $(sudo cat /home/login/knock-once_sequences | grep -v '#' | wc -l) -lt 3 ]; then
        /usr/local/bin/reset-knockd &
        echo "Neue Liste gemailt"
fi

Die verschlüsselte Liste könnt Ihr wie gewohnt mit gpg -e entpacken und die Liste in einer lokalen Datei hinterlegen. Falls Ihr Thunderbird mit Enigmail benutzt, könnt Ihr den Anhang über das Kontextmenü zum Anhang „Entschlüsseln und abspeichern“ die Datei sofort an der richtigen Stelle ablegen. Komfortabler geht es eigentlich nicht.

Der eigene Schlüssel

Um sich auch noch bequem anzumelden, können wir auf unserem Client folgendes in der .bashrc hinterlegen. Ein Aufruf von anonsphere klopft bei unserem Server an und sendet eine Sequenz, aber nur, falls Port 9922 blockiert ist. Ansonsten erfolgt sofort der Login. Evtl. müsst Ihr zusätzlich noch nmap installieren.

anonsphere() {
        if [ $(nmap -p9922 anonsphere.com | grep 9922 | grep closed | wc -l) -gt 0 ]; then
                knock-once  --comment-sequence ~/knock-once_sequences login@anonsphere.com ; ssh -p 9922 login@anonsphere.com
        else
                ssh -p 9922 login@anonsphere.com
        fi
}

Die Funktion bremst das Ganze etwas. Ich persönlich nutze einfach ein alias.

alias anonsphere="knock-once --comment-sequence ~/knock-once_sequences anonsphere.com"

Was noch so geht

Knockd kann jeden Systembefehl ausführen. Da er mit root Rechten arbeitet, wäre es z. B. problemlos möglich, verschlüsselte Ordner auszuhängen. Das ist dann nützlich, wenn man im Zuge einer Beschlagnahmung oder eines erfolgreichen Hackerangriffs seine privaten Daten wie E-Mails oder Datenbanken in Sicherheit bringen will ohne lange Umwege. Meistens kommt es dann auf Sekunden an.

Auch ein kompletter Server Lockdown wäre möglich. Sagen wir, ein Server wird per DDOS oder per Brute Force attackiert. Dann wäre es über eine einfach Sequenz möglich, sämtlichen Traffic auf allen Ports abzuweisen bis die Gefahr vorüber ist. Sich selbst kann man über die Platzhalter ausnehmen oder den Zugang mit einer anderen Sequenz manuell wieder freischalten.

Noch ein paar hilfreiche Tips

Kockd kann selbst nur an einem Port lauschen. Das ist bei mir z. B. problematisch, weil ich mich auch per VPN mit meinem Server verbinde. Ein regulärer Login führt also nicht über eth0, sondern über tun0. Eine Sequenz würde verfeuert ohne Nutzen. Diese Zeile Code sorgt dafür, dass knockd auf eth0 und tun0 lauscht.

killall -9 knockd ; knockd -d -i eth0 -c /etc/knockd.conf ; knockd -d -i tun0 -c /etc/knockd.conf

Das nächste „Problem“ ist, dass die Verbindung mit knock-once sehr lange dauert, weil zwischen den Pings eine unnötige Pause gemacht wird. Dies können wir mit dem Parameter d ändern:

knock-once -d 0 --comment-sequence ~/knock-once_sequences anonsphere.com

Sollte eine Sequenz aus welchen Gründen auch immer nicht funktionieren, z. B. weil die Liste abgearbeitet wurde, während Eure Internetverbindung nicht richtig funktionierte, lässt sich das Problem so lösen:

sed -i 's/#/ /g' ~/knock-once_sequences && while true; do knock-once -d 0 --comment-sequence ~/knock-once_sequences anonsphere.com ; ssh -p 9922 login@anonsphere.com; done

Alle getesteten Zeilen werden wie üblich markiert bis die richtige gefunden ist. Nachdem die Verbindung erfolgreich war, solltet Ihr das Terminal einfach schliessen. Eure Liste auf dem Client ist jetzt wieder aktuell. Ein Logout endet in einer neuen Anmeldung (ausser durch heftigen Gebrauch von Strg + c).

Fazit

Mit knockd ist es sehr einfach und vor allem komfortabel möglich, Eure Serverzugänge zusätzlich abzusichern. Die Konfiguration ist einfach und das Verfahren ist für jeden Angreifer eine echte Hürde. Das Ganze entlässt Euch aber nicht von der Verwendung sicherer Passwörter oder noch besser Publickeys bzw. SSH Zertifikaten. Ein echter Nachteil ist natürlich das manuelle Patchen von OpenSSH. Ich habe aber die Hoffnung, dass die Entwickler es irgendwann mal standardmässig unterstützen, denn an sich sind alle nötigen Funktionen schon vorhanden.

Written by Oliver

August 31st, 2012 at 10:20 am

6 Responses to '„Klopf-Klopf“ … wer da?'

Subscribe to comments with RSS or TrackBack to '„Klopf-Klopf“ … wer da?'.

  1. Habe in meinen Serveranfangsseiten auch knockd benutzt. Allerdings habe ich das Konzept nach cq. 2 Jahren aufgegeben: Zu kompliziert, gerade wenn man mal in nicht gewohnter Umgebung auf den Server muss – bei mir gab es manchmal Probleme, sich aus dem Ausland durchzuknocken.

    Zum Aussperren: Ich selbst habe nur immer Server, die eine Remote Konsole über eine 2. IP anbieten. Damit kann man selbst bei eoiner verkorksten iptables Konfiguration noch auf dem Server arbeiten.

    „Auch ein kompletter Server Lockdown wäre möglich. Sagen wir, ein Server wird per DDOS oder per Brute Force attackiert. Dann wäre es über eine einfach Sequenz möglich, sämtlichen Traffic auf allen Ports abzuweisen bis die Gefahr vorüber ist.“

    Das ist ja etwas sinnfrei. Wenn die Büchse eh kaum erreichbar ist, was soll es dann bringen, via knockd alles dichtzumachen. Ich denke, dass ein ifconfig eth0 down wesentlich effizienter ist – vorausgesetzt, man hat einen 2. Zugang zum Server. Das Dichtmachen des kompletten Traffics mit Ausschluss der eigenen IP ist mit dynamischen IPs auch eher kompliziert und hinderlich als produktiv.

    Holgersen

    31 Aug 12 at 11:10

  2. Sorry, aber die Aussage dass ein veränderter SSH-Port den Rechner/Server erst „richtig interessant“ erscheinen lässt, halte ich für falsch. Viele Einbrüche auf einem Server sind automatisierte Brut-Force-Attacken. Diese werde oft auch von unerfahrenen „Hackern“ benutzt, um Systeme zu erobern. Dort ist der umgezogene Port schon die halbe Miete, auch wenn es kein Allheilmittel ist.
    Für die 0815-Hacker, die nur eine Kiste zum Scannen suchen, ist der Rechner somit meist uninteressant geworden. Denn man kann den Schluss ziehen: Wer den Port ändert, wird eventuell den Server besser beobachten und eher den Einbruch feststellen.

    Was bleibt (und sich nicht vom Port schrecken lässt) sind jene Hacker, die unbedingt diesen einen Server wollen. Dies hat dann aber andere Gründe. Kann sein, dass der Hacker den Pagerank einer bekannten Seite ausnutzen will. Oder dass es ein Service ist, bei dem man Kreditkarten vermuten kann.

    Die Frage die sich mir also stellt ist: Was für einen Server hast du im Selbsttest benutzt? Welche (bekannten) Domains sind da geparkt?

    Die Anleitung ist toll. Däumchen hoch!

    Sebastian

    31 Aug 12 at 12:58

  3. @Holgersen
    Also ich benutze das jetzt seit 1 Jahr etwa (fast so alt ist auch die Anleitung) und ich hatte mit dem Klopfen selbst nie Probleme. Auch nicht über ausländische VPNs o. ä. Kann es evtl. sein, dass Du in Netzwerken warst, die den Traffic filtern? Hotels oder öffentliche Wlans oder so? Ich habe es auch so, dass ich die Adminzugänge kaum brauche, weil ich die Dateien für den Webserver per SFTP ändere. Im Monat verbrauche ich so 20 Zeilen etwa.

    @Sebastian
    Natürlich kann man auch die Ports nur so umbiegen, allerdings schreib ich dann groß auf meinen Eingang „such doch mal“. So kann ein Angreifer sich auf dem SFTP Zugang richtig austoben und kriegt doch nicht, was er eigentlich wollte. Auf dem Server sind so 10 kleine Domains mit wenig Traffic.

    Oliver

    31 Aug 12 at 21:29

  4. […] von Anderen angewiesen. Diese sind oftmals, und das sage ich aus eigener Erfahrung, nicht so gesichert, wie man es eigentlich erwarten kann. Das ist aber auch nicht weiter verwunderlich, denn […]

  5. […] von Anderen angewiesen. Diese sind oftmals, und das sage ich aus eigener Erfahrung, nicht so gesichert, wie man es eigentlich erwarten kann. Das ist aber auch nicht weiter verwunderlich, denn […]

  6. […] https://www.phpgangsta.de/klopf-klopf-wer-da ‎Ein sehr tiefgehender Atikel über das Sicherheitskonzept “Portknocking”. Der Artikel ist in deutsch verfasst.‎ […]

Leave a Reply

You can add images to your comment by clicking here.