Fail2ban para protexer o servizo ssh

De MediaWiki
Ir a la navegación Ir a la búsqueda

Escenario

Este escenario ten como principal obxectivo explicar o funcionamento da ferramenta fail2ban e implantala no servidor para protexer o servizo ssh fronte ataques de contrasinais.

Configuración dos equipos

Para desenvolver o escenario precisamos que:

  • Os equipos son os do escenario anterior.

O equipo server:

  • Precisa ter saída a Internet para acceder ós repositorios oficiais para instalar fail2ban
  • Débese autorizar a autenticación por contrasinal e deshabilitar o acceso por claves dixitais modificando no arquivo de configuración /etc/ssh/sshd_config:
$ sudo nano /etc/ssh/sshd_config
PubkeyAuthentication no
PasswordAuthentication yes
$ sudo systemctl restart sshd.service

Para facer máis claro o escenario non haberá regras netfilter/iptables configuradas.

fail2ban (iptables)

fail2ban é unha aplicación que monitoriza os arquivos de log na procura de información interesante, en especial os erros de autenticación. Analizando esa información e tomando como referencia os parámetros de configuración introducidos polo administrador é capaz de distinguir entre un simple erro de autenticación e un intento de ataque. Unha vez detectado o ataque, fail2ban pode realizar diferentes accións, na maioría dos casos procederá a reconfigurar o firewall do equipo para bloquear o equipo atacante e/ou notificalo ó administrador mediante un email.

Como vimos nun escenario anterior os ataques de forza bruta ou diccionario deixan pegadas no sistema de logs:

$ less /var/log/auth.log
...
Oct 29 01:02:21 server-medusa sshd[1961]: Failed password for root from 192.168.100.134 port 59298 ssh2
Oct 29 01:02:21 server-medusa sshd[1958]: Failed password for root from 192.168.100.134 port 59292 ssh2
Oct 29 01:02:21 server-medusa sshd[1952]: Failed password for root from 192.168.100.134 port 59280 ssh2
Oct 29 01:02:21 server-medusa sshd[1949]: Failed password for root from 192.168.100.134 port 59275 ssh2
Oct 29 01:02:21 server-medusa sshd[1960]: Failed password for root from 192.168.100.134 port 59296 ssh2
Oct 29 01:02:21 server-medusa sshd[1957]: Failed password for root from 192.168.100.134 port 59290 ssh2
Oct 29 01:02:21 server-medusa sshd[1950]: Failed password for root from 192.168.100.134 port 59274 ssh2
Oct 29 01:02:21 server-medusa sshd[1951]: Failed password for root from 192.168.100.134 port 59278 ssh2
Oct 29 01:02:21 server-medusa sshd[1954]: Failed password for root from 192.168.100.134 port 59284 ssh2
Oct 29 01:02:21 server-medusa sshd[1953]: Failed password for root from 192.168.100.134 port 59282 ssh2
Oct 29 01:02:21 server-medusa sshd[1955]: Failed password for root from 192.168.100.134 port 59286 ssh2
...

fail2ban detecta estas pegadas e procede a actuar. Na seguinte imaxe dase unha visión xeral do proceso:

Proceso de traballo de fail2ban

Fig. Esquema de funcionamento de fail2ban

Para instalar fail2ban no servidor executamos os comandos:

$ sudo apt update 
$ sudo apt install fail2ban iptables

Os arquivos de configuración de fail2ban están ubicados no directorio /etc/fail2ban.

$ ls -lahF /etc/fail2ban/

total 36K
drwxr-xr-x  6 root root   12 abr 29 18:32 ./
drwxr-xr-x 90 root root  178 abr 29 18:32 ../
drwxr-xr-x  2 root root   65 abr 29 18:32 action.d/
-rw-r--r--  1 root root 2,8K nov 23  2020 fail2ban.conf
drwxr-xr-x  2 root root    2 mar 10  2022 fail2ban.d/
drwxr-xr-x  3 root root   94 abr 29 18:32 filter.d/
-rw-r--r--  1 root root  25K mar 10  2022 jail.conf
drwxr-xr-x  2 root root    3 abr 29 18:32 jail.d/
-rw-r--r--  1 root root  645 nov 23  2020 paths-arch.conf
-rw-r--r--  1 root root 2,8K nov 23  2020 paths-common.conf
-rw-r--r--  1 root root  650 mar 10  2022 paths-debian.conf
-rw-r--r--  1 root root  738 nov 23  2020 paths-opensuse.conf

Hai tres conceptos básicos para entender a configuración e a forma de traballo de fail2ban:

filter
expresión regular que busca un patrón nun log (p.e. erro de autenticación). No cartafol /etc/fail2ban/filter.d/ hai arquivos con filtros para os servizos/aplicacións máis comúns e non unicamente para ssh:

$ ls -lahF /etc/fail2ban/filter.d/

