Segurança SSH · 14 min read · Jan 10, 2026

Prevenindo Ataques de Dicionário SSH Com DenyHosts

Prevenindo Ataques de Dicionário SSH Com DenyHosts

Versão 1.0
Autor: Falko Timme
Última edição: 02/07/2006

Neste HowTo, vou mostrar como instalar e configurar o DenyHosts. DenyHosts é uma ferramenta que observa tentativas de login no SSH e, se encontrar tentativas de login falhadas repetidamente do mesmo endereço IP, o DenyHosts bloqueia novas tentativas de login desse endereço IP colocando-o em /etc/hosts.deny. O DenyHosts pode ser executado pelo cron ou como um daemon. Neste tutorial, vou executar o DenyHosts como um daemon.

Do site do DenyHosts:

“DenyHosts é um script destinado a ser executado por administradores de sistema Linux para ajudar a frustrar ataques ao servidor ssh.

Se você já olhou para o seu log ssh (/var/log/secure no Redhat, /var/log/auth.log no Mandrake, etc…) pode ficar alarmado ao ver quantos hackers tentaram acessar seu servidor. Esperançosamente, nenhum deles teve sucesso (mas, novamente, como você saberia?). Não seria melhor prevenir automaticamente que esse atacante continuasse a entrar em seu sistema?

DenyHosts tenta abordar o acima…”

Este tutorial é baseado em um sistema Debian Sarge, no entanto, deve se aplicar a outras distribuições com quase nenhuma modificação.

Quero dizer primeiro que esta não é a única maneira de configurar um sistema assim. Existem muitas maneiras de alcançar esse objetivo, mas este é o caminho que eu sigo. Não dou nenhuma garantia de que isso funcionará para você!

1 Instalação

O DenyHosts é escrito em Python, portanto, devemos instalar o Python e também os arquivos de desenvolvimento do Python primeiro:

apt-get install python python2.3-dev python2.3

Em seguida, baixamos e instalamos o DenyHosts assim:

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

Isso instala o DenyHosts em /usr/share/denyhosts.

2 Configuração

Agora precisamos criar o arquivo de configuração do DenyHosts /usr/share/denyhosts/denyhosts.cfg. Podemos usar o arquivo de configuração de exemplo /usr/share/denyhosts/denyhosts.cfg-dist para isso:

cd /usr/share/denyhosts
cp denyhosts.cfg-dist denyhosts.cfg

Em seguida, devemos editar denyhosts.cfg com nosso editor favorito, como vi, por exemplo. O meu fica assim:

