Nachdem die Grundlagen geklärt sind, benötigen wir die entsprechenden Firewall Regeln.

Zunächst macht es Sinn die Filter-Regeln für das Port-Knocking nicht direkt in die input Chain zu schreiben, sondern eine eigene Chain für ICMP Typ 8 Pakete zu erstellen, die wir auch betrachten wollen.

/ip firewall filter add action=jump chain=input icmp-options=8:0-255 \
    jump-target=knock packet-size=!0-99 protocol=icmp

Diese Regel sollte recht früh in der input Chain hinterlegt sein, auf jeden Fall vor einer Regel, die das ICMP als solches akzeptiert.

In diesem Fall werden alle Pakete des Protokolls ICMP sofern sie vom Typ 8 sind und die Paketgröße nicht 0-99 Bytes ist in die Chain mit dem Namen knock umgeleitet.

Damit achtet diese Regel nicht auf Pakete die vom normalen Ping Befehl ohne zusätzliche Parameter erstellt werden. Es ist daher auch möglich in der Folge einen normalen Ping nicht anzunehmen und zu droppen.

Die Chain knock kann dann wie folgt aussehen:

/ip firewall filter
add action=return chain=knock src-address-list=knock-fail
add action=add-src-to-address-list address-list=knock-success \
    address-list-timeout=20s chain=knock log=yes \
    log-prefix="successful ping-knock" packet-size=265 \
    src-address-list=knock-2
add action=return chain=knock src-address-list=knock-success
add action=add-src-to-address-list address-list=knock-fail \
address-list-timeout=1m chain=knock src-address-list=knock-2
add action=return chain=knock src-address-list=knock-fail
add action=add-src-to-address-list address-list=knock-2 \
address-list-timeout=10s chain=knock packet-size=745 \
src-address-list=knock-1
add action=return chain=knock src-address-list=knock-2
add action=add-src-to-address-list address-list=knock-fail \
address-list-timeout=1m chain=knock src-address-list=knock-1
add action=return chain=knock src-address-list=knock-fail
add action=add-src-to-address-list address-list=knock-1 \
address-list-timeout=10s chain=knock packet-size=363
add action=return chain=knock src-address-list=knock-1
add action=add-src-to-address-list address-list=knock-fail \
address-list-timeout=1m chain=knock

Das ist ein recht großer Block, den wir im Folgenden zeilenweise zerlegen müssen. Warum ist dies soviel Code obwohl nur die Größe geprüft wird? Es wird nicht nur die Größe eines ankommenden Paketes geprüft, sondern die von mehreren nacheinander ankommenden Paketen. In diesem Fall werden 3 Pakete geprüft, die zeitlich auch nur jeweils 10 Sekunden auseinander liegen dürfen. Nachdem die 3 Pakete eingetroffen sind wird das Fenster für 20 Sekunden geöffnet. Das reicht z. B. für ssh aus um eine Verbindung aufzubauen.

Fangen wir oben an:

add action=return chain=knock src-address-list=knock-fail

Alle Absender, die bereits in der address-list knock-fail stehen werden direkt zurück in das normale Regelwerk nach dem jump geschickt. Diese address-list wird von den weiteren Regeln mit Einträgen versehen, falls unerwartete Pakete eintreffen. Der Zugriff wird über diese Regel quasi gesperrt bis der address-list Eintrag für den Absender abgelaufen ist. Einzusehen sind die address-list Einträge unter /ip firewall address-list.

add action=add-src-to-address-list address-list=knock-success \
    address-list-timeout=20s chain=knock log=yes \
    log-prefix="successful ping-knock" packet-size=265 \
    src-address-list=knock-2

Mit dieser Regel wird für einen Absender, der in der address-list knock-2 steht und ein Paket mit 265 Bytes sendet ein Eintrag in der address-list knock-success erstellt, der für 20 Sekunden gültig ist. Dies ist eigentlich der letzte Ping. Da wir von Ping zu Ping den knock - Level erhöhen müssen wir zunächst die höheren Level prüfen.

add action=return chain=knock src-address-list=knock-success

Wenn der Absender bereits in der address-list knock-success ist werden keine weiteren Regeln durchlaufen und es wird zurück an die Regel nach dem jump in die knock Chain gesprungen.

add action=add-src-to-address-list address-list=knock-fail \
address-list-timeout=1m chain=knock src-address-list=knock-2

Diese Regel schützt gegen Angreifer indem sie falls der Absender in der address-list knock-2 ist und ein Paket schickt, dass - in unserem Fall - nicht vorher (2 Regeln zurück) schon mit 265 Bytes erkannt wurde, den Absender in die adress-list knock-fail für 1 Minute einträgt. Innerhalb dieser Minute würde der Angreifer dann durch die erste Regel dieser Chain immer wieder geblockt.

add action=return chain=knock src-address-list=knock-fail

Damit das aktuelle Paket nicht weiter bearbeitet wird falls es in der address-list knock-fail ist, springt diese Regel zurück zum jump in die Chain. Obwohl diese Regel gleich mit der ersten Regel dieser Chain ist, ist sie wichtig um das aktuelle Paket nicht weiter zu bearbeiten, die erste Regel verhindert nur, dass neue Pakete nicht abgearbeitet werden.

add action=add-src-to-address-list address-list=knock-2 \
address-list-timeout=10s chain=knock packet-size=745 \
src-address-list=knock-1
add action=return chain=knock src-address-list=knock-2
add action=add-src-to-address-list address-list=knock-fail \
address-list-timeout=1m chain=knock src-address-list=knock-1
add action=return chain=knock src-address-list=knock-fail

Die gleichen Regeln wiederholen sich jetzt für den davor liegenden Ping. Dieser muss 745 Bytes gross und der Absender zuvor in der address-list knock-1 sein.

add action=add-src-to-address-list address-list=knock-1 \
address-list-timeout=10s chain=knock packet-size=363
add action=return chain=knock src-address-list=knock-1
add action=add-src-to-address-list address-list=knock-fail \
address-list-timeout=1m chain=knock

Der letzte Block ist ein wenig kleiner. Er ist für den ersten Ping. Wenn der Absender in keiner der bisher geprüfen address-list war wir hier auf eine Größe von 363 Bytes geprüft. Der Absender landet dann entweder in der knock-1 oder der knock-fail address-list.

Damit haben wir eine Ping - Reihenfolge von 363 Bytes, 745 Bytes und 265 Bytes.

Wenn nun im Abstand von jeweils maximal 10 Sekunden Pakete mit den angebenen Größen per Ping eingehen, wird der Absender für 20 Sekunden in die address-list knock-success aufgenommen.

Mit weiteren Regeln kann dann z. B. für SSH geprüft werden ob der Absender in der Liste ist. Beispiel:

/ip firewall filter
add action=accept chain=input port=22 protocol=tcp \
src-address-list=knock-success

Die folgenden Befehle würden dann das Port-Knocking durchführen und einen SSH starten:

user@linux $ ping -c 1 -s 335 1.1.1.1
user@linux $ ping -c 1 -s 717 1.1.1.1
user@linux $ ping -c 1 -s 237 1.1.1.1
user@linux $ ssh user@1.1.1.1

Bitte nicht die hier vorgeschlagenen Werte in der eigenen Firewall benutzen.

Last modified: Wednesday, 6 January 2021, 2:56 PM