Fail2ban ist ein kleines Programm, daß ähnlich wie swatch die Logfiles beobachtet.
Während man swatch jedoch ganz nach eigenem Wunsch für alles Mögliche einsetzen kann, aber immer nur für eine Regel pro Prozess, kann Fail2ban viele Regeln in einem Prozess anwenden, aber nur eine Aufgabe erfüllen:
Die IP-Adresse eines Regelverletzers für eine bestimmte Zeit komplett sperren.
Beispiel:
Fail2ban beobachtet die Logs von beiden VPN-Servern, udp und tcp.
Versucht ein Angreifer ( z.B. RU-honk mit der IP 45.136.108.67 ) sich dort anzumelden, sperrt Fail2ban diese IP nach 3 erfolglosen Anmeldeversuchen für 10 Minuten, nicht nur für den VPN Port, sondern komplett.
Nun kann man darüber streiten, ob es nötig ist beim VPN, der ja schon sehr hohe Anforderungen an die Anmeldung stellt, einen Fail2ban aufzusetzen.
Ich zeige es trotzdem, der Aufwand hält sich in Grenzen, der Effekt ist enorm.
Und, ich kann diese ganzen respektlosen Honks einfach nicht leiden.
Mein Fail2ban macht nach einem Fehlversuch für eine Woche zu.
Man muss sich das mal vorstellen:
Du sitzt zuhause vor der Glotze und draussen an der Tür versuchen ein paar Typen die ganze Zeit mit einem ganzen Koffer voller Schlüssel Deine Tür aufzumachen!
Kein Spaß, sollte Dich diese Lektüre dazu ermuntern Dir irgendwann einen eigenen Webserver aufzusetzen, nicht zuhause – etwas mit fester IP, dann wirst Du Dich wundern, was da alles los sein wird an Deiner Tür.
OK. neben fail2ban installieren wir noch whois, damit wir auch erfahren wer da ausgesperrt wird. Muss nicht, nur für die Neugierigen. Ich bin neugierig.
gateway: ~ # apt install fail2ban whois apt update vorher muss ich nicht mehr extra ansagen? Heute schon gemacht? ok, weglassen..
whois ist sofort lauffähig, wenn wir Port 43 tcp dafür aufmachen, also
ACCEPT $FW net tcp 43
und shorewall neustarten, Test:
gateway: ~ # whois 45.136.108.67 % This is the RIPE Database query service. % The objects are in RPSL format. % % The RIPE Database is subject to Terms and Conditions. % See http://www.ripe.net/db/support/db-terms-conditions.pdf % Note: this output has been filtered. % To receive output for a database update, use the "-B" flag. % Information related to '45.136.108.0 - 45.136.111.255' % Abuse contact for '45.136.108.0 - 45.136.111.255' is '[email protected]' inetnum: 45.136.108.0 - 45.136.111.255 netname: RU-COMTRADE-20190801 country: DE org: ORG-CL547-RIPE admin-c: VT4439-RIPE tech-c: VT4439-RIPE status: ALLOCATED PA mnt-by: mnt-ru-comtrade-1 mnt-by: RIPE-NCC-HM-MNT created: 2019-08-01T13:51:28Z last-modified: 2019-08-08T09:10:06Z source: RIPE organisation: ORG-CL547-RIPE org-name: COMTRADE LLC org-type: LIR address: st. Roshchinskaya 2nd, d. 4, of. 7341g, rm. 1 address: 115191 address: Moscow address: RUSSIAN FEDERATION admin-c: VT4439-RIPE tech-c: VT4439-RIPE abuse-c: AR54426-RIPE mnt-ref: mnt-ru-comtrade-1 mnt-by: RIPE-NCC-HM-MNT mnt-by: mnt-ru-comtrade-1 created: 2019-07-31T13:09:00Z last-modified: 2019-10-29T14:13:43Z source: RIPE # Filtered phone: +74954096573 person: Vladimir Torhov address: st. Roshchinskaya 2nd, d. 4, of. 7341g, rm. 1 address: 115191 address: Moscow address: RUSSIAN FEDERATION phone: +74954096573 nic-hdl: VT4439-RIPE mnt-by: mnt-ru-comtrade-1 created: 2019-07-31T13:08:59Z last-modified: 2019-10-29T14:17:09Z source: RIPE % Information related to '45.136.108.0/24AS38994' route: 45.136.108.0/24 descr: erahost.pro origin: AS38994 mnt-by: mnt-ru-comtrade-1 created: 2019-08-16T11:00:43Z last-modified: 2019-08-16T11:00:43Z source: RIPE % This query was served by the RIPE Database Query Service version 1.95.1 (HEREFORD)
Praktisch, den hat gerade mein Fail2ban geblockt, Vladimir, oder ein Kunde von Vladimir, wollte dumme Anfragen stellen.
Dumme Anfragen auf openVPN sind eher selten, vor allem hinter dynamischen IP-Adressen, aber ihr wisst ja, ….genau.
Also whois geht, weiter:
gateway: ~ # cd /etc/fail2ban
gateway: /etc/fail2ban # l
insgesamt 60 drwxr-xr-x 2 root root 4096 Nov 12 18:41 action.d -rw-r--r-- 1 root root 2334 Jan 18 2018 fail2ban.conf drwxr-xr-x 2 root root 4096 Sep 23 2018 fail2ban.d drwxr-xr-x 3 root root 4096 Nov 12 18:41 filter.d -rw-r--r-- 1 root root 22897 Jan 18 2018 jail.conf drwxr-xr-x 2 root root 4096 Nov 12 18:41 jail.d -rw-r--r-- 1 root root 645 Jan 18 2018 paths-arch.conf -rw-r--r-- 1 root root 2827 Jan 18 2018 paths-common.conf -rw-r--r-- 1 root root 573 Jan 18 2018 paths-debian.conf -rw-r--r-- 1 root root 738 Jan 18 2018 paths-opensuse.conf
Na, hier ist ja mal alles da – scheinbar.
Unsere Dateien sind jail.conf und alles in filter.d.
Ein Blick ins Verzeichnis filter.d zeigt alle Filter die bereits vorgefertigt mitgekommen sind, ein openvpn.conf fehlt.
Ferner hat fail2ban sich feste vorgenommen, alle Deine Einstellungen in jail.conf bei jedem Update zu überschreiben.
Schauen wir uns das trotzdem an:
Jesus, das ist nicht dein ernst? #kleinlaut - doch -aber der Aufwand hält sich in Grenzen? ok, nicht lustig, ich weiss, aber das sieht schlimmer aus als es ist. # WARNING: heavily refactored in 0.9.0 release. Please review and # customize settings for your setup. # # Changes: in most of the cases you should not modify this # file, but provide customizations in jail.local file, wir brauchen so gut wie nichts hiervon und sollten das was wir brauchen unbedingt als jail.local ablegen. # or separate .conf files under jail.d/ directory, e.g.: # # HOW TO ACTIVATE JAILS: # # YOU SHOULD NOT MODIFY THIS FILE. # # It will probably be overwritten or improved in a distribution update.!!! # # Provide customizations in a jail.local file or a jail.d/customisation.local. # For example to change the default bantime for all jails and to enable the # ssh-iptables jail the following (uncommented) would appear in the .local file. # See man 5 jail.conf for details. # # [DEFAULT] # bantime = 1h # # [sshd] # enabled = true # # See jail.conf(5) man page for more information # Comments: use '#' for comment lines and ';' (following a space) for inline comments [INCLUDES] #before = paths-distro.conf before = paths-debian.conf # The DEFAULT allows a global definition of the options. They can be overridden # in each jail afterwards. [DEFAULT] # # MISCELLANEOUS OPTIONS # # "ignorself" specifies whether the local resp. own IP addresses should be ignored # (default is true). Fail2ban will not ban a host which matches such addresses. #ignorself = true trauen wir unserem eigenen Netzwerk? # "ignoreip" can be a list of IP addresses, CIDR masks or DNS hosts. Fail2ban # will not ban a host which matches an address in this list. Several addresses # can be defined using space (and/or comma) separator. #ignoreip = 127.0.0.1/8 ::1 möchte ich jetzt den SSH im erstes.netz auch absichern, gehört hier z.B. die IP-Adresse unseres Verwaltungsrechners hin und die Raute weg # External command that will take an tagged arguments to ignore, e.g. <ip>, # and return true if the IP is to be ignored. False otherwise. # # ignorecommand = /path/to/command <ip> ignorecommand = # "bantime" is the number of seconds that a host is banned. bantime = 10m wielange, 10 Minuten # A host is banned if it has generated "maxretry" during the last "findtime" # seconds. findtime = 10m wieviele Fehlversuche in welchem Zeitraum # "maxretry" is the number of failures before a host get banned. maxretry = 5 wieviele Fehlversuche bis ban # "backend" specifies the backend used to get files modification. # Available options are "pyinotify", "gamin", "polling", "systemd" and "auto". # This option can be overridden in each jail as well. # # pyinotify: requires pyinotify (a file alteration monitor) to be installed. # If pyinotify is not installed, Fail2ban will use auto. # gamin: requires Gamin (a file alteration monitor) to be installed. # If Gamin is not installed, Fail2ban will use auto. # polling: uses a polling algorithm which does not require external libraries. # systemd: uses systemd python library to access the systemd journal. # Specifying "logpath" is not valid for this backend. # See "journalmatch" in the jails associated filter config # auto: will try to use the following backends, in order: # pyinotify, gamin, polling. # # Note: if systemd backend is chosen as the default but you enable a jail # for which logs are present only in its own log files, specify some other # backend for that jail (e.g. polling) and provide empty value for # journalmatch. See https://github.com/fail2ban/fail2ban/issues/959#issuecomment-74901200 backend = auto # "usedns" specifies if jails should trust hostnames in logs, # warn when DNS lookups are performed, or ignore all hostnames in logs # # yes: if a hostname is encountered, a DNS lookup will be performed. # warn: if a hostname is encountered, a DNS lookup will be performed, # but it will be logged as a warning. # no: if a hostname is encountered, will not be used for banning, # but it will be logged as info. # raw: use raw value (no hostname), allow use it for no-host filters/actions (example user) usedns = warn # "logencoding" specifies the encoding of the log files handled by the jail # This is used to decode the lines from the log file. # Typical examples: "ascii", "utf-8" # # auto: will use the system locale setting logencoding = auto # "enabled" enables the jails. # By default all jails are disabled, and it should stay this way.!!! # Enable only relevant to your setup jails in your .local or jail.d/*.conf # # true: jail will be enabled and log files will get monitored for changes # false: jail is not enabled enabled = false # "mode" defines the mode of the filter (see corresponding filter implementation for more info). mode = normal # "filter" defines the filter to use by the jail. # By default jails have names matching their filter name # filter = %(__name__)s[mode=%(mode)s] ......bis hier lauter infos und Einstellungen die man lassen kann wie sie sind. Ab wieder hier interessant: # # ACTIONS # # Some options used for actions # Destination email address used solely for the interpolations in # jail.{conf,local,d/*} configuration files. destemail = root@localhost gleiche mail bitte wie in logwatch # Sender email address used solely for some actions sender = root@<fq-hostname> # E-mail action. Since 0.8.1 Fail2Ban uses sendmail MTA for the # mailing. Change mta configuration parameter to mail if you want to # revert to conventional 'mail'. mta = sendmail lassen, geht auch für exim # Default protocol protocol = tcp # Specify chain where jumps would need to be added in ban-actions expecting parameter chain chain = <known/chain> # Ports to be banned # Usually should be overridden in a particular jail port = 0:65535 # Format of user-agent https://tools.ietf.org/html/rfc7231#section-5.5.3 fail2ban_agent = Fail2Ban/%(fail2ban_version)s # # Action shortcuts. To be used to define action parameter # Default banning action (e.g. iptables, iptables-new, # iptables-multiport, shorewall, etc) It is used to define # action_* variables. Can be overridden globally or per # section within jail.local file banaction = iptables-multiport shorewall banaction_allports = iptables-allports shorewall # The simplest action to take: ban only action_ = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"] simpel , nur blocken # ban & send an e-mail with whois report to the destemail. action_mw = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"] %(mta)s-whois[name=%(__name__)s, sender="%(sender)s", dest="%(destemail)s", protocol="%(protocol)s", chain="%(chain)s"] blocken und e-mail mit whois # ban & send an e-mail with whois report and relevant log lines # to the destemail. action_mwl = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"] %(mta)s-whois-lines[name=%(__name__)s, sender="%(sender)s", dest="%(destemail)s", logpath=%(logpath)s, chain="%(chain)s"] blocken und e-mail mit whois und log-treffer # See the IMPORTANT note in action.d/xarf-login-attack for when to use this action # # ban & send a xarf e-mail to abuse contact of IP address and include relevant log lines # to the destemail. action_xarf = %(banaction)s[name=%(__name__)s, bantime="%(bantime)s", port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"] xarf-login-attack[service=%(__name__)s, sender="%(sender)s", logpath=%(logpath)s, port="%(port)s"] Keine Ahnung, Suche "xarf" # ban IP on CloudFlare & send an e-mail with whois report and relevant log lines # to the destemail. action_cf_mwl = cloudflare[cfuser="%(cfemail)s", cftoken="%(cfapikey)s"] %(mta)s-whois-lines[name=%(__name__)s, sender="%(sender)s", dest="%(destemail)s", logpath=%(logpath)s, chain="%(chain)s"] nur wenn unser server auch unter dem Schutz von Cloudflare steht # Report block via blocklist.de fail2ban reporting service API # # See the IMPORTANT note in action.d/blocklist_de.conf for when to use this action. # Specify expected parameters in file action.d/blocklist_de.local or if the interpolation # `action_blocklist_de` used for the action, set value of `blocklist_de_apikey` # in your `jail.local` globally (section [DEFAULT]) or per specific jail section (resp. in # corresponding jail.d/my-jail.local file). # action_blocklist_de = blocklist_de[email="%(sender)s", service=%(filter)s, apikey="%(blocklist_de_apikey)s", agent="%(fail2ban_agent)s"] Möchten wir mitmachen am Listen bauen? Blacklisten können ebenfalls eingebunden werden ( in shorewall übrigens auch, siehe blrules...hinter einem Plasterouter aber nicht nötig,- finde ich ) # Report ban via badips.com, and use as blacklist # # See BadIPsAction docstring in config/action.d/badips.py for # documentation for this action. # # NOTE: This action relies on banaction being present on start and therefore # should be last action defined for a jail. # action_badips = badips.py[category="%(__name__)s", banaction="%(banaction)s", agent="%(fail2ban_agent)s"] # # Report ban via badips.com (uses action.d/badips.conf for reporting only) # action_badips_report = badips[category="%(__name__)s", agent="%(fail2ban_agent)s"] # Report ban via abuseipdb.com. # # See action.d/abuseipdb.conf for usage example and details. # action_abuseipdb = abuseipdb Dazu muss die oben genannte Datei eingerichtet werden, mit Anmeldung bei abuseipdb.com erhält man dort einen API Key, dann kann man geblockte IP-Adressen dort melden. Nach deren Regeln werden sie dann eventuell in die Blacklist aufgenommen. So lassen - macht nix. # Choose default action. To change, just override value of 'action' with the # interpolation to the chosen action shortcut (e.g. action_mw, action_mwl, etc) in jail.local # globally (section [DEFAULT]) or per specific section action = %(action_mw)s %(action_mw)s wäre meine Wahl fürs erste # # JAILS # Jetzt geht das mit den Regeln los, jede Regel fängt mit [regel] an, und braucht ein enable = true wenn sie genutzt werden soll, ferner muss Port und der Pfad zum Log stimmen. Zu jeder Regel wird ein bisschen erzählt, weitere Infos erhält man zudem in der dazugehörigen .conf unter filter.d Da wir diese Datei gleich ohnehin als jail.local speichern werden, kann alles ab hier weg und nur unsere neuen openvpn-Regeln hin: Das Löschen mit nano macht jetzt mal keinen Spaß, selbst mit control+k ganze Zeile löschen. Der Freund von vi lacht sich jetzt weg, und sagt lösche von - bis. Nano sagt tschüß und wir kopieren was gebraucht wird, also alles von hier nach oben mit der Maus in eine neue Datei jail.local. Dann schauen wir mal wie wir an eine openvpn.conf kommen.
Dazu lohnt mal ein Blick in bestehende .conf Dateien, vielleicht die …. ….. …,puh, die sind aber alle ganz schön voll geworden, lange nicht mehr reingeschaut, ok, vielleicht apache-auth.conf:
# Fail2Ban apache-auth filter # [INCLUDES] # Read common prefixes. If any customizations available -- read them from # apache-common.local before = apache-common.conf erstmal die Regel apache-common.conf auslesen und voraussetzen. Wenn dort Änderungen nötig sind, dann .conf zu .local ändern und die geänderte Datei natürlich als apache-common.local speichern. Finger von lassen, wenn man nicht genau weiss was man tut. [Definition] Hier stehen jetzt die Regeln. Findet Fail2ban im entsprechenden Log einen Eintrag der zu einem der folgenden Suchmuster passt, dann wird die dazugehörende IP gesperrt. prefregex = ^%(_apache_error_client)s (?:AH\d+: )?<F-CONTENT>.+</F-CONTENT>$ # auth_type = ((?:Digest|Basic): )? auth_type = ([A-Z]\w+: )? failregex = ^client (?:denied by server configuration|used wrong authentication scheme)\b ^user <F-USER>(?:\S*|.*?)</F-USER> (?:auth(?:oriz|entic)ation failure|not found|denied by provider)\b ^Authorization of user <F-USER>(?:\S*|.*?)</F-USER> to access .*? failed\b ^%(auth_type)suser <F-USER>(?:\S*|.*?)</F-USER>: password mismatch\b ^%(auth_type)suser `<F-USER>(?:[^']*|.*?)</F-USER>' in realm `.+' (not found|denied by provider)\b ^%(auth_type)sinvalid nonce .* received - length is not\b ^%(auth_type)srealm mismatch - got `(?:[^']*|.*?)' but expected\b ^%(auth_type)sunknown algorithm `(?:[^']*|.*?)' received\b ^invalid qop `(?:[^']*|.*?)' received\b ^%(auth_type)sinvalid nonce .*? received - user attempted time travel\b ignoreregex = Welche Treffer zu welchem Suchmuster sollen ignoriert werden. #DEV Notes erzählt etwas genauer was hier passiert, wissen wollen wir das eigentlich nur, wenn uns unsere Anmeldung am Webserver, die hier geschützt wird, trotz korrektem Passwort rausschmeisst, was ja nicht passieren sollte. Fehlersuche bei Fail2ban setzt Verständnis für die hier eingesetzten "regulären Ausdrücke" voraus.
Und was fangen wir jetzt damit an? Erstmal nichts, aber wir wissen jetzt wie Fail2ban arbeitet, können es auch für andere Zwecke nutzen und überhaupt.
Um jetzt ernsthaft über einen regulären Ausdruck nachzudenken, der einen unberechtigten openVPN Loginversuch entdeckt, müssten wir jetzt diesen produzieren und schauen, was dann im Log auftaucht. Ich habe mir dazu mal ein altes Schlüsselpaar, bzw. eine alte Konfiguration behalten, die ich einfach mit Anpassen der remote IP auf alles loslassen kann.
Im Log sieht sowas dann so aus:
gateway: /etc/openvpn # tail -f /var/log/openvpn/openvpn.udp.log Wed Nov 13 18:59:02 2019 Initialization Sequence Completed Wed Nov 13 18:59:54 2019 Authenticate/Decrypt packet error: packet HMAC authentication failed Wed Nov 13 18:59:54 2019 TLS Error: incoming packet authentication failed from [AF_INET]10.0.2.2:62235 Wed Nov 13 18:59:56 2019 Authenticate/Decrypt packet error: packet HMAC authentication failed Wed Nov 13 18:59:56 2019 TLS Error: incoming packet authentication failed from [AF_INET]10.0.2.2:62235
Die Zeile „Sequence Completed“ ist das Ende der erfolgreichen Startmeldungen vom Server, danach wartet er auf Anmeldungen.
Nun lasse ich meinPC mit falschen Schlüsseln auf den Server los und die Meldungen „HMAC authentication failed“ und „authentication failed from“ wechseln sich solange ab, bis der Server die Verbindung wieder abbricht.
Das sollte doch machbar sein!
Erstellen wir also eine Datei openvpn.conf in filter.d und versuchen mal folgendes:
# Fail2Ban filter für openvpn # # [Definition] failregex = TLS Error: incoming packet authentication failed from \[AF_INET\]<HOST>:\d+$ <HOST>:\d+ TLS Auth Error <HOST>:\d+ TLS Error: TLS handshake failed$ <HOST>:\d+ VERIFY ERROR ignoreregex =
Speichern und zurück in die jail.local:
# # JAILS # # # openvpn # [openvpn] enabled = true protocol = udp port = 1196 filter = openvpn logpath = /var/log/openvpn/openvpn.udp.log maxretry = 1
Speichern und schliessen. Jetzt kommt mal wieder eine Besonderheit.
gateway: /etc/fail2ban # fail2ban-server restart startet den Server neu, stop,start,status sind die weiteren optionen
gateway: /etc/fail2ban # fail2ban-client status zeigt wieviele Regeln laufen
gateway: /etc/fail2ban # fail2ban-client status Regelname zeigt Details zur Regel
gateway: /etc/fail2ban # fail2ban-client reload lädt die Regeln neu
Wenn alles geklappt hat, dann sollten direkt nach dem Start E-Mails mit Statusmeldungen eintreffen.