| ############ ESSAS CONFIGURAÇÕES SÃO OBRIGATÓRIAS ############ ######################################################################## # # SECURE_LOG: o arquivo de log que contém informações de log do sshd # se você não tiver certeza, grep "sshd:" /var/log/* # # O arquivo a ser processado pode ser substituído pelo argumento da linha de comando --file # # Redhat ou Fedora Core: #SECURE_LOG = /var/log/secure # # Mandrake, FreeBSD ou OpenBSD: SECURE_LOG = /var/log/auth.log # # SuSE: #SECURE_LOG = /var/log/messages # ######################################################################## ######################################################################## # HOSTS_DENY: o arquivo que contém informações de acesso restrito de hosts # # A maioria dos sistemas operacionais: HOSTS_DENY = /etc/hosts.deny # # Alguns BSD (FreeBSD) Unixes: #HOSTS_DENY = /etc/hosts.allow # # Outra possibilidade (veja também a próxima opção): #HOSTS_DENY = /etc/hosts.evil ####################################################################### ######################################################################## # PURGE_DENY: remove entradas do HOSTS_DENY que são mais antigas que este tempo # quando o DenyHosts é invocado com a flag --purge # # o formato é: i[dhwmy] # Onde 'i' é um inteiro (ex. 7) # 'm' = minutos # 'h' = horas # 'd' = dias # 'w' = semanas # 'y' = anos # # nunca purgar: PURGE_DENY = # # purgar entradas mais antigas que 1 semana #PURGE_DENY = 1w # # purgar entradas mais antigas que 5 dias #PURGE_DENY = 5d ####################################################################### ####################################################################### # BLOCK_SERVICE: o nome do serviço que deve ser bloqueado no HOSTS_DENY # # man 5 hosts_access para detalhes # # ex. sshd: 127.0.0.1 # bloqueará logins sshd de 127.0.0.1 # # Para bloquear todos os serviços para o host ofensivo: #BLOCK_SERVICE = ALL # Para bloquear apenas sshd: BLOCK_SERVICE = sshd # Para apenas registrar o host ofensivo e nada mais (se usar # um arquivo auxiliar para listar os hosts). Consulte: # http://denyhosts.sourceforge.net/faq.html#aux #BLOCK_SERVICE = # ####################################################################### ####################################################################### # # DENY_THRESHOLD_INVALID: bloqueia cada host após o número de tentativas de login falhadas # ter excedido este valor. Este valor se aplica a tentativas de login de usuário inválido # (ex. contas de usuário inexistentes) # DENY_THRESHOLD_INVALID = 5 # ####################################################################### ####################################################################### # # DENY_THRESHOLD_VALID: bloqueia cada host após o número de falhas de # tentativas de login ter excedido este valor. Este valor se aplica a tentativas de login válidas # (ex. contas de usuário que existem em /etc/passwd) exceto # para o usuário "root" # DENY_THRESHOLD_VALID = 10 # ####################################################################### ####################################################################### # # DENY_THRESHOLD_ROOT: bloqueia cada host após o número de falhas de # tentativas de login ter excedido este valor. Este valor se aplica a # tentativas de login do usuário "root" apenas. # DENY_THRESHOLD_ROOT = 5 # ####################################################################### ####################################################################### # # WORK_DIR: o caminho que o DenyHosts usará para gravar dados # (ele será criado se ainda não existir). # # Nota: é recomendado que você use um caminho absoluto # para este valor (ex. /home/foo/denyhosts/data) # WORK_DIR = /usr/share/denyhosts/data # ####################################################################### ####################################################################### # # SUSPICIOUS_LOGIN_REPORT_ALLOWED_HOSTS # # SUSPICIOUS_LOGIN_REPORT_ALLOWED_HOSTS=SIM|NÃO # Se definido como SIM, se uma tentativa de login suspeita resultar de um host permitido # então é considerada suspeita. Se for NÃO, então logins suspeitos # de hosts permitidos não serão relatados. Todos os logins suspeitos de # endereços IP que não estão em hosts permitidos sempre serão relatados. # SUSPICIOUS_LOGIN_REPORT_ALLOWED_HOSTS=SIM ###################################################################### ###################################################################### # # HOSTNAME_LOOKUP # # HOSTNAME_LOOKUP=SIM|NÃO # Se definido como SIM, para cada endereço IP que é relatado pelo Denyhosts, # o nome do host correspondente será pesquisado e relatado também # (se disponível). # HOSTNAME_LOOKUP=SIM # ###################################################################### ###################################################################### # # LOCK_FILE # # LOCK_FILE=/path/denyhosts # Se este arquivo existir quando o DenyHosts for executado, então o DenyHosts sairá # imediatamente. Caso contrário, este arquivo será criado ao ser invocado # e excluído ao sair. Isso garante que apenas uma instância esteja # em execução por vez. # # Redhat/Fedora: #LOCK_FILE = /var/lock/subsys/denyhosts # # Debian LOCK_FILE = /var/run/denyhosts.pid # # Vários #LOCK_FILE = /tmp/denyhosts.lock # ###################################################################### ############ ESSAS CONFIGURAÇÕES SÃO OBRIGATÓRIAS ############ ####################################################################### # # ADMIN_EMAIL: se você gostaria de receber e-mails sobre novos # hosts restritos e logins suspeitos, defina este endereço para # corresponder ao seu endereço de e-mail. Se você não quiser receber esses relatórios # deixe este campo em branco (ou execute com a opção --noemail) # ADMIN_EMAIL = # ####################################################################### ####################################################################### # SMTP_HOST = localhost SMTP_PORT = 25 SMTP_FROM = DenyHosts SMTP_SUBJECT = Relatório DenyHosts #SMTP_USERNAME=foo #SMTP_PASSWORD=bar # ####################################################################### ###################################################################### # # ALLOWED_HOSTS_HOSTNAME_LOOKUP # # ALLOWED_HOSTS_HOSTNAME_LOOKUP=SIM|NÃO # Se definido como SIM, para cada entrada no arquivo WORK_DIR/allowed-hosts, # o nome do host será pesquisado. Se suas versões de tcp_wrappers # e sshd às vezes registram nomes de hosts além de endereços IP # então você pode querer especificar esta opção. # #ALLOWED_HOSTS_HOSTNAME_LOOKUP=NÃO # ###################################################################### ###################################################################### # # AGE_RESET_VALID: Especifica o período de tempo entre tentativas de login falhadas # que, quando excedido, resultará na contagem de falhas para # este host sendo redefinida para 0. Este valor se aplica a tentativas de login # para todos os usuários válidos (aqueles dentro de /etc/passwd) com a # exceção do root. Se não definido, esta contagem nunca # será redefinida. # # Veja os comentários na seção PURGE_DENY (acima) # para detalhes sobre como especificar este valor ou para detalhes completos # consulte: http://denyhosts.sourceforge.net/faq.html#timespec # AGE_RESET_VALID=5d # ###################################################################### ###################################################################### # # AGE_RESET_ROOT: Especifica o período de tempo entre tentativas de login falhadas # que, quando excedido, resultará na contagem de falhas para # este host sendo redefinida para 0. Este valor se aplica a todas as tentativas de login # para a conta de usuário "root". Se não definido, # esta contagem nunca será redefinida. # # Veja os comentários na seção PURGE_DENY (acima) # para detalhes sobre como especificar este valor ou para detalhes completos # consulte: http://denyhosts.sourceforge.net/faq.html#timespec # AGE_RESET_ROOT=25d # ###################################################################### ###################################################################### # # AGE_RESET_INVALID: Especifica o período de tempo entre tentativas de login falhadas # que, quando excedido, resultará na contagem de falhas para # este host sendo redefinida para 0. Este valor se aplica a tentativas de login # feitas para qualquer nome de usuário inválido (aqueles que não aparecem # em /etc/passwd). Se não definido, a contagem nunca será redefinida. # # Veja os comentários na seção PURGE_DENY (acima) # para detalhes sobre como especificar este valor ou para detalhes completos # consulte: http://denyhosts.sourceforge.net/faq.html#timespec # AGE_RESET_INVALID=10d # ###################################################################### ###################################################################### # # PLUGIN_DENY: Se definido, este valor deve apontar para um executável # programa que será invocado quando um host for adicionado ao # arquivo HOSTS_DENY. Este executável receberá o host # que será adicionado como seu único argumento. # #PLUGIN_DENY=/usr/bin/true # ###################################################################### ###################################################################### # # PLUGIN_PURGE: Se definido, este valor deve apontar para um executável # programa que será invocado quando um host for removido do # arquivo HOSTS_DENY. Este executável receberá o host # que deve ser purgado como seu único argumento. # #PLUGIN_PURGE=/usr/bin/true # ###################################################################### ###################################################################### # # USERDEF_FAILED_ENTRY_REGEX: se definido, este valor deve conter # uma expressão regular que pode ser usada para identificar hackers adicionais # para sua configuração ssh particular. Esta funcionalidade # estende as expressões regulares internas que o DenyHosts usa. # Este parâmetro pode ser especificado várias vezes. # Veja esta entrada de faq para mais detalhes: # http://denyhosts.sf.net/faq.html#userdef_regex # #USERDEF_FAILED_ENTRY_REGEX= # ###################################################################### ######### ESSAS CONFIGURAÇÕES SÃO ESPECÍFICAS PARA O MODO DAEMON ########## ####################################################################### # # DAEMON_LOG: quando o DenyHosts é executado no modo daemon (--daemon flag) # este é o arquivo de log que o DenyHosts usa para relatar seu status. # Para desativar o log, deixe em branco. (o padrão é: /var/log/denyhosts) # DAEMON_LOG = /var/log/denyhosts # # desativar log: #DAEMON_LOG = # ###################################################################### ####################################################################### # # DAEMON_LOG_TIME_FORMAT: quando o DenyHosts é executado no modo daemon # (--daemon flag) isso especifica o formato do timestamp das # mensagens do DAEMON_LOG (o padrão é o formato ISO8061: # ou seja, 2005-07-22 10:38:01,745) # # para possíveis valores para este parâmetro consulte: man strftime # # Jan 1 13:05:59 #DAEMON_LOG_TIME_FORMAT = %b %d %H:%M:%S # # Jan 1 01:05:59 #DAEMON_LOG_TIME_FORMAT = %b %d %I:%M:%S # ###################################################################### ####################################################################### # # DAEMON_LOG_MESSAGE_FORMAT: quando o DenyHosts é executado no modo daemon # (--daemon flag) isso especifica o formato da mensagem de cada entrada registrada. # Por padrão, o seguinte formato é usado: # # %(asctime)s - %(name)-12s: %(levelname)-8s %(message)s # # Onde a parte "%(asctime)s" é expandida para o formato # definido por DAEMON_LOG_TIME_FORMAT # # Esta string é passada para o construtor logging.Formatter do python. # Para detalhes sobre os possíveis tipos de formato, consulte: # http://docs.python.org/lib/node357.html # # Este é o padrão: #DAEMON_LOG_MESSAGE_FORMAT = %(asctime)s - %(name)-12s: %(levelname)-8s %(message)s # ###################################################################### ####################################################################### # # DAEMON_SLEEP: quando o DenyHosts é executado no modo daemon (--daemon flag) # este é o tempo que o DenyHosts irá dormir entre as verificações # do SECURE_LOG. Veja os comentários na seção PURGE_DENY (acima) # para detalhes sobre como especificar este valor ou para detalhes completos # consulte: http://denyhosts.sourceforge.net/faq.html#timespec # DAEMON_SLEEP = 30s # ####################################################################### ####################################################################### # # DAEMON_PURGE: Com que frequência o DenyHosts, quando executado no modo daemon, # deve executar o mecanismo de purga para expirar entradas antigas no HOSTS_DENY # Isso não tem efeito se PURGE_DENY estiver em branco. # DAEMON_PURGE = 1h # ####################################################################### ######### ESSAS CONFIGURAÇÕES SÃO ESPECÍFICAS PARA ########## ######### SINCRONIZAÇÃO DO DAEMON ########## ####################################################################### # # O modo de sincronização permite que o daemon DenyHosts # envie e receba dados de hosts negados periodicamente, de modo que # os daemons DenyHosts em todo o mundo possam informar automaticamente # uns aos outros sobre hosts banidos. Este modo está desativado por # padrão, você deve descomentar SYNC_SERVER para habilitar este modo. # # para mais informações, consulte: # http:/denyhosts.sourceforge.net/faq.html#sync # ####################################################################### ####################################################################### # # SYNC_SERVER: O servidor central que se comunica com os daemons DenyHost # Atualmente, denyhosts.net é o único servidor disponível # no entanto, no futuro, pode ser possível que organizações # instalem seu próprio servidor para sincronização de rede interna # # Para desativar a sincronização (o padrão), não faça nada. # # Para habilitar a sincronização, você deve descomentar a seguinte linha: #SYNC_SERVER = http://xmlrpc.denyhosts.net:9911 # ####################################################################### ####################################################################### # # SYNC_INTERVAL: o intervalo de tempo para realizar sincronizações se # SYNC_SERVER foi descomentado. O padrão é 1 hora. # #SYNC_INTERVAL = 1h # ####################################################################### ####################################################################### # # SYNC_UPLOAD: permitir que seu daemon DenyHosts transmita hosts que foram # negados? Esta opção só se aplica se SYNC_SERVER foi # descomentado. # #SYNC_UPLOAD = não # # o padrão: #SYNC_UPLOAD = sim # ####################################################################### ####################################################################### # # SYNC_DOWNLOAD: permitir que seu daemon DenyHosts receba hosts que foram # negados por outros? Esta opção só se aplica se SYNC_SERVER foi # descomentado. # #SYNC_DOWNLOAD = não # # o padrão: #SYNC_DOWNLOAD = sim # ####################################################################### ####################################################################### # # SYNC_DOWNLOAD_THRESHOLD: Se SYNC_DOWNLOAD estiver habilitado, este parâmetro # filtra os hosts retornados para aqueles que foram bloqueados este número # de vezes por outros. Ou seja, se definido como 1, então se um único servidor DenyHosts # negou um endereço IP, você receberá o host negado. # #SYNC_DOWNLOAD_THRESHOLD = 10 # # o padrão: #SYNC_DOWNLOAD_THRESHOLD = 3 # ####################################################################### |