total 145K
drwxr-xr-x 3 root root   94 abr 29 18:32 ./
drwxr-xr-x 6 root root   12 abr 29 18:32 ../
-rw-r--r-- 1 root root  467 nov 23  2020 3proxy.conf
-rw-r--r-- 1 root root 3,2K nov 23  2020 apache-auth.conf
-rw-r--r-- 1 root root 2,8K nov 23  2020 apache-badbots.conf
-rw-r--r-- 1 root root 1,3K nov 23  2020 apache-botsearch.conf
-rw-r--r-- 1 root root 1,6K nov 23  2020 apache-common.conf
-rw-r--r-- 1 root root  324 nov 23  2020 apache-fakegooglebot.conf
-rw-r--r-- 1 root root  511 nov 23  2020 apache-modsecurity.conf
-rw-r--r-- 1 root root  596 nov 23  2020 apache-nohome.conf
-rw-r--r-- 1 root root 1,3K nov 23  2020 apache-noscript.conf
-rw-r--r-- 1 root root 2,2K nov 23  2020 apache-overflows.conf
-rw-r--r-- 1 root root  362 nov 23  2020 apache-pass.conf
-rw-r--r-- 1 root root 1020 nov 23  2020 apache-shellshock.conf
-rw-r--r-- 1 root root 3,5K nov 23  2020 assp.conf
-rw-r--r-- 1 root root 2,4K nov 23  2020 asterisk.conf
-rw-r--r-- 1 root root  427 nov 23  2020 bitwarden.conf
-rw-r--r-- 1 root root  522 nov 23  2020 botsearch-common.conf
-rw-r--r-- 1 root root  307 nov 23  2020 centreon.conf
-rw-r--r-- 1 root root 2,8K nov 23  2020 common.conf
-rw-r--r-- 1 root root  244 nov 23  2020 counter-strike.conf
-rw-r--r-- 1 root root  463 mar 10  2022 courier-auth.conf
-rw-r--r-- 1 root root  512 nov 23  2020 courier-smtp.conf
-rw-r--r-- 1 root root  444 nov 23  2020 cyrus-imap.conf
-rw-r--r-- 1 root root  338 nov 23  2020 directadmin.conf
-rw-r--r-- 1 root root 2,1K nov 23  2020 domino-smtp.conf
-rw-r--r-- 1 root root 2,4K nov 23  2020 dovecot.conf
-rw-r--r-- 1 root root 1,7K nov 23  2020 dropbear.conf
...
-rw-r--r-- 1 root root  242 nov 23  2020 portsentry.conf
-rw-r--r-- 1 root root 3,1K nov 23  2020 postfix.conf
-rw-r--r-- 1 root root 1,2K nov 23  2020 proftpd.conf
-rw-r--r-- 1 root root 2,4K nov 23  2020 pure-ftpd.conf
-rw-r--r-- 1 root root  795 nov 23  2020 qmail.conf
-rw-r--r-- 1 root root 1,4K nov 23  2020 recidive.conf
-rw-r--r-- 1 root root 1,6K mar 10  2022 roundcube-auth.conf
-rw-r--r-- 1 root root  354 mar 10  2022 scanlogd.conf
-rw-r--r-- 1 root root  821 nov 23  2020 screensharingd.conf
-rw-r--r-- 1 root root  538 nov 23  2020 selinux-common.conf
-rw-r--r-- 1 root root  570 nov 23  2020 selinux-ssh.conf
-rw-r--r-- 1 root root  776 nov 23  2020 sendmail-auth.conf
-rw-r--r-- 1 root root 2,9K nov 23  2020 sendmail-reject.conf
-rw-r--r-- 1 root root  371 nov 23  2020 sieve.conf
-rw-r--r-- 1 root root  706 nov 23  2020 slapd.conf
-rw-r--r-- 1 root root  451 nov 23  2020 softethervpn.conf
-rw-r--r-- 1 root root  722 nov 23  2020 sogo-auth.conf
-rw-r--r-- 1 root root 1,1K nov 23  2020 solid-pop3d.conf
-rw-r--r-- 1 root root  260 nov 23  2020 squid.conf
-rw-r--r-- 1 root root  191 nov 23  2020 squirrelmail.conf
-rw-r--r-- 1 root root 7,4K nov 23  2020 sshd.conf
-rw-r--r-- 1 root root  363 nov 23  2020 stunnel.conf
-rw-r--r-- 1 root root  649 nov 23  2020 suhosin.conf
-rw-r--r-- 1 root root  890 nov 23  2020 tine20.conf
-rw-r--r-- 1 root root 2,4K nov 23  2020 traefik-auth.conf
-rw-r--r-- 1 root root  374 nov 23  2020 uwimap-auth.conf
-rw-r--r-- 1 root root  637 nov 23  2020 vsftpd.conf
-rw-r--r-- 1 root root  444 nov 23  2020 webmin-auth.conf
-rw-r--r-- 1 root root  520 nov 23  2020 wuftpd.conf
-rw-r--r-- 1 root root  521 nov 23  2020 xinetd-fail.conf
-rw-r--r-- 1 root root  912 nov 23  2020 znc-adminlog.conf
-rw-r--r-- 1 root root  524 nov 23  2020 zoneminder.conf

