Atenção: esse artigo tem um vídeo complementar. Clique e assista!

Do que se trata este artigo:

Este artigo tem como objetivo demonstrar de forma prática uma técnica capaz de confundir scanners mal intencionados na procura por serviços de acesso remoto ativos no servidor, tornando a porta de acesso remoto do SSH (Secure Shell) oculta para estas ameaças. A técnica de port knocking, aliada às configurações de segurança do SSH, cria um canal confiável de comunicação para servidores GNU/Linux.


Para que serve:

A técnica de port knocking está intimamente ligada ao SSH, que simultaneamente é um programa e um protocolo de rede capaz de permitir conexões remotas por meio das redes de computadores, de forma a permitir a execução de comandos em um computador remoto. O SSH vem se tornando a cada dia mais popular entre os administradores de sistemas e, por conta de sua facilidade de uso e por possuir diversos sistemas clientes, proporciona uma grande flexibilidade e segurança na autenticação e proteção do tráfego de dados.


Em que situação o tema é útil:

A técnica port knocking, e procedimentos relacionados, podem ser aplicados em servidores que necessitam de conexão remota para a administração. Implementando mecanismos e configurações de segurança, o usuário administrador não irá efetuar login diretamente no sistema remoto. Pode-se criar uma configuração automática de lista negra de endereços IP, tempo de inatividade de seção, ocultamento da porta de conexão remota, dentre outras técnicas que serão apresentadas posteriormente.

Autores: Flávio Alexandre dos Reis e Eduardo Pagani Julio

Uma das grandes vantagens no uso do GNU/Linux é a facilidade de administrar o sistema remotamente, seja administração feita via linha de comando ou com acesso à interface gráfica. Essa é uma necessidade para qualquer administrador de redes que mantém diversos servidores, em diferentes locais.

Nos dias atuais, poucas empresas hospedam seus websites em servidores instalados dentro da própria empresa. Quase sempre os servidores ficam hospedados em data centers que oferecem toda a estrutura necessária para que os serviços fiquem em funcionamento de forma confiável, incluindo links redundantes, no-breaks de grande porte, geradores, refrigeração, dentre outras vantagens.

Dessa forma, apesar do servidor ser de propriedade da empresa, o administrador não tem nenhum tipo de acesso físico a ele, tudo terá que ser feito à distância.

No GNU/Linux, toda a configuração do sistema, instalação de novos programas, dentre algumas funcionalidades, podem ser feitas a partir do modo texto, o que permite configurar o servidor e mantê-lo atualizado remotamente, não dependendo de aplicações específicas de modo gráfico. Toda essa manutenção poderá ser efetuada de outro sistema operacional. Por exemplo, uma estação Windows pode efetuar um acesso remoto a um servidor GNU/Linux, possibilitando assim a manutenção desejada.

Um exemplo comum no uso de acesso remoto é dentro das redes locais para acesso a aplicativos. Em muitas situações, faz sentido instalar determinados aplicativos em um servidor central e abrir seções remotas nos clientes, permitindo assim a centralização de informações no servidor (facilitando os backups, por exemplo) e, ao mesmo tempo, usar menos recursos nos clientes, o que possibilita o uso de micros mais antigos.

TELNET

O serviço telnet é um protocolo de acesso remoto cliente/servidor que permite ao administrador trabalhar conectado a outro computador à distância como se estivesse em frente ao mesmo. Esse protocolo chegou para substituir o rlogin e possui muitas melhorias em relação a seu antecessor, como o controle de acesso, personalização de seção e controle de terminal.

O telnet viabiliza emular terminais, permitindo assim ao usuário acessar aplicações remotas que estejam disponibilizadas em outras redes. A partir do momento que se inicia a seção de trabalho, qualquer comando digitado é enviado diretamente para o computador remoto. Será solicitado um username e uma password para acessar o sistema, conforme visto na Figura 1.

Figura 1. Início da conexão com servidor telnet.

O protocolo telnet oferece um terminal virtual de rede, que proporciona uma interface padrão para aplicações remotas, não havendo necessidade de um programa cliente compreender os detalhes de todos os possíveis sistemas remotos. Inclui um mecanismo que permite ao cliente e ao servidor negociarem opções e proporcionar um conjunto de opções padrão. Trata ambas as pontas da conexão simetricamente. Assim, ao invés de forçar o cliente a conectar-se a um terminal de usuário, o protocolo telnet permite um programa arbitrário tornar-se um cliente.

A seguir são listadas algumas características do protocolo telnet:

• Conexão rápida (não utiliza transmissão de dados criptografada), recomendado para ambientes seguros;

• Possui uma versão com suporte a criptografia via ssl;

• Possui controle de acesso tcpd (usando /etc/hosts.allow e /etc/hosts.deny);

• A maioria dos sistemas operacionais possui esse utilitário por padrão como sistema de acesso remoto a máquinas UNIX;

• Suporte a terminais ANSI (cores e códigos de escape especiais para o console) e uma grande variedade de outros terminais;

• O telnet responde por padrão na porta 23/tcp.

Um servidor telnet poderá criar arquivos de log a fim de auditar o sistema. As mensagens do servidor telnet relacionadas com seções são enviadas para /var/log/daemon.log, conforme visto na Figura 2.

Figura 2. Exemplo do arquivo /var/log/daemon.log.

As mensagens sobre autenticação e serviços de login são registradas pelos módulos PAM (Sistema padrão de autenticação do GNU/Linux) em /var/log/auth.log, conforme visto na Figura 3.

