Port knocking com iptables

Last update: 3/5/2010

Para quem é novo nessa história de Firewall, um Firewall é responsável por criar uma barreira na comunicação de entrada ou saída de rede em um computador. Tornando a explicação um pouco mais simples: é aquilo que impede que outras pessoas entrem através da internet em sua máquina para bagunçar suas coisas.

Este artigo é voltado para máquinas com Linux e Iptables, você deve encontrar pela internet outros métodos para criar port knocking ou até configurar um Firewall com outras ferramentas, este artigo cobre este sistema operacional e essa ferramenta por serem muito comuns, e em praticamente todas as distribuições Linux você pode encontrar o Iptables muitas vezes já instalado (caso do Ubuntu). Neste artigo não cobrirei a instalação do Iptables em outras distribuições pois em alguns casos basta um apk add iptables para instalar a aplicação e executar os passos apresentados aqui (no Alpine Linux).

Se você não sabe o que é uma porta (estou falando de portas de redes de computadores), você deve começar por aquiopen in new window e aí voltar para este artigo. Vale também dar uma olhada na lista de portasopen in new window, isso ajuda a identificar quais portas são utilizadas pelos serviços que você usa.

Entendendo a técnica Port Knocking

Normalmente um Firewall define as portas abertas ou fechadas mas com Iptables você pode fazer muito mais, desde criar redirecionamentos até controlar a quantidade de conexões por segundo.

Como os números das portas seguem convenções (exemplo 22 para SSH) é comum trocar o número da porta do serviço para outra que não tenha nada a ver com o serviço em questão, porém com uma simples varredura de portas (port scan) você pode encontrar a porta novamente e de nada adiantou seu trabalho. A segunda alternativa costuma ser criar uma regra no Firewall para liberar a porta apenas para um IP mas isso também não ajuda muito quando você está utilizando uma conexão ADSL/3G que força você a trocar constantemente de IP.

Para resolver este problema você pode utilizar o Port Knocking, que consiste em criar uma outra porta (ou mais portas), na qual você precisa conectar na sequência antes de tentar uma conexão na porta que seu serviço está escutando.

Configurando o básico no Iptables

Se você já possui um conjunto de regras para seu Firewall com Iptables passe para a seção seguinte. Se você não possui vai a dica: crie um arquivo firewall.sh e dê permissão de execução chmod a+x firewall.sh, neste arquivo você deve escrever todas as regras abaixo, e quando precisar recarregar o Firewall basta executar este arquivo que todas as regras serão aplicadas. Não esqueça que você precisa ter privilégios de root.

Antes de sair por aí reconfigurando suas máquinas, lembre-se que o bloqueio das portas pode lhe deixar de fora da máquina (sem acesso SSH), portanto tenha sempre um plano B durante seus testes.

# Limpando todas as regras existentes, isso também irá liberar todas as portas
# Caso faça alguma bobagem e queira remover todas as regras, execute as próximas linhas
iptables -F
iptables -X
iptables -Z
iptables -t nat -F
iptables -t nat -X
iptables -t mangle -F
iptables -t mangle -X
iptables -P INPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -P OUTPUT ACCEPT
# Fim da limpeza

# Por padrão, um firewall deve bloquear tudo, então utilizamos
iptables -P INPUT DROP
iptables -P FORWARD DROP
# Descomente abaixo se deseja bloquear as conexões de saída também
#iptables -P OUTPUT DROP

# Estas regras liberam a conexão local (localhost/127.0.0.1)
iptables -A INPUT -i lo -s 0/0 -d 0/0 -j ACCEPT
iptables -A OUTPUT -o lo -s 0/0 -d 0/0 -j ACCEPT

# Se você quiser liberar todas as conexões para um IP específico descomente
# a linha abaixo. Note que TODAS as portas serão liberadas para o IP!
#iptables -A INPUT -s 000.000.000.000 -j ACCEPT

# Caso tenha alguns serviços que quer liberar para qualquer IP
# Libere as portas 53 UDP/TCP (DNS), 80 TCP (HTTP) e 443 TCP (HTTPS)
iptables -A INPUT -p tcp -m multiport --destination-ports 53,80,443 -j ACCEPT
iptables -A INPUT -p udp -m multiport --destination-ports 53 -j ACCEPT

# Vale também criar uma regra para que não "derrube" conexões já estabelecidas
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

Regras do Port Knocking

Se você executou o firewall.sh com o conteúdo do REF{fbasic} já deve ter notado que nenhuma nova conexão de SSH na porta 22 é possível, ocorre timeout, e até os pings são ignorados. Com a regra de manter as conexões já estabelecidas você deve continuar com seu acesso SSH.

Para nosso exemplo liberaremos a porta 22 por alguns segundos após você conectar por TCP uma sequência de portas como 1000, 3000 e 2000 (é importante não utilizar portas sequenciais pois um port scan normalmente segue uma ordem que poderia realizar as conexões necessárias para liberar a porta 22 sem você querer).

Adicione ao final do seu arquivo de configurações de Firewall o seguinte código.

# Obs.: Uma Chain é uma lista de regras de filtragem dentro do iptables
# São 3 passos de conexão, portanto criamos 2 chains
iptables -N AGUARDANDO-PASSO2
iptables -N AGUARDANDO-PASSO3

# De acordo com a chain acessada, define uma flag para demonstrar o passo atingido
iptables -A AGUARDANDO-PASSO2 -m recent --name PASSO2 --set
iptables -A AGUARDANDO-PASSO3 -m recent --name PASSO3 --set

# Para cada porta na ordem 1000 3000 2000 encaminha o pacote para a chain respectiva
iptables -A INPUT -p tcp --syn --dport 1000 -m recent --set --name PASSO1
iptables -A INPUT -p tcp --syn --dport 3000 -m recent --rcheck --seconds 3 \
     --name PASSO1 -j AGUARDANDO-PASSO2
iptables -A INPUT -p tcp --syn --dport 2000 -m recent --rcheck --seconds 3 \
     --name PASSO2 -j AGUARDANDO-PASSO3

# Esta é a regra final, que habilita para todoos os ips (-s 0/0) a conexão na porta
# 22 por 3 segundos
iptables -A INPUT -p tcp -s 0/0 --dport 22 -m recent --rcheck --seconds 3 \
     --name PASSO3 -j ACCEPT

Note que a validade de cada flag é de 3 segundos, portanto você não pode demorar muito para tentar a conexão em cada porta.

Realizando as chamadas TCP para liberar a porta

A liberação da porta pode ser feita através do comando telnet mas você precisa ser muito ágil para tentar realizar todas as conexões com 3 segundos entre cada chamada. Para resolver isso você pode utilizar o comando nc no Linux. Outra dica é criar um script com a sequência de liberação.

nc -w 1 <hostdestino> 1000 # Conecta no host destino e aguarda 1 segundo para desconectar
nc -w 1 <hostdestino> 3000
nc -w 1 <hostdestino> 2000
ssh <usuario>@<hostdestino>