Por exemplo, no arquivo /etc/fail2ban/filter.d/sshd.conf atopamos as seguintes expresións regulares para atopar incidencias no servizo ssh:

cmnfailre = ^[aA]uthentication (?:failure|error|failed) for <F-USER>.*</F-USER> from <HOST>( via \S+)?%(__suff)s$
            ^User not known to the underlying authentication module for <F-USER>.*</F-USER> from <HOST>%(__suff)s$
            ^Failed publickey for invalid user <F-USER>(?P<cond_user>\S+)|(?:(?! from ).)*?</F-USER> from <HOST>%(__on_port_opt)s(?: ssh\d*)?(?(cond_user): |(?:(?:(?! from ).)*)$)
            ^Failed \b(?!publickey)\S+ for (?P<cond_inv>invalid user )?<F-USER>(?P<cond_user>\S+)|(?(cond_inv)(?:(?! from ).)*?|[^:]+)</F-USER> from <HOST>%(__on_port_opt)s(?: ssh\d*)?(?(cond_user): |(?:(?:(?! from ).)*)$)
            ^<F-USER>ROOT</F-USER> LOGIN REFUSED FROM <HOST>
            ^[iI](?:llegal|nvalid) user <F-USER>.*?</F-USER> from <HOST>%(__suff)s$
            ^User <F-USER>.+</F-USER> from <HOST> not allowed because not listed in AllowUsers%(__suff)s$
            ^User <F-USER>.+</F-USER> from <HOST> not allowed because listed in DenyUsers%(__suff)s$
            ^User <F-USER>.+</F-USER> from <HOST> not allowed because not in any group%(__suff)s$
            ^refused connect from \S+ 
            ^Received <F-MLFFORGET>disconnect</F-MLFFORGET> from <HOST>%(__on_port_opt)s:\s*3: .*: Auth fail%(__suff)s$
            ^User <F-USER>.+</F-USER> from <HOST> not allowed because a group is listed in DenyGroups%(__suff)s$
            ^User <F-USER>.+</F-USER> from <HOST> not allowed because none of user's groups are listed in AllowGroups%(__suff)s$
            ^<F-NOFAIL>%(__pam_auth)ssshd:auth
:\s+authentication failure;</F-NOFAIL>(?:\s+(?:(?:logname|e?uid|tty)=\S*)){0,4}\s+ruser=<F-ALT_USER>\S*</F-ALT_USER>\s+rhost=<HOST>(?:\s+user=<F-USER>\S*</F-USER>)?%(__suff)s$
            ^(error: )?maximum authentication attempts exceeded for <F-USER>.*</F-USER> from <HOST>%(__on_port_opt)s(?: ssh\d*)?%(__suff)s$
            ^User <F-USER>.+</F-USER> not allowed because account is locked%(__suff)s
            ^<F-MLFFORGET>Disconnecting</F-MLFFORGET>(?: from)?(?: (?:invalid|authenticating)) user <F-USER>\S+</F-USER> <HOST>%(__on_port_opt)s:\s*Change of username or service not allowed:\s*.*preauth
\s*$
            ^<F-MLFFORGET>Disconnecting</F-MLFFORGET>: Too many authentication failures(?: for <F-USER>.+?</F-USER>)?%(__suff)s$
            ^<F-NOFAIL>Received <F-MLFFORGET>disconnect</F-MLFFORGET></F-NOFAIL> from <HOST>%(__on_port_opt)s:\s*11:
            <mdre-<mode>-other>
            ^<F-MLFFORGET><F-MLFGAINED>Accepted \w+</F-MLFGAINED></F-MLFFORGET> for <F-USER>\S+</F-USER> from <HOST>(?:\s|$)
