Depois de alguns meses ausente (envolvido em outros projetos e por falta de tempo), resolvi tratar um assunto que julgo importante, tenho visto muita discussão e também para deixar documentado – assim, eu mesmo não “patinarei” conforme atualizar o kernel de alguns firewalls (risos).

Alguns protocolos, como FTP e SIP, apresentam uma implementação um pouco mais complexa, separando o fluxo de controle do fluxo de dados.

No caso do protocolo FTP, por exemplo, a primeira conexão, na porta TCP/21 (ftp-control), é utilizada para fins de controle (comandos para o servidor). No entanto, para a troca de dados (ftp-data), na listagem de conteúdo (ls) ou transferência de arquivos (put ou get), o servidor negocia novos sockets dinamicamente para este propósito. Para complicar um pouco mais, o ftp-data ainda pode operar em modo ativo ou passivo.

No modo ativo, a conexão ftp-data é entrante – ou seja, do servidor para os clientes. Neste caso, o servidor conectará aos clientes e utilizará o socket tcp/20 como porta de ORIGEM. Em termos de firewall, fica simples tratar o fluxo porque a porta de origem será sempre a tcp/20. Mas, por ser uma conexão entrante, costuma ser evitado.

Imagem extraída de https://pplware.sapo.pt/

Outra alternativa para o ftp-data é a utilização do modo passivo. Neste caso, a conexão se torna passante – ou seja, do servidor aos clientes (fluxo de saída). Por um lado é considerado mais seguro, mas, por outro, impõe uma dificuldade maior porque trabalha com uma alocação de portas dinamicamente (não privilegiadas).

Imagem extraída de https://pplware.sapo.pt/

É possível tratar estes fluxos manualmente, porém, além de ineficiente, é fácil perceber que será inseguro:

– Modo ATIVO

iptables -A FORWARD -s $client -p tcp --dport 21 --syn -j ACCEPT
iptables -A FORWARD -d $client -p tcp --sport 20 -j ACCEPT

– MODO PASSIVO

iptables -A FORWARD -s $client -p tcp --dport 21 --syn -j ACCEPT
iptables -A FORWARD -s $client -p tcp --dport 1024: -j ACCEPT

No primeiro caso, teríamos que permitir qualquer conexão entrante (limitada apenas pela porta), pois seria inviável tratar cada servidor na Internet. Logo, qualquer conexão com porta de origem tcp/20 estaria autorizada. Por outro lado, no modo passivo, com a abertura de todas as portas não privilegiadas, o acesso liberado extrapola uma “simples” conexão de FTP. Pois é, não é uma questão muito simples, mas o conntrack controla todas estas questões de forma automática (podemos interferir)!

Se conceitualmente parece complexo, imagine a implementação interna! 😉

É aí que entra o papel dos helpers

Para lidar com esta situação, o netfilter provê uma infraestrutura modular conhecida como Connection Tracking helpers, oferecendo toda assistência necessária para o mapeamento destes protocolos. O tratamento das conexões secundárias (reincidentes) é feito através de uma tabela separada conhecida como expected (para lidar com o “tráfego esperado”) e mantido em memória por um intervalo de tempo.

Além de melhorar a eficiência e a facilidade de configuração, alguns helpers oferecem um nível segurança superior porque são capazes de “prever” os envolvidos na conexão (tanto origem como destino). No caso do FTP, por exemplo, o sistema deverá prever quais serão as conexões esperadas para cada comando da sessão de controle (tcp/21).

É claro que alguns helpers podem ser “menos seguros”.
Confiram os principais módulos disponíveis, bem como seu funcionamento:

Secure use of iptables and connection tracking helpers

– Podemos listar os módulos suportados pelo kernel com o comando:

for i in $(find /lib/modules/$(uname -r) -name ??_nat_* -print | grep -i netfilter | \
      sed 's/.*\///' | sed 's/\..*\.gz$//; s/\.ko$//'); do echo $i ; done

Por exemplo:

root@firewall:~# for i in $(find /lib/modules/$(uname -r) -name ??_nat_* -print | grep -i netfilter | sed 's/.*\///' | sed 's/\..*\.gz$//; s/\.ko$//'); do echo $i ; done
nf_nat_snmp_basic
nf_nat_pptp
nf_nat_h323
nf_nat_ipv4
nf_nat_proto_gre
nf_nat_proto_sctp
nf_nat_irc
nf_nat_proto_udplite
nf_nat_proto_dccp
nf_nat_amanda
nf_nat_sip
nf_nat_ftp
nf_nat_tftp                                                                                                                                          
nf_nat_ipv6                                                                                                                                          
root@firewall:~#