Figura 3. Exemplo do arquivo /var/log/auth.log.

O programa tcpd, que pode ser configurado no arquivo /etc/inetd.conf, oferece mecanismos de registro e controle de acesso para os serviços que está configurado para proteger. Ele é um tipo de firewall simples, de fácil configuração, que pode evitar conexões indesejadas e ainda registrar possíveis tentativas de invasão. Quando é executado pelo programa inetd (veja a Nota DevMan 1), lê os arquivos contendo regras de acesso, permitindo ou bloqueando o acesso ao servidor. Se nenhuma regra conferir, então assume que o acesso deve ser permitido a qualquer um. Esse tipo de bloqueio é conhecido como TCP WRAPPERS e pode ser configurado nos arquivos /etc/hosts.allow e /etc/hosts.deny.

Nota DevMan 1. inetd

É chamado de “Super-Servidor Internet” porque gerencia conexões para diversos daemons. Daemons são processos que rodam em segundo plano esperando por requisições.

O arquivo hosts.allow contém regras descrevendo que hosts têm permissão de acessar um serviço na máquina. O formato do arquivo é muito simples, como visto na Listagem 1.

Listagem 1. Estrutura do arquivo hosts.allow.

  # /etc/hosts.allow
  #
  # lista de serviços: lista de hosts: comando 

No campo lista de serviços será inserida uma lista com seus nomes (separados por vírgula), aonde essa regra irá se aplicar. Alguns exemplos são: ftpd, telnetd e fingerd.

Na lista de hosts do arquivo, pode-se especificar nomes de computadores ou endereços IP usando caracteres coringas para atingir grupos de hosts. O arquivo poderá conter um endereço específico ou combinações de strings para atingir qualquer endereço de computador. Alguns parâmetros especiais também podem ser utilizados para simplificar a configuração, são eles: ALL, atinge todos os endereços; LOCAL, atinge qualquer computador que não contém um “.” (isto é, está no mesmo domínio de sua máquina); e PARANOID, que atinge qualquer computador que o nome não confere com seu endereço (falsificação de nome). Existe também um último parâmetro, o EXCEPT, útil quando se deseja criar uma lista de exceções.

A opção “comando” na Listagem 1 é um parâmetro opcional. Nesse parâmetro é inserido o caminho completo de um comando que deverá ser executado toda vez que a regra for utilizada. Nesta opção pode ser executado um comando para tentar identificar quem está conectado pelo host remoto, para gerar uma mensagem via e-mail ou algum outro alerta para um administrador de rede informando que alguém está tentando se conectar.

Existe um grande número de opções que podem ser incluídas. Alguns exemplos comuns são: com a opção “%h” será inserido o nome do computador que está conectado. A opção “%d” insere o nome do daemon a ser chamado. Se o computador tiver permissão de acessar um serviço através do /etc/hosts.allow, então o /etc/hosts.deny não será consultado e o acesso será permitido. Um exemplo do /etc/hosts.allow pode ser observado na Listagem 2.

Listagem 2. Exemplo do arquivo hosts.allow.

  # /etc/hosts.allow
  #
  # Permite que qualquer um envie e-mails
  in.smtpd: ALL
  # Permite telnet e ftp somente para hosts locais e myhost.athome.org.au
  in.telnetd, in.ftpd: LOCAL, myhost.athome.org.au
  # Permite finger para qualquer um, mas manter um registro de quem é.
  in.fingerd: ALL: (finger @%h | mail -s "finger from %h" root) 

Qualquer modificação no arquivo /etc/hosts.allow entrará em ação após reiniciar o daemon inetd. Isso pode ser feito com o comando invoke-rc.d openbsd-inetd restart.

O arquivo /etc/hosts.deny é um arquivo de configuração das regras que descreve quais computadores não têm a permissão de acessar um serviço na máquina. Um modelo simples deste arquivo pode ser observado na Listagem 3.

Listagem 3. Exemplo do arquivo hosts.deny.

  # /etc/hosts.deny
  #
  # Bloqueia o acesso de computadores com endereços suspeitos
  ALL: PARANOID
  #
  # Bloqueia todos os computadores
  ALL: ALL 

A entrada PARANOID será redundante, pois a entrada seguinte irá negar tudo. Qualquer uma destas linhas pode aumentar a segurança dependendo de seu requerimento em particular. Tendo um padrão que bloqueia tudo “ALL: ALL” no arquivo /etc/hosts.deny, deverão então ser ativados os serviços específicos no /etc/hosts.allow, permitindo acesso aos computadores que se deseja, e assim deixando uma configuração mais adequada e segura. Qualquer modificação no arquivo /etc/hosts.deny entrará em ação após reiniciar o daemon inetd, pois este é responsável pelas requisições. Isto pode ser feito executando o comando invoke-rc.d openbsd-inetd restart, de forma semelhante a hosts.allow. Para uma descrição completa das opções fornecidas, deve-se verificar a página de manual apropriada com o comando man 5 hosts_access.

O serviço telnet utiliza texto plano para seção (exceto nas versões cliente/servidor “-ssl”). Os dados transmitidos por serviços que utilizam texto plano podem ser capturados por sniffers (programas que capturam pacotes em uma rede) e trazer perigo ao sistema. É recomendável somente executar o servidor telnet padrão em ambientes seguros (como em uma rede interna) e a versão com suporte a ssl para fazer conexões via redes inseguras (como a Internet). O serviço SSH é uma excelente alternativa ao telnet. Além de possuir outras características adicionais que justificam seu uso, possui programas cliente para sistemas operacionais GNU/Linux e Windows.