action
define varios comandos a executar en diferentes momentos. No cartafol /etc/fail2ban/action.d/ hai arquivos con accións para diferentes tipos de firewalls:
$ ls -lahF /etc/fail2ban/action.d/
total 139K
drwxr-xr-x 2 root root   65 abr 29 18:32 ./
drwxr-xr-x 6 root root   12 abr 29 18:32 ../
-rw-r--r-- 1 root root 3,7K nov 23  2020 abuseipdb.conf
-rw-r--r-- 1 root root  587 nov 23  2020 apf.conf
-rw-r--r-- 1 root root  629 nov 23  2020 badips.conf
-rw-r--r-- 1 root root  12K nov 23  2020 badips.py
-rw-r--r-- 1 root root 2,7K nov 23  2020 blocklist_de.conf
-rw-r--r-- 1 root root 3,2K nov 23  2020 bsd-ipfw.conf
-rw-r--r-- 1 root root 3,0K nov 23  2020 cloudflare.conf
-rw-r--r-- 1 root root 4,7K nov 23  2020 complain.conf
-rw-r--r-- 1 root root 7,5K nov 23  2020 dshield.conf
-rw-r--r-- 1 root root 1,7K nov 23  2020 dummy.conf
-rw-r--r-- 1 root root 1,5K nov 23  2020 firewallcmd-allports.conf
-rw-r--r-- 1 root root 2,6K nov 23  2020 firewallcmd-common.conf
-rw-r--r-- 1 root root 2,7K nov 23  2020 firewallcmd-ipset.conf
-rw-r--r-- 1 root root 1,3K nov 23  2020 firewallcmd-multiport.conf
-rw-r--r-- 1 root root 2,0K nov 23  2020 firewallcmd-new.conf
-rw-r--r-- 1 root root 1021 nov 23  2020 firewallcmd-rich-logging.conf
-rw-r--r-- 1 root root 1,8K nov 23  2020 firewallcmd-rich-rules.conf
-rw-r--r-- 1 root root  592 nov 23  2020 helpers-common.conf
-rw-r--r-- 1 root root 1,7K nov 23  2020 hostsdeny.conf
-rw-r--r-- 1 root root 1,6K nov 23  2020 ipfilter.conf
-rw-r--r-- 1 root root 1,5K nov 23  2020 ipfw.conf
-rw-r--r-- 1 root root 1,5K nov 23  2020 iptables-allports.conf
-rw-r--r-- 1 root root 2,7K nov 23  2020 iptables-common.conf
-rw-r--r-- 1 root root 1,4K nov 23  2020 iptables.conf
-rw-r--r-- 1 root root 2,1K nov 23  2020 iptables-ipset-proto4.conf
-rw-r--r-- 1 root root 2,7K nov 23  2020 iptables-ipset-proto6-allports.conf
-rw-r--r-- 1 root root 2,8K nov 23  2020 iptables-ipset-proto6.conf
-rw-r--r-- 1 root root 1,5K nov 23  2020 iptables-multiport.conf
-rw-r--r-- 1 root root 2,2K nov 23  2020 iptables-multiport-log.conf
-rw-r--r-- 1 root root 1,6K nov 23  2020 iptables-new.conf
-rw-r--r-- 1 root root 2,7K nov 23  2020 iptables-xt_recent-echo.conf
-rw-r--r-- 1 root root 2,4K nov 23  2020 mail-buffered.conf
...

Por exemplo, no arquivo /etc/fail2ban/action.d/iptables-multiport.conf atopamos uns exemplos de accions. Revisandoas podemos ver:

actionstart
ó arrincar fail2ban crea unha cadea nova f2b-<name> hacia a que dirixe os paquetes dun determinado tipo (indicado polo protocolo e porto/s).
actionban
crea unha regra para bloquear o tráfico do tipo xestionado pola cadea f2b-<name> con orixe o equipo indicado en <ip>.
actionunban
borrar a regra que bloquea o tráfico do tipo xestionado pola cadea f2b-<name> con orixe o equipo indicado en <ip>.
actionstop

borrar a cadea creada por actionstart e as regras asociadas.

# Fail2Ban configuration file
#
# Author: Cyril Jaquier
# Modified by Yaroslav Halchenko for multiport banning
#

[INCLUDES]

before = iptables-common.conf

[Definition]

# Option:  actionstart
# Notes.:  command executed on demand at the first ban (or at the start of Fail2Ban if actionstart_on_demand is set to false).
# Values:  CMD
#
actionstart = <iptables> -N f2b-<name>
              <iptables> -A f2b-<name> -j <returntype>
              <iptables> -I <chain> -p <protocol> -m multiport --dports <port> -j f2b-<name>

# Option:  actionstop
# Notes.:  command executed at the stop of jail (or at the end of Fail2Ban)
# Values:  CMD
#
actionstop = <iptables> -D <chain> -p <protocol> -m multiport --dports <port> -j f2b-<name>
             <actionflush>
             <iptables> -X f2b-<name>

# Option:  actioncheck
# Notes.:  command executed once before each actionban command
# Values:  CMD
#
actioncheck = <iptables> -n -L <chain> | grep -q 'f2b-<name>[ \t]'

# Option:  actionban
# Notes.:  command executed when banning an IP. Take care that the
#          command is executed with Fail2Ban user rights.
# Tags:    See jail.conf(5) man page
# Values:  CMD
#
actionban = <iptables> -I f2b-<name> 1 -s <ip> -j <blocktype>

# Option:  actionunban
# Notes.:  command executed when unbanning an IP. Take care that the
#          command is executed with Fail2Ban user rights.
# Tags:    See jail.conf(5) man page
# Values:  CMD
#
actionunban = <iptables> -D f2b-<name> -s <ip> -j <blocktype>
jail