Dann wollen wir mal Fehler produzieren:….
Na toll, jetzt habe ich mich ausgesperrt: Zum Glück nur 10 Minuten, Kaffee?
gateway: /etc/fail2ban # fail2ban-client status openvpn Status for the jail: openvpn |- Filter | |- Currently failed: 0 | |- Total failed: 1 | `- File list: /var/log/openvpn/openvpn.udp.log `- Actions |- Currently banned: 1 |- Total banned: 1 `- Banned IP list: 10.0.2.2
Die IP 10.0.2.2 kann von whois nicht angefragt werden (private, unroutable, whois streikt), deshalb kommt dazu jetzt auch keine Mail – egal, oder? Die Frage ist jetzt eher, wie kann ich den Bann wieder aufheben, wenn ich das will?
gateway: /etc/fail2ban # fail2ban-client set openvpn unbanip 10.0.2.2
Und der openVPN auf TCP?
Richtig! Nochmal zur jail.local
# # JAILS # # # openvpn für udp und (1) tcp # [openvpn] enabled = true protocol = udp port = 1196 filter = openvpn logpath = /var/log/openvpn/openvpn.udp.log maxretry = 1 [openvpn1] enabled = true protocol = tcp port = 1196 filter = openvpn logpath = /var/log/openvpn/openvpn.tcp.log maxretry = 1
gateway: /etc/fail2ban # fail2ban-client reload
gateway: /etc/fail2ban # fail2ban-client status
Status
|- Number of jail: 3
`- Jail list: openvpn, openvpn1, sshd
Das war doch garnicht so schlimm wie es erstmal aussah.
next > Aufräumen