Certifique-se de definir SECURE_LOG e LOCK_FILE para os valores corretos para sua distribuição! Para Debian, estes são:

SECURE_LOG = /var/log/auth.log
LOCK_FILE = /var/run/denyhosts.pid

Como queremos executar o DenyHosts como um daemon, precisamos do script de controle do daemon /usr/share/denyhosts/daemon-control. Novamente, podemos usar o script de exemplo /usr/share/denyhosts/daemon-control-dist para criar o arquivo necessário:

cp daemon-control-dist daemon-control

Edite /usr/share/denyhosts/daemon-control e certifique-se de definir os valores corretos para DENYHOSTS_BIN, DENYHOSTS_LOCK e DENYHOSTS_CFG. Para Debian, estes são:

DENYHOSTS_BIN = “/usr/bin/denyhosts.py”
DENYHOSTS_LOCK = “/var/run/denyhosts.pid”
DENYHOSTS_CFG = “/usr/share/denyhosts/denyhosts.cfg”

Então meu /usr/share/denyhosts/daemon-control fica assim:

| #!/usr/bin/env python # denyhosts Ativa/desativa o daemon DenyHosts # # chkconfig: 2345 98 02 # descrição: Ativa/Desativa o # daemon DenyHosts para bloquear tentativas de ssh # ############################################### ############################################### #### Edite isso para se adequar à sua configuração #### ############################################### DENYHOSTS_BIN = "/usr/bin/denyhosts.py" DENYHOSTS_LOCK = "/var/run/denyhosts.pid" DENYHOSTS_CFG = "/usr/share/denyhosts/denyhosts.cfg" ############################################### #### Não edite abaixo #### ############################################### 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 uma lista de 'args' válidos, consulte:" 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 SIGTERM para DenyHosts" else: print "DenyHosts não está em execução" def debug(): pid = getpid() if pid >= 0: os.kill(pid, signal.SIGUSR1) print "enviado SIGUSR1 para DenyHosts" else: print "DenyHosts não está em execução" def status(): pid = getpid() if pid == STATE_LOCK_EXISTS: print "%s existe, mas DenyHosts não está em execução" % DENYHOSTS_LOCK elif pid == STATE_NOT_RUNNING: print "Denyhosts não está em execução" else: print "DenyHosts está em execução com 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() |