é unha combinación dun filter e unha ou varias actions. Para evitar problemas con futuras actualizacións que poidan modificar o contido do ficheiro jail.conf recoméndase crear un ficheiro jail.local onde poremos a nosa configuración particular. Hai que sinalar que dende hai algunhas versións as directivas de configuración poden indicarse en diversos arquivos/cartafoles o que ás veces pode ser lioso:

$ sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
$ sudo nano /etc/fail2ban/jail.local

No arquivo /etc/fail2ban/jail.local:

  • Defínense algúns parámetros de configuración globais que afectan a todos os jails.
  • Configúranse os jails cos que traballará fail2ban (pode manexar varias jails á vez) e dentro destes jails é posible definir valores específicos que sobreescriben os definidos globalmente. Un exemplo de sección jail para o servidor FTP vsftpd é:
[vsftpd]
# or overwrite it in jails.local to be
# logpath = %(syslog_authpriv)s
# if you want to rely on PAM failed login attempts
# vsftpd's failregex should match both of those formats
port     = ftp,ftp-data,ftps,ftps-data
logpath  = %(vsftpd_log)s

Revisando os parámetros globais e o jail para ssh en /etc/fail2ban/jail.local, /etc/fail2ban/jail.d/defaults-debian.conf e /etc/fail2ban/paths-common.conf temos que:

Si ó monitorizar o arquivo /var/log/auth.log (logpath) durante ós últimos 10 minutos (findtime) aparecen 5 (maxretry) entradas asociadas ó mesmo equipo orixe con erros indicados no filter /etc/fail2ban/filter.d/sshd.conf (filter), procederase a 'banear' (action) ese equipo durante 10 minutos (bantime). Por 'banear' referímonos a executar o action iptables-multiport cos parámetros porto 22/tcp (protocol e port) e a IP do equipo problemático; é dicir, crease unha regra para bloquear ó equipo problemático e ós 10 minutos proceder a borrala para desbloquear ó equipo. Fixarse que o que está fóra da sección [sshd] é un parámetro global e dentro da [sshd] (tanto en jail.local como en defaults-debian.conf ) é local e ten prioridade sobre o global. Poñendo dentro da sección [sshd] parámetros coma bantime, findtime, ..., podemos personalizar os valores para o servizo.

/etc/fail2ban/jail.local
...
# "bantime" is the number of seconds that a host is banned.
bantime  = 10m

# A host is banned if it has generated "maxretry" during the last "findtime"
# seconds.
findtime  = 10m

# "maxretry" is the number of failures before a host get banned.
maxretry = 5

...

# 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
banaction_allports = iptables-allports

...