A falta de segurança no protocolo telnet pode ser observada com o uso do aplicativo dsniff (uma coleção de ferramentas de análise de conteúdo de pacote TCP/IP, utilizado para capturar o tráfego de rede). Sendo assim, é possível monitorar o tráfego da rede e descobrir problemas como:

Tráfego intenso: se a rede estiver com uma velocidade inferior aos padrões, uma boa alternativa é utilizar um sniffer para descobrir as possíveis causas;

Serviços de rede consumindo exageradamente recursos do sistema: um sniffer possibilita verificar quais máquinas estão utilizando o serviço. Determina a quantidade de conexões que um cliente estabeleceu com o servidor;

Monitoramento de serviços: muitas vezes é necessário saber como determinados serviços estão se comportando na rede, principalmente os que não possuem um sistema eficiente de log.

Um programa pode ser utilizado com o objetivo de capturar informações sigilosas na rede. Este é um dos principais problemas de segurança nas redes de computadores atualmente. O telnet, por exemplo, é um tipo de serviço que não utiliza de criptografia para trafegar seus dados na rede, estando assim vulnerável a esse tipo de ataque.

Com o dsniff pode-se capturar todos os dados que trafegam na rede, inclusive os bits dos pacotes TCP/IP que armazenam as senhas.

No exemplo a seguir, o host cliente com IP 192.168.105.7 faz uma conexão telnet no servidor com IP 192.168.105.100. Toda operação do cliente será capturada com o uso do dsniff, conforme visto na Listagem 4.

Listagem 4. Exemplo de captura com dsniff.

  # dsniff -d -m -i eth0 -w trafego.log 

Onde:

dsniff: programa utilizado para capturar o tráfego;

• -d: parâmetro usado para modo de debug;

• -m: parâmetro utilizado para detectar automaticamente os protocolos;

• -i : parâmetro utilizado para indicar uma interface;

• eth0: interface de rede utilizada;

• -w: parâmetro utilizado para informar um arquivo de saída;

trafego.log: arquivo onde os dados de saída serão gravados.

Com o uso da opção “-r” após o comando dsniff, pode-se analisar os dados capturados, como por exemplo, usuário “flavio” e senha “!@s3curityd3b#2o1o”. Mesmo a senha sendo considerada segura, por fazer combinação de letras, números e caracteres especiais, ela foi capturada com sucesso, assim como toda operação efetuada pelo usuário. Observe que o exemplo da saída do comando é visto na Listagem 5.

Listagem 5. Exemplo de log capturado pelo dsniff.

  # dsniff -r trafego.log 
  -----------------
  07/10/10 08:32:59 tcp 192.168.105.7.1046 -> 192.168.105.100.23 (telnet)
  flavio
  !@s3curityd3b#2o1o
  cd /etc
  ls -l
  cat fstab
  exit 

SSH

O SSH (Secure shell) é conhecido pelos administradores como o canivete suíço da administração de sistemas por possibilitar que toda a configuração, atualizações de segurança e instalação de novos programas seja realizada remotamente em sistemas Linux.

Ele proporciona flexibilidade ao administrador, pois as conexões remotas utilizando SSH podem ser realizadas a partir de vários sistemas operacionais clientes, entre eles o Windows, que possui aplicativos capazes de realizar acesso seguro a um sistema GNU/Linux, como exemplo, o aplicativo Putty.

O benefício de realizar suporte remoto em ambientes GNU/Linux com segurança, seja em uma LAN (Local Area Network) ou WAN (Wide Area Network), é certamente o ponto principal do SSH. As técnicas de criptografia empregadas em sua utilização são o que o difere das demais soluções disponíveis e, se bem configurado, é capaz de proporcionar os mais altos níveis de segurança para um acesso remoto, chegando a ser citado por alguns autores como sendo impenetrável virtualmente.

Estudos revelam que é inviável tentar quebrar uma senha utilizada por uma conexão SSH com força bruta (ver Nota DevMan 2), uma vez que esse tipo de conexão utiliza criptografia de 512 bits para a realização de troca de chaves. Pode-se ter uma ideia do tempo que levaria para quebrar uma chave utilizada em uma conexão SSH analisando estudos realizados no protocolo de criptografia mais tradicional, o DES, que utiliza 64 bits para a criptografia de chaves. É possível decifrar uma chave criptografada com DES em menos de um dia, caso se tenha acesso a uma estrutura de cluster com 100 máquinas e processadores Xeon ou Opteron quad-core.

A vulnerabilidade de segurança do acesso remoto está ligada ao rápido descobrimento das chaves de acesso por exploração de vulnerabilidades existentes nos algoritmos de encriptação. No entanto, vulnerabilidades graves nos algoritmos de encriptação utilizados no SSH são descartadas totalmente, uma vez que diversos servidores importantes de todo o mundo utilizam este recurso para sua administração.

Nota DevMan 2. Força Bruta

Consiste na utilização de ferramentas capazes de testar várias combinações possíveis de chaves até conseguir a combinação correta e obter acesso ao sistema.

O SSH utiliza em seu processo de autenticação chaves assimétricas, ou seja, são geradas duas chaves, sendo uma pública (utilizada para encriptar os dados) e outra privada (utilizada para decriptar os dados).

É interessante descrever que, na utilização de chaves assimétricas, a informação é encriptada com a chave pública e decriptada somente pelo detentor da chave privada correspondente. Diferente do processo com chave simétrica, onde é utilizada uma chave única para a encriptação e decriptação dos dados, conforme observado na Figura 4.

