Seguridad SSH · 15 min read · Jan 10, 2026
Prevención de Ataques de Diccionario SSH con DenyHosts
Prevención de Ataques de Diccionario SSH con DenyHosts
Versión 1.0
Autor: Falko Timme
Última edición: 02/07/2006
En este HowTo mostraré cómo instalar y configurar DenyHosts. DenyHosts es una herramienta que observa los intentos de inicio de sesión en SSH, y si encuentra intentos fallidos de inicio de sesión una y otra vez desde la misma dirección IP, DenyHosts bloquea más intentos de inicio de sesión desde esa dirección IP al ponerla en /etc/hosts.deny. DenyHosts se puede ejecutar mediante cron o como un daemon. En este tutorial ejecutaré DenyHosts como un daemon.
Desde el sitio web de DenyHosts:
“DenyHosts es un script destinado a ser ejecutado por administradores de sistemas Linux para ayudar a frustrar ataques al servidor ssh.
Si alguna vez has mirado tu registro ssh (/var/log/secure en Redhat, /var/log/auth.log en Mandrake, etc…) puedes alarmarte al ver cuántos hackers intentaron acceder a tu servidor. Esperemos que ninguno de ellos haya tenido éxito (pero, ¿cómo lo sabrías?). ¿No sería mejor prevenir automáticamente que ese atacante continúe accediendo a tu sistema?
DenyHosts intenta abordar lo anterior…”
Este tutorial se basa en un sistema Debian Sarge, sin embargo, debería aplicarse a otras distribuciones con casi ninguna modificación.
Quiero decir primero que esta no es la única forma de configurar un sistema así. Hay muchas maneras de lograr este objetivo, pero este es el camino que elijo. No emito ninguna garantía de que esto funcione para ti.
1 Instalación
DenyHosts está escrito en Python, por lo tanto, primero debemos instalar Python y también los archivos de desarrollo de Python:
apt-get install python python2.3-dev python2.3
Luego descargamos e instalamos DenyHosts de esta manera:
cd /tmp
wget http://mesh.dl.sourceforge.net/sourceforge/denyhosts/DenyHosts-2.0.tar.gz
tar xvfz DenyHosts-2.0.tar.gz
cd DenyHosts-2.0
python setup.py install
Esto instala DenyHosts en /usr/share/denyhosts.
2 Configuración
Ahora tenemos que crear el archivo de configuración de DenyHosts /usr/share/denyhosts/denyhosts.cfg. Podemos usar el archivo de configuración de muestra /usr/share/denyhosts/denyhosts.cfg-dist para esto:
cd /usr/share/denyhosts
cp denyhosts.cfg-dist denyhosts.cfg
Luego debemos editar denyhosts.cfg con nuestro editor favorito como vi, por ejemplo. El mío se ve así:
| ############ ESTAS CONFIGURACIONES SON REQUERIDAS ############ ######################################################################## # # SECURE_LOG: el archivo de registro que contiene información de registro de sshd # si no estás seguro, grep "sshd:" /var/log/* # # El archivo a procesar puede ser sobreescrito con el argumento de línea de comando --file # # Redhat o Fedora Core: #SECURE_LOG = /var/log/secure # # Mandrake, FreeBSD o OpenBSD: SECURE_LOG = /var/log/auth.log # # SuSE: #SECURE_LOG = /var/log/messages # ######################################################################## ######################################################################## # HOSTS_DENY: el archivo que contiene información de acceso restringido de hosts # # La mayoría de los sistemas operativos: HOSTS_DENY = /etc/hosts.deny # # Algunos BSD (FreeBSD) Unixes: #HOSTS_DENY = /etc/hosts.allow # # Otra posibilidad (también ver la siguiente opción): #HOSTS_DENY = /etc/hosts.evil ####################################################################### ######################################################################## # PURGE_DENY: elimina las entradas de HOSTS_DENY que son más antiguas que este tiempo # cuando DenyHosts es invocado con la bandera --purge # # el formato es: i[dhwmy] # Donde 'i' es un entero (ej. 7) # 'm' = minutos # 'h' = horas # 'd' = días # 'w' = semanas # 'y' = años # # nunca purgar: PURGE_DENY = # # purgar entradas más antiguas que 1 semana #PURGE_DENY = 1w # # purgar entradas más antiguas que 5 días #PURGE_DENY = 5d ####################################################################### ####################################################################### # BLOCK_SERVICE: el nombre del servicio que debe ser bloqueado en HOSTS_DENY # # man 5 hosts_access para detalles # # ej. sshd: 127.0.0.1 # bloqueará inicios de sesión sshd desde 127.0.0.1 # # Para bloquear todos los servicios para el host ofensivo: #BLOCK_SERVICE = ALL # Para bloquear solo sshd: BLOCK_SERVICE = sshd # Para solo registrar el host ofensivo y nada más (si se usa # un archivo auxiliar para listar los hosts). Referirse a: # http://denyhosts.sourceforge.net/faq.html#aux #BLOCK_SERVICE = # ####################################################################### ####################################################################### # # DENY_THRESHOLD_INVALID: bloquear cada host después de que el número de intentos de inicio de sesión fallidos # haya superado este valor. Este valor se aplica a intentos de inicio de sesión de usuario inválidos # (ej. cuentas de usuario no existentes) # DENY_THRESHOLD_INVALID = 5 # ####################################################################### ####################################################################### # # DENY_THRESHOLD_VALID: bloquear cada host después de que el número de fallidos # intentos de inicio de sesión haya superado este valor. Este valor se aplica a intentos de inicio de sesión de usuario válidos # (ej. cuentas de usuario que existen en /etc/passwd) excepto # para el usuario "root" # DENY_THRESHOLD_VALID = 10 # ####################################################################### ####################################################################### # # DENY_THRESHOLD_ROOT: bloquear cada host después de que el número de fallidos # intentos de inicio de sesión haya superado este valor. Este valor se aplica a # intentos de inicio de sesión del usuario "root" únicamente. # DENY_THRESHOLD_ROOT = 5 # ####################################################################### ####################################################################### # # WORK_DIR: la ruta que DenyHosts usará para escribir datos # (se creará si no existe ya). # # Nota: se recomienda que uses una ruta absoluta # para este valor (ej. /home/foo/denyhosts/data) # WORK_DIR = /usr/share/denyhosts/data # ####################################################################### ####################################################################### # # SUSPICIOUS_LOGIN_REPORT_ALLOWED_HOSTS # # SUSPICIOUS_LOGIN_REPORT_ALLOWED_HOSTS=YES|NO # Si se establece en YES, si un intento de inicio de sesión sospechoso resulta de un host permitido # entonces se considera sospechoso. Si esto es NO, entonces los inicios de sesión sospechosos # de hosts permitidos no se informarán. Todos los inicios de sesión sospechosos de # direcciones IP que no están en hosts permitidos siempre se informarán. # SUSPICIOUS_LOGIN_REPORT_ALLOWED_HOSTS=YES ###################################################################### ###################################################################### # # HOSTNAME_LOOKUP # # HOSTNAME_LOOKUP=YES|NO # Si se establece en YES, para cada dirección IP que es reportada por Denyhosts, # se buscará el nombre de host correspondiente y se informará también # (si está disponible). # HOSTNAME_LOOKUP=YES # ###################################################################### ###################################################################### # # LOCK_FILE # # LOCK_FILE=/path/denyhosts # Si este archivo existe cuando se ejecuta DenyHosts, entonces DenyHosts saldrá # inmediatamente. De lo contrario, este archivo se creará al invocarlo # y se eliminará al salir. Esto asegura que solo una instancia esté # en ejecución a la vez. # # Redhat/Fedora: #LOCK_FILE = /var/lock/subsys/denyhosts # # Debian LOCK_FILE = /var/run/denyhosts.pid # # Varios #LOCK_FILE = /tmp/denyhosts.lock # ###################################################################### ############ ESTAS CONFIGURACIONES SON OPCIONALES ############ ####################################################################### # # ADMIN_EMAIL: si deseas recibir correos electrónicos sobre nuevos # hosts restringidos e inicios de sesión sospechosos, establece esta dirección para # que coincida con tu dirección de correo electrónico. Si no deseas recibir estos informes # deja este campo en blanco (o ejecuta con la opción --noemail) # ADMIN_EMAIL = # ####################################################################### ####################################################################### # SMTP_HOST = localhost SMTP_PORT = 25 SMTP_FROM = DenyHosts |
Asegúrate de establecer SECURE_LOG y LOCK_FILE en los valores correctos para tu distribución. Para Debian, estos son:
SECURE_LOG = /var/log/auth.log
LOCK_FILE = /var/run/denyhosts.pid
Como queremos ejecutar DenyHosts como un daemon, necesitamos el script de control del daemon /usr/share/denyhosts/daemon-control. Nuevamente, podemos usar el script de muestra /usr/share/denyhosts/daemon-control-dist para crear el archivo necesario:
cp daemon-control-dist daemon-control
Edita /usr/share/denyhosts/daemon-control y asegúrate de establecer los valores correctos para DENYHOSTS_BIN, DENYHOSTS_LOCK y DENYHOSTS_CFG. Para Debian, estos son:
DENYHOSTS_BIN = “/usr/bin/denyhosts.py”
DENYHOSTS_LOCK = “/var/run/denyhosts.pid”
DENYHOSTS_CFG = “/usr/share/denyhosts/denyhosts.cfg”
Así que mi /usr/share/denyhosts/daemon-control se ve así:
| #!/usr/bin/env python # denyhosts Iniciar/detener el daemon DenyHosts # # chkconfig: 2345 98 02 # descripción: Activa/Desactiva el # daemon DenyHosts para bloquear intentos ssh # ############################################### ############################################### #### Edita esto para adaptarlo a tu configuración #### ############################################### DENYHOSTS_BIN = "/usr/bin/denyhosts.py" DENYHOSTS_LOCK = "/var/run/denyhosts.pid" DENYHOSTS_CFG = "/usr/share/denyhosts/denyhosts.cfg" ############################################### #### No edites abajo #### ############################################### import os, sys, signal, time STATE_NOT_RUNNING = -1 STATE_LOCK_EXISTS = -2 def usage(): print "Uso: %s {start [args...] | stop | restart [args...] | status | debug | condrestart [args...] }" % sys.argv[0] print print "Para una lista de 'args' válidos, refiérete a:" print "$ denyhosts.py --help" print sys.exit(0) def getpid(): try: fp = open(DENYHOSTS_LOCK, "r") pid = int(fp.readline().rstrip()) fp.close() except Exception, e: return STATE_NOT_RUNNING if os.access(os.path.join("/proc", str(pid)), os.F_OK): return pid else: return STATE_LOCK_EXISTS def start(*args): cmd = "%s --daemon " % DENYHOSTS_BIN if args: cmd += ' '.join(args) print "iniciando DenyHosts: ", cmd os.system(cmd) def stop(): pid = getpid() if pid >= 0: os.kill(pid, signal.SIGTERM) print "enviado DenyHosts SIGTERM" else: print "DenyHosts no está en ejecución" def debug(): pid = getpid() if pid >= 0: os.kill(pid, signal.SIGUSR1) print "enviado DenyHosts SIGUSR1" else: print "DenyHosts no está en ejecución" def status(): pid = getpid() if pid == STATE_LOCK_EXISTS: print "%s existe pero DenyHosts no está en ejecución" % DENYHOSTS_LOCK elif pid == STATE_NOT_RUNNING: print "Denyhosts no está en ejecución" else: print "DenyHosts está en ejecución con pid = %d" % pid def condrestart(*args): pid = getpid() if pid >= 0: restart(*args) def restart(*args): stop() time.sleep(1) start(*args) if __name__ == '__main__': cases = {'start': start, 'stop': stop, 'debug': debug, 'status': status, 'condrestart': condrestart, 'restart': restart} try: args = sys.argv[2:] except: args = [] try: option = sys.argv[1] if option in ('start', 'restart', 'condrestart'): if '--config' not in args and '-c' not in args: args.append("--config=%s" % DENYHOSTS_CFG) cmd = cases[option] apply(cmd, args) except: usage() |
A continuación, debemos hacer que ese archivo sea ejecutable:
chown root daemon-control
chmod 700 daemon-control
Después, creamos los enlaces de inicio del sistema para DenyHosts para que se inicie automáticamente cuando se inicie el sistema:
cd /etc/init.d
ln -s /usr/share/denyhosts/daemon-control denyhosts
update-rc.d denyhosts defaults
Finalmente, iniciamos DenyHosts:
/etc/init.d/denyhosts start
DenyHosts registra en /var/log/denyhosts, si estás interesado en los registros. El daemon SSH registra en /var/log/auth.log en Debian. Puedes observar ambos registros e intentar iniciar sesión con un usuario inválido o con un usuario válido y una contraseña incorrecta, etc. a través de SSH y ver qué sucede. Después de haber cruzado el umbral de intentos de inicio de sesión incorrectos, la dirección IP desde la cual intentaste conectarte debería aparecer en /etc/hosts.deny, así:
| # /etc/hosts.deny: lista de hosts que _no_ están permitidos para acceder al sistema. # Ver las páginas manuales hosts_access(5), hosts_options(5) # y /usr/doc/netbase/portmapper.txt.gz # # Ejemplo: ALL: some.host.name, .some.domain # ALL EXCEPT in.fingerd: other.host.name, .other.domain # # Si vas a proteger el portmapper, usa el nombre "portmap" para el # nombre del daemon. Recuerda que solo puedes usar la palabra clave "ALL" y direcciones IP # (NO nombres de host o nombres de dominio) para el portmapper. Ver portmap(8) # y /usr/doc/portmap/portmapper.txt.gz para más información. # # El comodín PARANOID coincide con cualquier host cuyo nombre no coincide con su # dirección. # Puede que desees habilitar esto para asegurar que cualquier programa que no # valide nombres de host buscados aún deje registros comprensibles. En versiones pasadas # de Debian, este ha sido el valor predeterminado. # ALL: PARANOID sshd: 192.168.0.203 |
Esto significa que el sistema con la dirección IP 192.168.0.203 ya no puede conectarse usando SSH.
Puedes especificar si/cuándo se eliminan las direcciones IP nuevamente de /etc/hosts.deny - echa un vistazo a la variable PURGE_DENY en /usr/share/denyhosts/denyhosts.cfg. Debes iniciar DenyHosts con la opción –purge para hacer efectiva la variable PURGE_DENY, así:
/etc/init.d/denyhosts start –purge
Sin embargo, también puedes eliminar direcciones IP manualmente de allí, y tan pronto como se hayan eliminado, estas direcciones IP pueden intentar iniciar sesión nuevamente a través de SSH.
Enlaces
- DenyHosts: http://denyhosts.sourceforge.net
Recibe nuevas publicaciones en tu bandeja de entrada.
No spam. Cancela la suscripción en cualquier momento.