Em seguida, precisamos tornar esse arquivo executável:

chown root daemon-control
chmod 700 daemon-control

Depois, criamos os links de inicialização do sistema para o DenyHosts para que ele seja iniciado automaticamente quando o sistema for inicializado:

cd /etc/init.d
ln -s /usr/share/denyhosts/daemon-control denyhosts
update-rc.d denyhosts defaults

Finalmente, iniciamos o DenyHosts:

/etc/init.d/denyhosts start

O DenyHosts registra em /var/log/denyhosts, se você estiver interessado nos logs. O daemon SSH registra em /var/log/auth.log no Debian. Você pode observar ambos os logs e tentar fazer login com um usuário inválido ou com um usuário válido e senha incorreta, etc. via SSH e ver o que acontece. Depois de ultrapassar o limite de tentativas de login incorretas, o endereço IP do qual você tentou se conectar deve ser listado em /etc/hosts.deny, assim:

| # /etc/hosts.deny: lista de hosts que não têm permissão para acessar o sistema. # Veja as páginas man hosts_access(5), hosts_options(5) # e /usr/doc/netbase/portmapper.txt.gz # # Exemplo: ALL: some.host.name, .some.domain # ALL EXCEPT in.fingerd: other.host.name, .other.domain # # Se você vai proteger o portmapper, use o nome "portmap" para o # nome do daemon. Lembre-se de que você só pode usar a palavra-chave "ALL" e endereços IP # (NÃO nomes de host ou de domínio) para o portmapper. Veja portmap(8) # e /usr/doc/portmap/portmapper.txt.gz para mais informações. # # O curinga PARANOID corresponde a qualquer host cujo nome não corresponda ao seu # endereço. # Você pode querer habilitar isso para garantir que qualquer programa que não # valide nomes de hosts pesquisados ainda deixe logs compreensíveis. Nas versões anteriores # do Debian, isso foi o padrão. # ALL: PARANOID sshd: 192.168.0.203 |

Isso significa que o sistema com o endereço IP 192.168.0.203 não pode mais se conectar usando SSH.

Você pode especificar se/quando os endereços IP são removidos novamente de /etc/hosts.deny - dê uma olhada na variável PURGE_DENY em /usr/share/denyhosts/denyhosts.cfg. Você deve iniciar o DenyHosts com a opção –purge para que a variável PURGE_DENY tenha efeito, assim:

/etc/init.d/denyhosts start –purge

No entanto, você também pode remover endereços IP manualmente de lá, e assim que eles forem removidos, esses endereços IP podem tentar fazer login novamente via SSH.

Links

Share: X/Twitter LinkedIn

Receba novas postagens na sua caixa de entrada

Sem spam. Cancele a assinatura a qualquer momento.