Figura 4. Representação do processo de autenticação realizado no SSH.

Inicialmente o cliente SSH solicita uma conexão à máquina servidora. O primeiro passo, antes que ocorra qualquer troca de informação entre as máquinas, consiste na troca de suas chaves públicas. Ou seja, o servidor envia ao cliente a sua chave pública, e o cliente envia sua chave pública ao servidor para que seja realizada a checagem de autenticidade durante a troca de chaves e dados, como apresenta a Figura 5.

Figura 5. Solicitação de conexão SSH enviada por um cliente.

Após a troca de chaves entre os envolvidos, será solicitado usuário e senha para autenticação do acesso. Essa e todas as outras chaves recebidas pelo cliente SSH serão armazenadas no arquivo .ssh/known_hosts do usuário, onde se encontram as chaves públicas de todos os hosts conhecidos por ele. A Figura 6 apresenta uma chave pública enviada pelo servidor ao cliente.

Figura 6. Verificação de persistência de chave pública enviada pelo servidor.

Devido à grande aceitação e utilização do serviço de acesso remoto por meio do SSH, sua instalação tornou-se bastante simples. Os pacotes “openssh-server” e ”openssh-client” já são encontrados na grande parte dos repositórios das mais variadas distribuições GNU/LINUX, assim como no site padrão do projeto (http://www.openssh.com/), onde poderão ser localizadas as últimas atualizações.

Grande parte dos administradores tem como conhecimento que o arquivo tem uma configuração padrão, mas é possível proporcionar diversas configurações de segurança. São essas configurações que serão abordadas a partir de agora.

Hardening de serviço SSH

A realização de uma análise no arquivo de configuração do servidor é fundamental para que o serviço seja disponibilizado com alto nível de segurança. Após uma instalação padrão, algumas configurações podem tornar inseguro o serviço, tais como, permitir login remoto por qualquer usuário, inclusive o root, o que pode ser visto na Figura 7.

Figura 7. Acessando o servidor SSH como root.

As configurações de segurança do servidor SSH estão disponíveis no arquivo /etc/ssh/sshd_config. Vale salientar que no diretório /etc/ssh também está presente o arquivo de configuração do cliente SSH, o “ssh_config”.

Para iniciar a configuração do servidor deve-se editar o arquivo /etc/sshd_config, conforme exemplo da Listagem 6.

Listagem 6. Editando conteúdo do arquivo sshd_config.

  # vim /etc/ssh/sshd_config 

Por padrão, o servidor SSH vem configurado para aceitar conexões na porta 22. É aconselhável que esse valor seja alterado, por exemplo, para 2222 (Listagem 7).

Listagem 7. Porta padrão SSH.

  # Package generated configuration file
  # See the sshd(8) manpage for details
  # What ports, IPs and protocols we listen for
  Port 22
  # Use these options to restrict which interfaces/protocols sshd will bind to
  #ListenAddress ::
  #ListenAddress 0.0.0.0 

Dessa forma, a maioria das tentativas de ataques como, por exemplo, utilizando scanners de rede, não irão obter sucesso em suas varreduras, pois normalmente são configurados para realizar buscas a portas conhecidas e, não encontrando o serviço, dificulta a possibilidade de exploração de alguma brecha de segurança que venha a existir no servidor SSH. Após realizar essa alteração, será necessário utilizar o parâmetro “-p” no comando de conexão do cliente para explicitar a porta que está sendo utilizada no servidor, de acordo com a Listagem 8.

Listagem 8. Utilização do parâmetro -p para solicitação de acesso remoto.

  $ ssh -p 2222 flavio@192.168.30.1 

A diretiva “ListenAddress 0.0.0.0” permite ao administrador do sistema apontar em quais interfaces o servidor SSH poderá ser acessado como, por exemplo, em servidores firewall, onde existem duas interfaces de rede. Pode-se informar o endereço IP da interface interna para que somente sejam permitidos acessos via SSH originados da rede local, como apresenta a Listagem 9.

Por padrão, o servidor SSH está habilitado para receber conexões originadas de qualquer uma de suas interfaces.

Listagem 9. Apontando a interface de conexão.

  ListenAddress 192.168.30.3 

A diretiva “Protocol” representa a versão do protocolo utilizada no servidor. Atualmente os pacotes disponibilizados nos repositórios das distribuições GNU/LINUX já se encontram atualizados para a versão 2, uma vez que a versão SSH 1 foi totalmente descontinuada devido a sérios problemas de segurança em seu funcionamento. Portanto, no servidor SSH deve somente constar a versão 2 na linha protocolo, conforme a Listagem 10.

Listagem 10. Apontando a versão de SSH aceita pelo servidor.

  Protocol 2 

Como informado anteriormente, o servidor SSH, em sua configuração padrão, permite que o usuário root realize acesso remoto ao servidor, o que não é uma boa prática de segurança. Se um invasor obtiver sucesso na exploração de uma vulnerabilidade, este terá acesso total ao sistema e poderá realizar qualquer atividade como instalação, alteração ou remoção de pacotes, utilizar os recursos de hardware para ataques em novas estruturas, entre outros.

Para resolver este problema de segurança, deve-se utilizar a opção “PermitRootLogin”, encontrada no arquivo de configuração. Por padrão, essa opção recebe o valor “yes” e deve ser trocada para “no”, como visto na Listagem 11.

Listagem 11. Retirando permissão de acesso remoto do usuário root.

  # Valor padrão
  PermitRootLogin yes
  # Valor alterado
  PermitRootLogin no 

Após realizar a alteração de permissão de acesso do usuário root, somente usuários comuns poderão acessar o servidor SSH. Com isso, é reduzido consideravelmente o risco, uma vez que será necessário realizar o login com um usuário comum e, depois de logado, fazer o login como root utilizando o comando sudo su -. Deste modo o invasor terá que descobrir duas senhas antes de ter acesso como administrador ao sistema.

É possível realizar um filtro ainda mais restritivo com a utilização das opções do arquivo de configuração. Por exemplo: pode-se retirar o comentário da opção “AllowUsers” e informar como parâmetro o nome do usuário que terá direito de realizar acesso remoto ao servidor SSH, como pode ser observado na Listagem 12.

Listagem 12. Habilitando usuário para realizar acesso remoto.

  AllowUsers reisfa 

Com o objetivo de dificultar as tentativas de invasão do servidor por um intruso que, por ventura, venha a descobrir a porta em que funciona o servidor SSH, é disponibilizada a opção “LoginGraceTime” que, quando utilizada, emprega o valor informado como parâmetro para limitar o tempo de tentativa de uma conexão. No exemplo da Listagem 13 está sendo informado o tempo de 60 segundos para a tentativa de conexão. Caso o login não seja realizado com sucesso, a conexão é fechada automaticamente.

Listagem 13. Informando tempo para tentativa de conexão.

  LoginGraceTime 60 

Em resumo, pode-se concluir que com as configurações realizadas acima, o servidor somente aceitará conexões de clientes SSH versão 2, na porta 2222 e que estejam na rede local. Atendendo a essas necessidades iniciais, somente o usuário marcos poderá autenticar-se e fazer login no sistema.

Recent

O módulo recent está disponível para uso com o iptables. Iptables é um firewall em nível de pacotes que funciona baseado no endereço/porta de origem/destino do pacote, prioridade, etc. Ele faz uma comparação de regras para saber se um pacote tem ou não permissão para passar.

O módulo cria uma tabela dinâmica com endereços IPs “recentes”, ou IPs setados pelo administrador, podendo dessa forma criar exceções. Um ponto interessante referente a esse módulo é que se pode alterar dinamicamente uma regra que foi anteriormente criada.

O administrador poderá criar regras no firewall para manter uma porta fechada e liberá-la quando um usuário mandar uma sequência de pacotes syn a algumas portas pré-determinadas. A porta referente ao serviço desejado será mantida fechada e, quando for necessário efetuar o acesso, um pedido de conexão via telnet será enviado nas portas definidas.

Assim, a porta será aberta para o IP informado. Se algum invasor tentar executar um portscanner não terá sucesso, pois a porta estará fechada.

Port Knocking

O port knocking pode ser utilizado como um segredo em uma estrutura de firewall, para que assim, o administrador possa liberar o acesso remoto ao servidor. Deste modo, o cliente deverá enviar uma sequência de pacotes para um determinado número de portas com um limite de tempo pré-configurado. Após o envio dos pacotes, o acesso será liberado ao IP de origem. Uma opção muito interessante que pode ser utilizada é a possibilidade de limitar o tempo de acesso para essa conexão.

Para exemplificar o funcionamento do Port Knocking, será criado um cenário utilizando regras do iptables para exemplificar a utilização da técnica de port knocking. As regras podem ser inseridas diretamente no terminal, mas se a máquina for reiniciada, as regras serão apagadas. Para auxiliar na criação e administração dessas regras, aconselha-se criar um script em shell script.

As regras aqui propostas têm como finalidade apresentar o uso da técnica de port knocking. Nenhuma outra configuração será apresentada neste artigo.

A primeira linha que compõe o script é a “#!/bin/bash”, a qual indica o shell a ser utilizado para executar as regras. Sempre que um script for utilizado para efetuar qualquer tarefa no sistema, o shell a ser utilizado deverá ser indicado no início do script, como pode ser visto na Listagem 14.

Listagem 14. Indicando o shell que será utilizado para carregar as regras.

  #!/bin/bash 

Assim como em qualquer aplicação, o uso de variáveis é utilizado para facilitar a manutenção do script. A primeira variável, “v_CMD_IPTABLES”, guarda a localização do binário do comando iptables, retornada pelo comando “which”. Dessa forma, independente do local que este seja disponibilizado, o sistema poderá localizá-lo. A segunda variável, “v_REDE”, foi utilizada para armazenar a rede a qual será utilizada para liberar o acesso. E, por último, a variável “v_IP_LIBERADO”, onde é armazenado o IP do host do administrador, o qual não irá passar pela regra criada. Observa-se na Listagem 15 a criação das variáveis.

Listagem 15. Criando as variáveis utilizadas.

  v_CMD_IPTABLES=$(which iptables);
  v_REDE="192.168.30.0/29";
  v_IP_LIBERADO="192.168.30.2" 

Prosseguindo na configuração do firewall, devem-se zerar quaisquer regras existentes. Dessa forma, o sistema não correrá o risco de executar regras que não estejam previstas. Para esse fim, utilizam-se os parâmetros “-F” (de flush) para limpar as regras, “-X” para eliminar as chains extras existentes (veja a Nota DevMan 3), e o “-Z” para zerar todos os contadores, observe na Listagem 16.

Nota DevMan 3. Chain

São locais onde as regras do firewall definidas pelo usuário são armazenadas para operação do firewall. Existem diferentes tipos de chains: os embutidos (como as chains INPUT, OUTPUT e FORWARD) e os criados pelo usuário. Os nomes das chains embutidos devem ser especificados sempre em maiúsculas (note que os nomes das chains são case sensitive, ou seja, o chain input é completamente diferente de INPUT).

Listagem 16. Limpando possíveis regras existentes.

  $v_CMD_IPTABLES -F
  $v_CMD_IPTABLES -X
  $v_CMD_IPTABLES -Z 

Sempre que um firewall é criado uma política padrão deverá ser criada. Pode-se citar duas situações, uma política onde tudo é permitido, exceto o que é expressamente proibido. Nessa forma, a chain INPUT é responsável pelos dados de entrada no firewall, OUTPUT é responsável pelos dados de saída do firewall e FORWARD manipula os dados que passam pelo firewall que receberam seu alvo como ACCEPT. Posteriormente deverão ser criadas regras de exceção. Outra forma é criar uma política restritiva, bloqueando todo o tráfego inserindo o alvo DROP para todas as três chains e, assim, liberar somente o que for necessário. No exemplo utilizado neste artigo será adotada a segunda opção, configurando as três chains como DROP (Listagem 17).

Listagem 17. Definindo a Política Padrão do Firewall.

  $v_CMD_IPTABLES -P OUTPUT DROP
  $v_CMD_IPTABLES -P INPUT DROP
  $v_CMD_IPTABLES -P FORWARD DROP 

Na regra seguinte do firewall, serão verificadas as requisições de entrada (pode-se observar que é usada a chain INPUT), quando chegar um pacote de nova conexão (-m state NEW) vindo da interface de rede interna (-i eth0) com destino à porta 42129 (--dport 42129), o parâmetro (-m recent) indica que o módulo recent será ativado podendo assim analisar as tabelas criadas. Caso não exista a tabela, a mesma será criada com o nome sshlimita (--name sshlimita) e irá retornar para a tabela INPUT analisando as próximas regras (-j RETURN). Observa-se um exemplo da regra na Listagem 18.

Listagem 18. Verificando estado da nova conexão.

  $v_CMD_IPTABLES -A INPUT -p tcp --dport 42129 -i eth0 -m state --state NEW –m recent --set --name sshlimita -j RETURN 

A próxima regra irá verificar as requisições de entrada (-A INPUT). Quando chegar um pacote de nova conexão (-m state NEW) vindo da interface de rede interna (-i eth0) com destino à porta 42129 tcp (-p tcp --dport 42129), o parâmetro (-m recent) indica que o módulo recent será ativado e irá verificar (--rcheck) se na tabela sshlimita (--name sshlimita) existe a entrada do IP de origem. Se a resposta for verdadeira, o módulo irá verificar se este tem três entradas (--hitcount 3) em menos de dois minutos (--seconds 120), caso contrário, o firewall irá descartá-la. Caso a resposta seja positiva, para fins de auditoria, o firewall irá adicionar uma entrada de nome “SSHLimitaConn” no arquivo de log de mensagens do kernel, e o administrador poderá dessa forma acompanhar os registros nos arquivos de log. O syslog é uma das ferramentas disponíveis no GNU/Linux que podem ser utilizadas para auxiliar a armazenagem de logs e auditoria dos mesmos. Sua configuração pode ser encontrada em /etc/syslog.conf. Um exemplo da segunda regra do iptables pode ser observado na Listagem 19.

Listagem 19. Logando tentativas de Brute Force.

  $v_CMD_IPTABLES -A INPUT -p tcp --dport 42129 -i eth0 -m state --state NEW -m recent --name sshlimita --rchek --seconds 120 --hitcount 3 -j LOG --log-prefix "SSHLimitaConn: " 

A terceira regra verifica as requisições na tabela de entrada (-A INPUT) quando chegar um pacote de nova conexão (-m state NEW) vindo da interface da rede interna (-i eth0) com direção à porta 42129 tcp (-p tcp --dport 42129). O módulo recent será ativado (-m recent) e será verificado (--rcheck) se na tabela sshlimita (--name sshlimita) existe a entrada do IP de origem. Caso a resposta seja positiva, será verificado se tem três entradas (--hitcount 3) em um intervalo menor que dois minutos (--seconds 120). Se a resposta for positiva, a tentativa de conexão será negada (-j DROP), conforme visto na Listagem 20.

Listagem 20. Bloqueando tentativas de Brute Force.

  $v_CMD_IPTABLES-A INPUT -p tcp --dport 42129 -i eth0 -m state --state NEW -m recent --name sshlimita --rcheck --seconds 120 --hitcount 3 -j DROP 

O administrador poderá optar por liberar sua máquina do segredo aplicado nas regras. Essa opção pode ser feita por IP ou até mesmo por rede. No exemplo aplicado no artigo foi liberado o IP do administrador, aqui representado pela variável “$v_IP_LIBERADO”. Caso o administrador venha a trocar de endereço IP, basta que o mesmo altere o valor atribuído à variável no início do script. A linha inserida no script pode ser observada na Listagem 21.

Listagem 21. Liberando acesso para máquina do Administrador.

  $v_CMD_IPTABLES -A INPUT -p tcp -s $v_IP_LIBERADO --dport 42129 -j ACCEPT 

As conexões com o firewall devem ser estabilizadas a fim de manter a conectividade entre cliente e servidor. Para que isso ocorra, uma regra é adicionada estabilizando as conexões aceitas pelo firewall. Um exemplo pode ser observado na Listagem 22.

Listagem 22. Estabilizando as conexões.

  $v_CMD_IPTABLES -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT 

Na Listagem 23 observam-se três conjuntos de regras. Na primeira linha de cada um dos conjuntos utiliza-se o parâmetro “iptables –N”, onde cada nova chain será inserida com o nome “PORTKNOCK-FASE2”, “PORTKNOCK-FASE3” e “PORTKNOCK-FASE4”, respectivamente. Dessa forma, o administrador pode acompanhar e organizar todo o processo de acesso ao servidor, utilizando as portas posteriormente definidas no firewall. Na segunda e terceira linhas, faz-se a alteração das fases, removendo a fase atual e indicando a próxima fase. Na quarta linha é efetuado um log desse processo. Na última listagem desta matéria é apresentado um registro do arquivo de log dessas regras, facilitando assim o entendimento da alteração entre as fases.

Listagem 23. Criando as fases do PortKnocking.

  $v_CMD_IPTABLES -N PORTKNOCKING-FASE2
  $v_CMD_IPTABLES -A PORTKNOCKING-FASE2 -m recent --name FASE1 --remove
  $v_CMD_IPTABLES -A PORTKNOCKING-FASE2 -m recent --name FASE2 --set
  $v_CMD_IPTABLES -A PORTKNOCKING-FASE2 -j LOG --log-prefix "INTO FASE2: "
   
  $v_CMD_IPTABLES -N PORTKNOCKING-FASE3
  $v_CMD_IPTABLES -A PORTKNOCKING-FASE3 -m recent --name FASE2 --remove
  $v_CMD_IPTABLES -A PORTKNOCKING-FASE3 -m recent --name FASE3 --set
  $v_CMD_IPTABLES -A PORTKNOCKING-FASE3 -j LOG --log-prefix "INTO FASE3: "
   
  $v_CMD_IPTABLES -N PORTKNOCKING-FASE4
  $v_CMD_IPTABLES -A PORTKNOCKING-FASE4 -m recent --name FASE3 --remove
  $v_CMD_IPTABLES -A PORTKNOCKING-FASE4 -m recent --name FASE4 --set
  $v_CMD_IPTABLES -A PORTKNOCKING-FASE4 -j LOG --log-prefix "INTO FASE4: " 

Quando o pacote passa por todas as regras, o módulo recent fará um update na chain retornando para a FASE1, responsável por analisar a primeira porta da sequência escolhida. Um exemplo da regra pode ser visto na Listagem 24.

Listagem 24. Atualizando as fases do PortKnocking.

  $v_CMD_IPTABLES -A INPUT -m recent --update --name FASE1 

O próximo passo da criação das regras do firewall será determinar quais portas serão controladas e também qual será o intervalo, em segundos, que cada uma das fases irá aguardar até que a próxima porta seja indicada para acertar o segredo. No cenário proposto, será utilizado um intervalo de 15 segundos entre cada fase, e caso o tempo expire, o processo deverá ser iniciado novamente. Essas regras podem ser observadas na Listagem 25.

Listagem 25. Conferindo a sequência de portas do PortKnocking.

  $v_CMD_IPTABLES -A INPUT -p tcp --dport 12345 -m recent --set --name FASE1
  $v_CMD_IPTABLES -A INPUT -p tcp --dport 51234 -m recent --rcheck --seconds 15 --name FASE1 -j INTO-FASE2
  $v_CMD_IPTABLES -A INPUT -p tcp --dport 45123 -m recent --rcheck --seconds 15 --name FASE2 -j INTO-FASE3
  $v_CMD_IPTABLES -A INPUT -p tcp --dport 34512 -m recent --rcheck --seconds 15 --name FASE3 -j INTO-FASE4 

Dica DevMan: Não é aconselhável utilizar portas em sequências crescentes ou decrescentes, assim como utilizar portas próximas, como: 400, 410, 420 e 430. O ideal é intercalar os valores evitando que algum portscan consiga identificar a sequência.

A última fase da configuração do firewall será liberar a conexão com a porta 42129 (SSH) por um tempo de 1800 segundos (30 minutos) somente para pacotes vindos da rede armazenada na variável “v_REDE”. Decorrido esse tempo, o acesso será interrompido para o IP em questão, sendo necessário um novo pedido de conexão. É importante destacar que, mesmo que o usuário ainda esteja logado no sistema, a conexão será interrompida. Um exemplo desta regra pode ser visto na Listagem 26.

Listagem 26. Autorizando conexões.

  $v_CMD_IPTABLES -A INPUT -p tcp -s $v_REDE --dport 42129 -m recent --rcheck --seconds 1800 --name FASE4 -j ACCEPT 

A última regra aplicada ao firewall irá atuar nas conexões que não passaram pelo segredo. Desse modo, todas as requisições feitas na porta 42129 serão negadas por essa regra. Aqui também se encerram as configurações no servidor. Pode-se observar um exemplo na Listagem 27.

Listagem 27. Recusando todas as demais requisições na porta 42129.

  $v_CMD_IPTABLES -A INPUT -p tcp --dport 42129 -j DROP 

Para que se possa ter certeza de que a porta do servidor destinado ao serviço de SSH está fechada para novas conexões, pode-se executar uma consulta no servidor utilizando um sniffer de rede para capturar todas as portas abertas. Nmap é um software livre que realiza um escaneamento de portas. Ele é utilizado para avaliar a segurança dos computadores e para descobrir serviços ou servidores em uma rede de computadores. Analisando o resultado da varredura feita com o Nmap, pode-se verificar que a porta 42129 está configurada para receber conexões e está sendo filtrada. Observa-se um exemplo simples de uso do Nmap na Listagem 28.

Listagem 28. Comando sugerido para testes.

  $ nmap 192.168.30.3 -p 42129
   
  Starting Nmap 5.00 ( http://nmap.org ) at 2010-07-10 11:49 BRT
  Interesting ports on 192.168.30.3:
  PORT      STATE    SERVICE
  42129/tcp filtered unknown 

Efetuando os testes

Para que se possa efetuar os testes de acesso no servidor, será empregado o aplicativo Knock, utilizado para efetuar conexões com intervalos pré-determinados, enviando pacotes às portas configuradas no intervalo de tempo escolhido. Para este teste foi utilizado um host Ubuntu como cliente e um servidor GNU/Linux Debian Lenny.

Para isso, o primeiro passo é observar se o aplicativo knock está disponível no host Ubuntu. Para conferir sua instalação, pode-se utilizar o comando “dpgk –l | grep knock”. Se nada for retornado, usa-se o comando “aptitude install knock” para instalar a aplicação.

Para facilitar o teste, será criado um pequeno script em shell. O script deverá iniciar indicando o shell que será utilizado, neste caso, “#!/bin/bash”. Na sequência do script, o aplicativo knock recebe como parâmetro o IP do servidor e as portas do segredo na sequência em que foram definidas no firewall. Um intervalo de três segundos é adicionado com o uso do comando “sleep” e, logo em seguida, é solicitada a conexão via ssh. Para executar a aplicação deve-se atribuir a permissão de execução com o comando chmod. O código do script é apresentado na Listagem 29.

Listagem 29. Script sugerido para testes.

  #!/bin/bash
  knock 192.168.30.3 12345:tcp 51234:tcp 45123:tcp 34512:tcp
  sleep 3
  ssh –p 42129 reisfa@192.168.30.3 

Durante a configuração do firewall no servidor, algumas regras foram utilizadas para registros de log. Esses registros podem ser acompanhados no arquivo /var/log/messages. Nota-se em destaque na Listagem 30 a origem do pacote em “SRC=192.168.30.2”, ou seja, onde foi executado o aplicativo Knock, o cliente Ubuntu. Em “DST=192.168.30.3” observa-se o IP de destino do pacote, no exemplo o IP do servidor Debian. O “DPT=51234” é a primeira porta configurada no servidor. A opção SYN (synchronize) indica uma solicitação para que uma conexão seja estabelecida. As três linhas do log coletadas e apresentadas indicam as portas escolhidas no servidor, onde pode ser observada a diretiva DPT (51234, 45123, 34512), fechando assim o ciclo completo para disponibilizar a conexão.

Listagem 30. Log de mensagem do kernel /var/log/messages.

  Jul  6 02:11:13 debian kernel: [ 1824.496437] PORTKNOCK-FASE2: IN=eth0 OUT= MAC=08:00:27:54:e9:c6:00:1c:c0:1c:e4:96:08:00 SRC=192.168.30.2 DST=192.168.30.3 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=18774 DF PROTO=TCP SPT=49872 DPT=51234 WINDOW=5840 RES=0x00 SYN URGP=0 
   
  Jul  6 02:11:13 debian kernel: [ 1824.496437] PORTKNOCK-FASEE3: IN=eth0 OUT= MAC=08:00:27:54:e9:c6:00:1c:c0:1c:e4:96:08:00 SRC=192.168.30.2 DST=192.168.30.3 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=3402 DF PROTO=TCP SPT=57478 DPT=45123 WINDOW=5840 RES=0x00 SYN URGP=0 
   
  Jul  6 02:11:13 debian kernel: [ 1824.496437] PORTKNOCK-FASE4: IN=eth0 OUT= MAC=08:00:27:54:e9:c6:00:1c:c0:1c:e4:96:08:00 SRC=192.168.30.2 DST=192.168.30.3 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=22711 DF PROTO=TCP SPT=49287 DPT=34512 WINDOW=5840 RES=0x00 SYN URGP=0 

Conclusão

Neste artigo foram apresentadas técnicas de conexões remotas, destacando algumas de suas vulnerabilidades, como no exemplo de uso do telnet, onde todos os seus dados trafegam em texto puro, sem criptografia, sendo assim facilmente capturados por um sniffer. Como substituto ao uso do telnet, foi apresentado o SSH (Secure Shell), e mesmo com toda segurança inserida no protocolo devido ao uso da criptografia, técnicas de hardening foram utilizadas para aumentar ainda mais seu nível de confiabilidade e segurança.

Manter uma aplicação segura em um servidor é uma tarefa importante e muitas vezes negligenciada pelos administradores de redes. Com o uso de firewalls, é possível criar uma barreira entre o cliente malicioso e o servidor. E com o módulo recent do iptables foi possível combinar regras e apresentar a técnica conhecida como port knocking, criando um segredo para que a conexão fosse liberada.

Um cracker poderá até usar um scanner para identificar se há portas abertas no servidor, porém, para que obtenha o acesso, deverá saber a combinação das portas, o que irá dificultar que a tentativa de invasão obtenha sucesso. No entanto, mesmo adotando esses recursos, recomenda-se avaliar os logs com frequência, identificando assim possíveis varreduras em busca de falhas na configuração do firewall. Além disso, aconselha-se o uso de um IDS (Snort) e um IPS (Guardian) junto com o firewall para aumentar a proteção do perímetro.

Links

Site sobre o iptables
www.netfilter.org

Debian Administration
www.debian-administration.org

Site telnet
www.telnet.org

Site SSH
www.openssh.com