– É possível confirmar quais módulos estão carregados com o comando:

lsmod | grep "_conntrack_\|_nat_"

Na filtragem de pacotes, o netfilter identificará as conexões esperadas (reincidentes) através do estado RELATED. É por esta razão que é comum utilizar regras como esta:

– modo prestes a se tornar depreciado:

...
iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT

– ou (padrão atual e recomendado):

...
iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

Para o fluxo principal (conexão única), o conntrack realiza perfeitamente o mapeamento das conexões na Tabela de Estados – algo que ocorrerá com o fluxo de ftp-control. Estas conexões são facilmente identificadas e mapeadas como NEW (na primeira ocorrência) e ESTABLISHED (na confirmação de resposta).

Graças aos helpers é possível tratar apenas as conexões de controle e deixar que o netfilter cuide do tráfego esperado em seguida.

É por esta razão que o tráfego de ftp pode ser autorizado com simples regras, como:

...
iptables -A FORWARD -s $client -o $ifnet-p udp --dport 53 -j ACCEPT
iptables -A FORWARD -s $client -o $ifnet -p tcp --dport 21 -j ACCEPT
iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

Na Tabela de Estados, o “retorno” será mapeado como ESTABLISHED e as “conexões esperadas” como RELATED. Portanto, o administrador não precisa tratar o ftp-data manualmente. É evidente que o funcionamento depende da presença dos módulos nf_conntrack_ftp e nf_nat_ftp.

Caso os módulos não estejam em memória, carregue com o comand modprobe.

modprobe nf_nat_ftp

Não, eu não esqueci do módulo conntrack (risos). Ao carregar o módulo nf_nat_ftp, o sistema carregará nf_conntrack_ftp como dependência automática.

Até aqui, talvez vocês não vejam muita novidade…

Porém, a partir do kernel 4.7 alguns critérios de segurança foram adotados.

Em versṍes anteriores, bastava requisitar acesso a porta tcp/21 (por exemplo) para o helper entrar em ação automaticamente.

O problema é que isto se aplica a qualquer módulo em memória (algo que costuma ser feito em diferentes scripts de firewall) – o mesmo ocorrerá com o SIP ao receber conexão na porta udp/5060, por exemplo. Logo, o processamento automático do helper passou a ser encarado como uma fragilidade passível de ser explorada (abrindo portas de forma indevida).

Já faz algum tempo que o kernel disponibiliza um arquivo de controle (em /proc) para desabilitar o processamento automático do helper.

cat /proc/sys/net/netfilter/nf_conntrack_helper

Anteriormente, por padrão, o conteúdo de nf_conntrack_helper era “1“. A partir da versão de kernel 4.7, o valor padrão foi alterado para “0” – desabilitando o processamento automático.

Parece pouco, mas certamente lhe tomará um belo tempo caso você desconheça esta alteração e adote configuração de firewall como a demonstrada anteriormente (não funcionará). O objetivo, segundo os desenvolvedores, foi reforçar a segurança do sistema.

– A primeira alternativa é reativar o processamento automático (volta ao padrão anterior):

echo 1 > /proc/sys/net/netfilter/nf_conntrack_helper

– Outra alternativa, mais recomendada, é ativar o processamento manualmente:

iptables -t raw -A PREROUTING -p tcp --dport 21 -o $ifnet -j CT --helper ftp

No exemplo anterior, é possível manter nf_conntrack_helper como ‘0’ e assegurar que o único helper processado será do protocolo FTP e na porta 21. A utilização do alvo CT pode ser útil para casos em que o servidor de FTP atende em outra porta (não padrão).

Em ambientes corporativos o ideal é tratar cada helper manualmente, conforme demonstrado na regra com alvo CT.

Para navegação (saída de Internet), esta configuração é suficiente e segura.

Porém, caso o administrador disponibilize o acesso remoto aos servidores da rede, é possível reforçar os critérios de acesso para conexões mapeadas como RELATED.

iptables -t raw -A PREROUTING -p tcp --dport 2121 -d $server -j CT --helper ftp

iptables -A FORWARD -m conntrack --ctstate RELATED -m helper --helper ftp \
       -d $server -p tcp --dport 1024: -j ACCEPT

Assim podemos restringir a utilização do helper de acordo com a topologia da rede.

Espero que vocês gostem do artigo.
Até o próximo!