Fail2ban
Siehe auch
- Ansible-Rolle Fail2ban:
Das 2004 erschienene Intrusion Prevention System Fail2ban (sinngemäss „Fehlschlag führt zum Bann“) scannt beliebige Log-Dateien mit Filtern auf bestimmte Muster und löst daraufhin eine oder mehrere frei definierbare Actions aus.
Als Aktionen kann Fail2ban beispielsweise:
die zugreifende IP-Adresse für einen definierten Zeitraum per iptables, firewalld, pf, ipfw oder nftables sperren
Mails inkl. Informationen über den Angreifer senden
die verdächtige IP auf Blocklists eintragen
dynamische DNS-Updates vornehmen
Filter werden durch anpassbare reguläre Ausdrücke definiert. Fail2ban wird mit einem umfangreichen Filter-Satz für verschiedenste Daemons wie Apache, SSH und andere geliefert.
Filter finden sich unter /etc/fail2ban/filter.d
, Aktionen unter /etc/fail2ban/action.d
(wo sie auch direkt konfiguriert werden können, z.B. für den Mail-Versand).
Die Kombination aus Filter, Action und einigen weiteren Konfigurationsparametern wird als Jail (Gefängnis) bezeichnet. Für jede Software, die Logdateien erstellt, kann ein Jail erstellt werden.
Fail2ban ist in Python geschrieben und arbeitet seit v0.9 intern mit einer SQLite-Datenbank in /var/lib/fail2ban/fail2ban.sqlite3
, um seine Zustandsinformationen zu speichern. Die Datenbank wird auf im Internet hängenden Systemen auch mal 1 GB gross, kann jederzeit gelöscht werden; beim Neustart legt Fail2ban diese einfach wieder an.
Fail2ban besticht durch seine Schlichtheit, seine Unabhängigkeit von den zu prüfenden Diensten und durch die breite Anwendbarkeit.
Die Verzeichnisstruktur:
/etc/fail2ban
├── action.d:
│ Aktionen, die in einem Jail als "action"
│ angegeben werden können
│── filter.d:
│ Definition regulärer Ausdrücke, um Log-
│ Dateien zu untersuchen
└── jail.local:
Definition des "Gefängnisses" - welche Log-
Dateien sollen mit welchem Filter untersucht werden,
welche Aktionen sind anzuwenden, wie lange soll
geblockt werden usw.
- Links
Doku (bis 0.8): https://www.fail2ban.org/wiki/index.php
Developer-Doku: https://fail2ban.readthedocs.io/en/latest/
Source Code: https://github.com/fail2ban/fail2ban/
Wikipedia: https://de.wikipedia.org/wiki/Fail2ban, https://en.wikipedia.org/wiki/Fail2ban
Tipp
In Fail2ban-Konfigurationsdateien Kommentare nie an das Ende von Konfigurationsanweisungen stellen - sonst wird die ganze Zeile deaktiviert. Kommentare gehören immer in eigene Zeilen.
Installation und Konfiguration
Fail2ban muss dort installiert werden, wo die auszuwertenden Log-Dateien liegen. Installiert wird es aus dem EPEL-Repo:
yum -y install fail2ban whois
systemctl enable --now fail2ban
Fail2ban sollte nach dem Start der lokalen Firewall hochfahren, im Beispiel fwb.service
. Bei Bedarf ist daher das Unit-File anzupassen:
After=default.target fwb.service #PartOf=firewalld.service
Der Installer für CentOS ignoriert schon seit Jahren (Stand 2020-11) ein paar Actions, von denen aber zugegeben auch nicht alle auf einem CentOS Sinn machen. Der Vollständigkeit halber:
# get the missing mail action files from GitHub
VER=$(fail2ban-server -V)
cd /etc/fail2ban/action.d
wget https://raw.githubusercontent.com/fail2ban/fail2ban/$VER/config/action.d/bsd-ipfw.conf
wget https://raw.githubusercontent.com/fail2ban/fail2ban/$VER/config/action.d/cloudflare.conf
wget https://raw.githubusercontent.com/fail2ban/fail2ban/$VER/config/action.d/hostsdeny.conf
wget https://raw.githubusercontent.com/fail2ban/fail2ban/$VER/config/action.d/ipfilter.conf
wget https://raw.githubusercontent.com/fail2ban/fail2ban/$VER/config/action.d/ipfw.conf
wget https://raw.githubusercontent.com/fail2ban/fail2ban/$VER/config/action.d/mail-buffered.conf
wget https://raw.githubusercontent.com/fail2ban/fail2ban/$VER/config/action.d/mail-whois-lines.conf
wget https://raw.githubusercontent.com/fail2ban/fail2ban/$VER/config/action.d/mail-whois.conf
wget https://raw.githubusercontent.com/fail2ban/fail2ban/$VER/config/action.d/mail.conf
wget https://raw.githubusercontent.com/fail2ban/fail2ban/$VER/config/action.d/osx-afctl.conf
wget https://raw.githubusercontent.com/fail2ban/fail2ban/$VER/config/action.d/osx-ipfw.conf
wget https://raw.githubusercontent.com/fail2ban/fail2ban/$VER/config/action.d/pf.conf
wget https://raw.githubusercontent.com/fail2ban/fail2ban/$VER/config/action.d/shorewall.conf
Ob Fail2ban arbeitet und was es macht, lässt sich per tail -f /var/log/messages /var/log/fail2ban.log
überprüfen - in der Regel genügt ein LogLevel ab NOTICE aufwärts. Von besonderem Interesse sind die Meldungen fail2ban.actions ... NOTICE [sshd] Ban 10.80.32.156
und ... Unban 10.80.32.156
in /var/log/fail2ban.log
.
Deinstallation
systemctl stop fail2ban
systemctl disable fail2ban
yum -y remove fail2ban
Danach:
rm -rf /etc/fail2ban
rm -f /etc/logrotate.d/fail2ban
rm -rf /etc/selinux/targeted/active/modules/100/fail2ban
rm -rf /run/fail2ban
rm -f /usr/bin/fail2ban*
rm -rf /usr/lib/python2.7/site-packages/fail2ban*
rm -f /usr/lib/systemd/system/fail2ban.service
rm -f /usr/lib/tmpfiles.d/fail2ban.conf
rm -rf /usr/share/doc/fail2ban*
rm -f /usr/share/man/man1/fail2ban*
rm -rf /var/lib/fail2ban
rm -f /var/log/fail2ban\*
Fail2ban konfigurieren
Vorgehensweise
Optional: Filter entwickeln und testen
Optional: Action entwickeln und testen
Jail konfigurieren - Filter, Actions und Rahmenbedingungen zusammenführen
Filter entwickeln
In den regulären Ausdrücken kann <HOST>
verwendet werden, wenn man die anfragende IP-Adresse matchen möchte - diese Variable ist daher auch in jedem Ausdruck Pflicht.
Reguläre Ausdrücke können so getestet werden:
fail2ban-regex -v /var/log/httpd/access_log 'myregex'
Im Beispiel soll ein Filter entwickelt werden, der eine übermässige Nutzung des Apache httpd verhindert. Erkennbar wird dies in /var/log/httpd/access*log
-Dateien durch eine massive Flutung von GET-Requests von der gleichen IP. Am Ende möchten wir also einfach gegen die Anzahl aller Requests in einem bestimmten Zeitraum matchen.
# Fail2Ban filter to massive web requests for any ressources on Apache servers
#
# if bantime is low, it effectively slows down a ``ab -n 5000 http://ip-of-my-host/``
[INCLUDES]
# overwrite with apache-common.local if _apache_error_client is incorrect.
before = apache-common.conf
[Definition]
failregex = ^<HOST>
datepattern = ^[^\[]*\[({DATE})
{^LN-BEG}
# DEV Notes:
#
# example log lines:
# 10.80.32.156 - - [27/Nov/2020:14:10:55 +0100] "GET / HTTP/1.0" 200 252910 9921 www.linuxfabrik.ch -
# 10.80.32.156 - - [27/Nov/2020:14:10:55 +0100] "GET / HTTP/1.0" 200 252910 8355 www.linuxfabrik.ch -
# 10.80.32.156 - - [27/Nov/2020:14:10:55 +0100] "GET / HTTP/1.0" 200 252910 8961 www.linuxfabrik.ch -
# 10.80.32.156 - - [27/Nov/2020:14:10:55 +0100] "GET / HTTP/1.0" 200 252910 8165 www.linuxfabrik.ch -
#
# Author: Linuxfabrik GmbH, Zurich, Switzerland
# Contact: info (at) linuxfabrik (dot) ch
# https://www.linuxfabrik.ch/
# License: The Unlicense, see LICENSE file.
Test gegen das bestehende Logfile.
fail2ban-regex -v /var/log/httpd/access_log /etc/fail2ban/filter.d/linuxfabrik-apache-dos.conf
Die zweimalige Angabe der Filter-Datei füttert das Kommando einmal mit dem failregex- und das zweite mal mit dem ignoreregex-Ausdruck (der in unserem Filter nicht vorhanden ist):
fail2ban-regex -v /var/log/httpd/access_log /etc/fail2ban/filter.d/linuxfabrik-apache-dos.conf /etc/fail2ban/filter.d/linuxfabrik-apache-dos.conf
Es geht noch etwas genauer:
fail2ban-regex /var/log/messages /etc/fail2ban/filter.d/linuxfabrik-apache-dos.conf /etc/fail2ban/filter.d/linuxfabrik-apache-dos.conf --print-all-matched
fail2ban-regex /var/log/messages /etc/fail2ban/filter.d/linuxfabrik-apache-dos.conf /etc/fail2ban/filter.d/linuxfabrik-apache-dos.conf --print-all-missed
fail2ban-regex /var/log/messages /etc/fail2ban/filter.d/linuxfabrik-apache-dos.conf /etc/fail2ban/filter.d/linuxfabrik-apache-dos.conf --print-all-ignored
Tipp
Wer Variablen in Filtern nutzen möchte, definiert diese in der jail.local
und übergibt sie dem filter =
-Aufruf, und zwar so:
[linuxfabrik-apache-dos]
filter = linuxfabrik-apache-dos[var1="%(myvar1)s", var2="%(myvar2)s"]
myvar1 = myvalue1
myvar2 = myvalue2
und im Filter:
failregex = ^... <var1> ... <var2>$
Action entwickeln
Im Beispiel soll die IP-Adresse nicht nur gebannt, sondern auch per Rocket.Chat benachrichtigt werden. Es muss also eine neue Action her.
# Author: Linuxfabrik GmbH, Zurich, Switzerland
# Contact: info (at) linuxfabrik (dot) ch
# https://www.linuxfabrik.ch/
# License: The Unlicense, see LICENSE file.
#
# 2020120101
[Init]
rockethook =
[Definition]
actionstart =
actionstop =
actioncheck =
actionban = curl --silent --output /dev/null -X POST -H 'Content-Type: application/json' -d '{"text":":fail2ban: banned <ip> for <bantime> seconds after <failures> attempts in jail *<name>* on `<fq-hostname>`\nTo unban use `fail2ban-client set <name> unbanip <ip>`"}' <rockethook>
#actionunban = curl --silent --output /dev/null -X POST -H 'Content-Type: application/json' -d '{"text":":fail2ban: unbanned <ip> from jail *<name>* on `<fq-hostname>`"}' <rockethook>
Diese Aktion benötigt noch ein freigeschaltetes SELinux-Boolean:
setsebool -P nis_enabled on
Jail konfigurieren
In der Jail kommen Action und Filter zusammen und werden mit „bantime“ und anderen Konfigurationsparametern versehen. Hier wird die Jail „linuxfabrik-apache-dos“ definiert, womit der gleichnamige Filter zur Anwendung kommt. IP-Adressen, die 200 und mehr Requests innerhalb von zehn Sekunden gegen den Webserver feuern, werden für 15 Minuten geblockt, und es wird per Rocket.Chat benachrichtigt.
[DEFAULT]
action = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]
linuxfabrik-rocket-chat[name=%(__name__)s, rockethook="%(rockethook)s"]
banaction = iptables-multiport
chain = INPUT
ignoreip = 127.0.0.1/8 10.80.32.0/24
logpath = /var/log/httpd/*access.log
port = http,https
protocol = tcp
rockethook = https://chat.linuxfabrik.io/hooks/692136e4b03b41cc98c2d1aa1fe3bb35
[linuxfabrik-apache-dos]
bantime = 15m
enabled = true
findtime = 10s
maxretry = 200
Dump der Einstellungen und gleichzeitig Test auf syntaktische Korrektheit:
# fail2ban does not need to be running for this
fail2ban-client -d
Alles aktivieren:
systemctl reload fail2ban
Ignorierte IPs ermitteln
fail2ban-client get $JAIL ignoreip
Gesperrte IPs ermitteln
Mit dem fail2ban-client
:
# get list of active jails
fail2ban-client status
# get stats on specific jail and
# "Banned IP list"
fail2ban-client status $JAIL
Alternativ mit iptables
(falls damit geblockt wurde):
iptables --list --numeric
Die gesperrten IP-Adressen tauchen bei Verwendung der Action „iptables“ in eigenen iptables-Chains namens „f2b-$JAIL“ auf, so dass bei bekanntem Namen auch der Aufruf
iptables --list f2b-$JAIL --numeric
genügt. Der Name ergibt sich aus f2b-
und angehängtem Jail-Name aus jail.local
, im Beispiel oben also f2b-linuxfabrik-apache-dos
.
Zählen, wieviele Adressen geblockt wurden (vom Ergebnis noch 3 abziehen):
iptables --list f2b-$JAIL --numeric | wc --lines
IP-Adresse manuell freigeben
Um die durch Fail2ban geblockte IP-Adresse 10.26.6.74 zu entsperren, entfernt man sie aus der passenden Jail:
fail2ban-client set $JAIL unbanip 10.26.6.74
Liste der mitgelieferten Jails und Actions
Actions:
abuseipdb
apf
apprise
blocklist_de
cloudflare
cloudflare-token
dshield
dummy
firewallcmd-allports
firewallcmd-common
firewallcmd-ipset
firewallcmd-multiport
firewallcmd-new
firewallcmd-rich-logging
firewallcmd-rich-rules
helpers-common
iptables
iptables-allports
iptables-ipset
iptables-ipset-proto4
iptables-ipset-proto6
iptables-ipset-proto6-allports
iptables-multiport
iptables-multiport-log
iptables-new
iptables-xt_recent-echo
ipthreat
mail-whois-common
mynetwatchman
netscaler
nftables
nftables-allports
nftables-multiport
nginx-block-map
npf
nsupdate
route
sendmail
sendmail-buffered
sendmail-common
sendmail-geoip-lines
sendmail-whois
sendmail-whois-ipjailmatches
sendmail-whois-ipmatches
sendmail-whois-lines
sendmail-whois-matches
shorewall-ipset-proto6
sm
symbiosis-blacklist-allports
xarf-login-attack
Filter:
3proxy
apache-auth
apache-badbots
apache-botsearch
apache-common
apache-fakegooglebot
apache-modsecurity
apache-nohome
apache-noscript
apache-overflows
apache-pass
apache-shellshock
assp
asterisk
bitwarden
botsearch-common
centreon
common
counter-strike
courier-auth
courier-smtp
cyrus-imap
directadmin
domino-smtp
dovecot
dropbear
drupal-auth
ejabberd-auth
exim
exim-common
exim-spam
freeswitch
froxlor-auth
gitlab
grafana
groupoffice
gssftpd
guacamole
haproxy-http-auth
horde
ignorecom
ignorecommands/apache-fakegoog
kerio
lighttpd-auth
mongodb-auth
monit
monitorix
mssql-auth
murmur
mysqld-auth
nagios
named-refused
nginx-bad-request
nginx-botsearch
nginx-http-auth
nginx-limit-req
nsd
openhab
openwebmail
oracleims
pam-generic
perdition
php-url-fopen
phpmyadmin-syslog
portsentry
postfix
proftpd
pure-ftpd
qmail
recidive
roundcube-auth
scanlogd
screensharingd
selinux-common
selinux-ssh
sendmail-auth
sendmail-reject
sieve
slapd
softethervpn
sogo-auth
solid-pop3d
squid
squirrelmail
sshd
stunnel
suhosin
tine20
traefik-auth
uwimap-auth
vsftpd
webmin-auth
wuftpd
xinetd-fail
znc-adminlog
zoneminder
Troubleshooting
- Filter enabled, IP taucht auch in der iptables-Liste als geblockt auf, aber Zugriff auf z.B. die Webseite ist immer noch möglich?
Greift ein Client beispielsweise auf
meine-ip:9999
zu, wird er geblockt. Ruft er danachmeine-ip:443
auf, darf er meine Webseite besuchen. Warum? Hat mich einen Tag gekostet, und wie immer sehr logisch: Fail2ban läuft hier auf einem System, welches direkt am Internet hängt und eingehenden Netzwerk NATtet, z.B. auf einen Webserver. Damit wird der Netzverkehr in der PREROUTING-Chain behandelt und an den Webserver durchgeroutet, durchläuft also nicht die Fail2ban-Chains. Ein Testzugriff aufmeine-ip:9998
zeigt, dass alles ausserhalb der NAT-Regeln wirklich geblockt wird.- fail2ban-client: ERROR NOK: (‚database disk image is malformed‘)
SQLite-Datenbank in
/var/lib/fail2ban/fail2ban.sqlite3
löschen und Fail2ban neu starten.- ERROR: No failure-id group in …
Fehler im Filter: im regulären Ausdruck fehlt die
<HOST>
-Angabe.
Built on 2024-11-18