Das kennt jeder Admin: Es gibt da einen Server der nur einen Dienst anbietet. Und sonst nichts. Trotzdem gibt es viele Zugriffe auf andere Ports. Die wo das versuchen dürfen gerne künftig geblockt werden – mit fail2ban.

Natürlich gibt es honeypot Lösungen mit allem Luxus. Zum Teil tut es aber was deutlich einfacheres. Hier eine Lösung wenn es schnell gehen muss mit systemd und fail2ban. Ja, die erkennt keine ausgeklügelten Portscans. Darum geht es mir aber auch gar nicht. Ich suche eine Lösung für alle tcp Verbindungen die „richtig“ aufgebaut wurden. Das reicht mir völlig aus.

Die Logik dazu: Irgendein einfaches Tool, welches idealerweise bei jedem gängigen Linux verfügbar ist, lauscht auf diverse nicht gebrauchte TCP-Ports. Sobald sich jemand verbindet schreibe einen entsprechenden Eintrag ins syslog und beende die Verbindung. Und hier kommt fail2ban ins Spiel: Werte das syslog aus und sperre gefundene Quell-IPs nach n Versuchen. Unterm Strich 3 Dinge die man braucht: fail2ban, lausche auf Ports, schreibe was weg. Ich zeige die notwendigen Schritte anhand Ubuntu 20.04.

Einige neuere Distributionen haben syslog durch das Journal von systemd ersetzt. Sinngemäß funktioniert das damals hier gezeigte Prinzip weiterhin: logger muss durch systemd-cat ersetzt sowie in der fail2ban jail Definition das Backend auf systemd gesetzt werden.

1. fail2ban

Für fail2ban benötigt man einen Filter sowie ein passendes Jail:

[Definition]
failregex = f2b_dummy_port: Connect from <HOST> \d+
ignoreregex =
[f2b_dummy_port]
enabled = true
filter = f2b_dummy_port
logpath = /var/log/syslog
maxretry = 2

Noch ein kurzer Einschub zu fail2ban: Mir ist genau genommen egal was da für ein Dienst kontaktiert wird: Der vermeintliche „Angriff“ geht auf etwas was es nicht gibt, also Sperre die Quell-IP komplett. Egal auf welchen Port der gerade wollte. Da bin ich nachtragend 😉 Somit steht bei mir in meiner jail.local unter anderem das hier drin:

[DEFAULT]
banaction = route

 

2. Lausche auf Ports

… und schreibe was ins syslog. Syslog für Arme oder wenn es schnell gehen muss: logger. Und lausche auf Ports? Früher hätte ich sowas wie xinetd verwendet. Heute nehme ich systemd. Auch hier wieder braucht es 2 Dateien: Einen Socket der auf die Ports lauscht sowie einen Service welcher letztendlich die Aktion, also den Eintrag ins Syslog schreibt.

[Unit]
Description=fail2ban dummy port listener
After=network.target

[Socket]
ListenStream=7
ListenStream=13
ListenStream=20
ListenStream=21
ListenStream=23
ListenStream=70
ListenStream=110
ListenStream=143
ListenStream=389
Accept=true

[Install]
WantedBy=multi-user.target

Das ist unterm Strich eine einfache Socket-Datei wie für systemd üblich. Das Netzwerk sollte gestartet sein und lausche auf diverse Ports. Hier enthalten eine einfache Beispielliste. Port 80 und 443 fehlen bei mir: Richtig, ist ein Webserver. Die sollten erreicht werden. Was passiert wenn sich jemand verbindet? Systemd sucht eine passende Service Definition.

3. Schreibe ins syslog

Wie gehabt, das geht kurz und knackig: Starte eine Shell wegen der Umgebungsvariablen und schreibe via logger einen Eintrag ins syslog.

[Unit]
Description=fail2ban dummy port listener

[Service]
ExecStart=/bin/bash -c "/usr/bin/logger -t f2b_dummy_port Connect from $REMOTE_ADDR $REMOTE_PORT"

4. Zum Schluss

Was, fehlt noch etwas? Ja, tut es: Dienste neustarten 😉

systemctl daemon-reload
systemctl enable f2b_dummy_port.socket
systemctl start f2b_dummy_port.socket
systemctl restart fail2ban.service

Ein paar Stunden später noch die Erfolgskontrolle:

Status for the jail: f2b_dummy_port
|- Filter
|  |- Currently failed:	1
|  |- Total failed:	1375
|  `- File list:	/var/log/syslog
`- Actions
   |- Currently banned:	xx
   |- Total banned:	352
   `- Banned IP list:	xxxxxxxx

Funktioniert. Was ist die Welt schlecht wenn man betrachtet wie viele IP-Adressen diesem einfachen System sprichwörtlich auf den Leim gehen.