# The simplest action to take: ban only
action_ = %(banaction)s[port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"]

...

#
# JAILS
#

#
# SSH servers
#

[sshd]

# To use more aggressive sshd modes set filter parameter "mode" in jail.local:
# normal (default), ddos, extra or aggressive (combines all).
# See "tests/files/logs/sshd" or "filter.d/sshd.conf" for usage example and details.
#mode   = normal
port    = ssh
logpath = %(sshd_log)s
backend = %(sshd_backend)


----
/etc/fail2ban/jail.d/defaults-debian.conf
[sshd]
enabled = true

----
/etc/fail2ban/paths-common.conf
syslog_authpriv = /var/log/auth.log
syslog_daemon  = %(syslog_local0)s
syslog_ftp = %(syslog_local0)s
syslog_mail =
syslog_mail_warn =
syslog_user = %(syslog_local0)s

# Set the default syslog backend target to default_backend
syslog_backend = %(default_backend)s

# Default values for several jails:

sshd_log = %(syslog_authpriv)s
sshd_backend = %(default_backend)s
...

Unha das formas en que fail2ban pode ser xestionado é a través de:

$ sudo systemctl {start | stop | restart | status } fail2ban.service 
$ sudo systemctl status fail2ban
○ fail2ban.service - Fail2Ban Service
     Loaded: loaded (/lib/systemd/system/fail2ban.service; disabled; vendor preset: enabled)
    Drop-In: /run/systemd/system/service.d
             └─zzz-lxc-service.conf
     Active: inactive (dead)
       Docs: man:fail2ban(1)
$ sudo systemctl start fail2ban
$ sudo systemctl status fail2ban
● fail2ban.service - Fail2Ban Service
     Loaded: loaded (/lib/systemd/system/fail2ban.service; disabled; vendor preset: enabled)
    Drop-In: /run/systemd/system/service.d
             └─zzz-lxc-service.conf
     Active: active (running) since Sat 2026-01-31 17:21:06 CET; 1s ago
       Docs: man:fail2ban(1)
   Main PID: 5140 (fail2ban-server)
      Tasks: 5 (limit: 4591)
     Memory: 12.4M
        CPU: 325ms
     CGroup: /system.slice/fail2ban.service
             └─5140 /usr/bin/python3 /usr/bin/fail2ban-server -xf start

ene 31 17:21:06 serverssh systemd[1]: Started Fail2Ban Service.
ene 31 17:21:07 serverssh fail2ban-server[5140]: Server ready
$ cat /var/log/fail2ban.log 
2026-01-31 17:21:07,079 fail2ban.server         [5140]: INFO    --------------------------------------------------
2026-01-31 17:21:07,080 fail2ban.server         [5140]: INFO    Starting Fail2ban v0.11.2
2026-01-31 17:21:07,081 fail2ban.observer       [5140]: INFO    Observer start...
2026-01-31 17:21:07,093 fail2ban.database       [5140]: INFO    Connected to fail2ban persistent database '/var/lib/fail2ban/fail2ban.sqlite3'
2026-01-31 17:21:07,106 fail2ban.database       [5140]: WARNING New database created. Version '4'
2026-01-31 17:21:07,107 fail2ban.jail           [5140]: INFO    Creating new jail 'sshd'
2026-01-31 17:21:07,130 fail2ban.jail           [5140]: INFO    Jail 'sshd' uses pyinotify {}
2026-01-31 17:21:07,135 fail2ban.jail           [5140]: INFO    Initiated 'pyinotify' backend
2026-01-31 17:21:07,137 fail2ban.filter         [5140]: INFO      maxLines: 1
2026-01-31 17:21:07,166 fail2ban.filter         [5140]: INFO      maxRetry: 5
2026-01-31 17:21:07,166 fail2ban.filter         [5140]: INFO      findtime: 600
2026-01-31 17:21:07,167 fail2ban.actions        [5140]: INFO      banTime: 600
2026-01-31 17:21:07,167 fail2ban.filter         [5140]: INFO      encoding: UTF-8
2026-01-31 17:21:07,170 fail2ban.filter         [5140]: INFO    Added logfile: '/var/log/auth.log' (pos = 0, hash = 67a5e2aa9748741bb6d66dd2c49c6171559f4f63)
2026-01-31 17:21:07,180 fail2ban.jail           [5140]: INFO    Jail 'sshd' started
2026-01-31 17:21:08,061 fail2ban.filter         [5140]: WARNING [sshd] Simulate NOW in operation since found time has too large deviation 1769872868.0 ~ 1769876468.0613005 +/- 60
2026-01-31 17:21:08,061 fail2ban.filter         [5140]: WARNING [sshd] Please check jail has possibly a timezone issue. Line with odd timestamp: Jan 31 16:21:08 serverssh sudo:   ubuntu : TTY=pts/2 ; PWD=/home/ubuntu ; USER=root ; COMMAND=/usr/bin/systemctl status fail2ban     

Despois de instalar fail2ban temos unha regra que recolle todo o tráfico ssh con destino ó servidor (cadea INPUT) e o envía á cadea f2b-sshd. Neste momento na cadea f2b-sshd a única regra que hai é un RETURN que devolve os paquetes ssh á cadea INPUT para seguir procesándoos e polo tanto chegarían ó final de INPUT e aplicaríaselles a policy (ACCEPT).

NOTA: non sempre aparece esa regra ó instalar fail2ban e neste caso aparecerá cando comece a bloquear equipos

$ sudo iptables -L -n --line-numbers
Chain INPUT (policy ACCEPT)
num  target     prot opt source               destination         
1    f2b-sshd   tcp  --  0.0.0.0/0            0.0.0.0/0            multiport dports 22

Chain FORWARD (policy ACCEPT)
num  target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
num  target     prot opt source               destination         

Chain f2b-sshd (1 references)
num  target     prot opt source               destination         
1    RETURN     all  --  0.0.0.0/0            0.0.0.0/0           

Agora imos a medusa lanzamos un ataque de diccionario contra o servidor que vemos que se inicia pero que ó pouco deixa de progresar:

$ medusa -h 192.168.100.101 -u asir04 -P rockyou.txt -M ssh -f  -t 6
Medusa v2.2 [http://www.foofus.net] (C) JoMo-Kun / Foofus Networks <jmk@foofus.net>

ACCOUNT CHECK: [ssh] Host: 192.168.100.101 (1 of 1, 0 complete) User: asir04 (1 of 1, 0 complete) Password: 123456 (1 of 14344390 complete)
ACCOUNT CHECK: [ssh] Host: 192.168.100.101 (1 of 1, 0 complete) User: asir04 (1 of 1, 0 complete) Password: 123456789 (2 of 14344390 complete)
ACCOUNT CHECK: [ssh] Host: 192.168.100.101 (1 of 1, 0 complete) User: asir04 (1 of 1, 0 complete) Password: 12345 (3 of 14344390 complete)
ACCOUNT CHECK: [ssh] Host: 192.168.100.101 (1 of 1, 0 complete) User: asir04 (1 of 1, 0 complete) Password: password (4 of 14344390 complete)
ACCOUNT CHECK: [ssh] Host: 192.168.100.101 (1 of 1, 0 complete) User: asir04 (1 of 1, 0 complete) Password: iloveyou (5 of 14344390 complete)
ACCOUNT CHECK: [ssh] Host: 192.168.100.101 (1 of 1, 0 complete) User: asir04 (1 of 1, 0 complete) Password: princess (6 of 14344390 complete)
ACCOUNT CHECK: [ssh] Host: 192.168.100.101 (1 of 1, 0 complete) User: asir04 (1 of 1, 0 complete) Password: 1234567 (7 of 14344390 complete)
ACCOUNT CHECK: [ssh] Host: 192.168.100.101 (1 of 1, 0 complete) User: asir04 (1 of 1, 0 complete) Password: 12345678 (8 of 14344390 complete)
ACCOUNT CHECK: [ssh] Host: 192.168.100.101 (1 of 1, 0 complete) User: asir04 (1 of 1, 0 complete) Password: rockyou (9 of 14344390 complete)
ACCOUNT CHECK: [ssh] Host: 192.168.100.101 (1 of 1, 0 complete) User: asir04 (1 of 1, 0 complete) Password: abc123 (10 of 14344390 complete)
ACCOUNT CHECK: [ssh] Host: 192.168.100.101 (1 of 1, 0 complete) User: asir04 (1 of 1, 0 complete) Password: nicole (11 of 14344390 complete)
ACCOUNT CHECK: [ssh] Host: 192.168.100.101 (1 of 1, 0 complete) User: asir04 (1 of 1, 0 complete) Password: daniel (12 of 14344390 complete)
NOTICE: ssh.mod: failed to connect, port 22 was not open on 192.168.100.101
NOTICE: ssh.mod: failed to connect, port 22 was not open on 192.168.100.101
ERROR: Thread 95021640: Host: 192.168.100.101 Cannot connect [unreachable], retrying (1 of 3 retries)
ERROR: Thread 8FFFF640: Host: 192.168.100.101 Cannot connect [unreachable], retrying (1 of 3 retries)
ERROR: Thread 94820640: Host: 192.168.100.101 Cannot connect [unreachable], retrying (1 of 3 retries)
ERROR: Thread 96023640: Host: 192.168.100.101 Cannot connect [unreachable], retrying (1 of 3 retries)

Se revisamos o firewall no servidor vemos que aparece unha nova regra na cadea f2b-sshd bloqueando á IP correspondente ó equipo medusa. fail2ban encargouse de executar a actionban: iptables -I f2b-sshd 1 -s 192.168.100.100 -j REJECT --reject-with icmp-port-unreachable

$ sudo iptables -L -n --line-numbers
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
f2b-sshd   tcp  --  0.0.0.0/0            0.0.0.0/0            multiport dports 22

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         

Chain f2b-sshd (1 references)
target     prot opt source               destination         
REJECT     all  --  192.168.100.100      0.0.0.0/0            reject-with icmp-port-unreachable
RETURN     all  --  0.0.0.0/0            0.0.0.0/0         

Cando pase o tempo definido na directiva bantime borrarase a regra que bloquea ó equipo medusa. fail2ban encargouse de executar a actionunban: iptables -D f2b-sshd -s 192.168.100.100 -j REJECT --reject-with icmp-port-unreachable

$ sudo iptables -L -n --line-numbers
Chain INPUT (policy ACCEPT)
num  target     prot opt source               destination         
1    f2b-sshd   tcp  --  0.0.0.0/0            0.0.0.0/0            multiport dports 22

Chain FORWARD (policy ACCEPT)
num  target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
num  target     prot opt source               destination         

Chain f2b-sshd (1 references)
num  target     prot opt source               destination         
1    RETURN     all  --  0.0.0.0/0            0.0.0.0/0   

É posible desbloquear manualmente un equipo baneado: primeiro buscamos o nome exacto do jail, revisamos os equipos baneados e despois mandamos a orde de unban a IP de interese.

$ sudo fail2ban-client status
Status
|- Number of jail:    1
`- Jail list:    sshd
$ sudo fail2ban-client status sshd
Status for the jail: sshd
|- Filter
|  |- Currently failed:    1
|  |- Total failed:    12
|  `- File list:    /var/log/auth.log
`- Actions
   |- Currently banned:    1
   |- Total banned:    1
   `- Banned IP list:    192.168.100.100
$ sudo fail2ban-client set sshd unbanip 192.168.100.100
192.168.100.100
$ sudo fail2ban-client status sshd
Status for the jail: sshd
|- Filter
|  |- Currently failed:    1
|  |- Total failed:    12
|  `- File list:    /var/log/auth.log
`- Actions
   |- Currently banned:    0
   |- Total banned:    1
   `- Banned IP list:    

No arquivo de log de fail2ban /var/log/fail2ban.log podemos ver como o equipo foi 'baneado' e tras 600 segundo é 'unbanned':

$ cat /var/log/fail2ban.log 
2024-04-29 18:43:22,970 fail2ban.server         [1481]: INFO    --------------------------------------------------
2024-04-29 18:43:22,970 fail2ban.server         [1481]: INFO    Starting Fail2ban v0.11.2
2024-04-29 18:43:22,971 fail2ban.observer       [1481]: INFO    Observer start...
2024-04-29 18:43:22,978 fail2ban.database       [1481]: INFO    Connected to fail2ban persistent database '/var/lib/fail2ban/fail2ban.sqlite3'
2024-04-29 18:43:22,982 fail2ban.database       [1481]: WARNING New database created. Version '4'
2024-04-29 18:43:22,983 fail2ban.jail           [1481]: INFO    Creating new jail 'sshd'
2024-04-29 18:43:23,006 fail2ban.jail           [1481]: INFO    Jail 'sshd' uses pyinotify {}
2024-04-29 18:43:23,010 fail2ban.jail           [1481]: INFO    Initiated 'pyinotify' backend
2024-04-29 18:43:23,013 fail2ban.filter         [1481]: INFO      maxLines: 1
2024-04-29 18:43:23,031 fail2ban.filter         [1481]: INFO      maxRetry: 5
2024-04-29 18:43:23,031 fail2ban.filter         [1481]: INFO      findtime: 600
2024-04-29 18:43:23,031 fail2ban.actions        [1481]: INFO      banTime: 600
2024-04-29 18:43:23,031 fail2ban.filter         [1481]: INFO      encoding: UTF-8
2024-04-29 18:43:23,033 fail2ban.filter         [1481]: INFO    Added logfile: '/var/log/auth.log' (pos = 0, hash = 718553d99a90c3779ca787665873eb21f6ea0eea)
2024-04-29 18:43:23,034 fail2ban.jail           [1481]: INFO    Jail 'sshd' started
2024-04-29 18:44:36,480 fail2ban.filter         [1481]: INFO    [sshd] Found 192.168.100.100 - 2024-04-29 18:44:36
2024-04-29 18:44:36,481 fail2ban.filter         [1481]: INFO    [sshd] Found 192.168.100.100 - 2024-04-29 18:44:36
2024-04-29 18:44:36,481 fail2ban.filter         [1481]: INFO    [sshd] Found 192.168.100.100 - 2024-04-29 18:44:36
2024-04-29 18:44:36,482 fail2ban.filter         [1481]: INFO    [sshd] Found 192.168.100.100 - 2024-04-29 18:44:36
2024-04-29 18:44:36,482 fail2ban.filter         [1481]: INFO    [sshd] Found 192.168.100.100 - 2024-04-29 18:44:36
2024-04-29 18:44:36,483 fail2ban.filter         [1481]: INFO    [sshd] Found 192.168.100.100 - 2024-04-29 18:44:36
2024-04-29 18:44:37,144 fail2ban.actions        [1481]: NOTICE  [sshd] Ban 192.168.100.100
2024-04-29 18:44:39,190 fail2ban.filter         [1481]: INFO    [sshd] Found 192.168.100.100 - 2024-04-29 18:44:38
2024-04-29 18:44:39,190 fail2ban.filter         [1481]: INFO    [sshd] Found 192.168.100.100 - 2024-04-29 18:44:38
2024-04-29 18:44:39,191 fail2ban.filter         [1481]: INFO    [sshd] Found 192.168.100.100 - 2024-04-29 18:44:38
2024-04-29 18:44:39,192 fail2ban.filter         [1481]: INFO    [sshd] Found 192.168.100.100 - 2024-04-29 18:44:38
2024-04-29 18:44:39,192 fail2ban.filter         [1481]: INFO    [sshd] Found 192.168.100.100 - 2024-04-29 18:44:38
2024-04-29 18:44:39,193 fail2ban.filter         [1481]: INFO    [sshd] Found 192.168.100.100 - 2024-04-29 18:44:38
2024-04-29 18:49:41,819 fail2ban.actions        [1481]: NOTICE  [sshd] Unban 192.168.100.100
maxretry e "Last message repeated N times"

Pode ocorrer que durante as probas de funcionamento un erre en máis de 5 ocasións o contrasinal e fail2ban non bloquea o equipo. Este 'erro' á hora de contar as entradas no auth.log pode ocorrer pola configuración do demo syslog, se a reducción das mensaxes repetidas está activada. Se o parámetro de syslog RepeatedMsgReduction está activado, unha mensaxe que apareza varias veces nun período de tempo moi curto non se repetirá no arquivo de log, senon que aparecerá unha liña indicando que a mesaxe repetiuse x veces:

Oct 29 02:29:38 serverssh sshd[3763]: Failed password for root from 192.168.100.1 port 38600 ssh2
Oct 29 02:29:45 serverssh sshd[3763]: message repeated 2 times: [ Failed password for root from 192.168.100.1 port 38600 ssh2]

Unha solución é poñer o parámetro de syslog RepeatedMsgReduction a off:

$ sudo nano /etc/rsyslog.conf
...
# Filter duplicated messages
$RepeatedMsgReduction off
...
$ sudo systemctl restart rsyslog.service 
$ sudo systemctl restart fail2ban.service