PROJETO DE IMPLEMENTAÇÃO DE UM SERVIDOR FIREWALL LIVRE UTILIZANDO IPTABLES 1 . Introdução O IPTABLES é um software usado para analisar os pacotes que passam entre redes. A partir desse princípio podemos aceitar, rejeitar ou descartar esses pacotes. Devidamente implementado, é capaz de prover segurança e otimizar o uso das redes corporativas. Através de um método de controle de acesso baseado em registros em tabelas presentes KERNEL, um FIREWALL pode monitorar e registrar qualquer informação que está sendo transmitida entre as redes locais e externas em tempo real. No Linux, a filtragem de pacotes é implementada no kernel, como módulo ou compilado diretamente através dos módulos do NETFILTER. 2 . Objetivo Este documento descreve os procedimentos para instalação e configuração de um servidor firewall IPTABLES no sistema operacional Debian GNU/Linux versão 3.0 testing. 3. IPTABLES 3.1 Opções a serem habilitadas no Kernel 2.6.6 Ao ser exibida a tela de opções do kernel, habilite as seguintes opções: ---> Device Drivers --> Networking Support ---> [ * ] Networking Support ---> Networking Options [ * ] Network packet filtering (replaces ipchains) ---> Após habilitar as opções do netfilter correspondentes no kernel, compile-o. 3.2 Instalando o IPTABLES Para instalar o IPTABLES, execute o seguinte comando: # apt-get install iptables 3.3 MANIPULANDO REGRAS COM O IPTABLES O iptables nos permite adicionar, listar e remover regras previamente implementadas através de parâmetros que serão listados a seguir: -A : Adiciona uma regra -D : Remove uma regra -F : Remove todas as regras em uma chain ou em todas as chains -L : Lista todas as regras -P -N : : Define uma política padrão para uma determinada chain Define uma nova chain 3.3.1 Adicionando, visualizando e removendo regras Para adicionar uma regra no kernel utilizando o iptables, basta executar o comando iptables juntamente com o parâmetro -A, para remover use o parâmetro -D. Exemplo: # iptables -A INPUT -p icmp -d 127.0.0.1 -j DROP Explicação: Pacotes do tipo ICMP (ping) que são direcionados para o endereço de loopback (127.0.0.1) são descartados. Para testar, tente executar o comando “ping 127.0.0.1” antes e depois de aplicar a regra. Para remover a regra adicionada anteriormente, execute o mesmo comando, substituindo o parâmetro -A, pelo parâmetro -D: # iptables -D INPUT -p icmp -d 127.0.0.1 -j DROP Para listar as regras já adicionadas, utilize o parâmetro -L, como a seguir: # iptables -L Para listar as regras adicionadas na tabela de NAT (Network Address Translation), utilize o parâmetro -L seguido pelo parâmetro -t nat, como a seguir: # iptables -L -t nat Obs.: Discutiremos NAT mais adiante, nesse mesmo documento. Ainda podemos remover regras utilizando seu número de acordo com a ordem na qual foi cadastrada: # iptables -D OUTPUT 1 Esse comando irá remover a primeira regra na chain INPUT. Para remover regras implementadas na tabela de NAT, utilize o parâmetro -t nat: # iptables -D PREROUTING 1 -t nat Obs.: Para obter a ajuda completa do comando iptables, utilize as páginas de manual através do comando man ou execute o comando iptables com o parâmetro -h. Ainda é possível criar chains personalizadas. Por exemplo: # iptables -N filtro Acima é criada uma chain, denominada filtro. # iptables -A filtro -j LOG # iptables -A filtro -j DROP Agora temos uma chain personalizada demoninada filtro que antes de descartar um pacote, efetua log do mesmo. 3.4 CHAINs Uma chain é uma lista de regras. Cada regra diz: “se o cabeçalho do pacote se parece com isso, então aqui está o que deve ser feito com o pacote”. Se a regra não associa-se com o pacote, então a próxima regra na chain é consultada. Se não há mais regras a consultar, o kernel analisa a política da chain para decidir o que fazer. 1. Quando o pacote chega (pela placa Ethernet, por exemplo) o kernel analisa o destino do pacote: isso é chamado roteamento (routing). 2. Se ele é destinado a própria máquina, o pacote desce no diagrama, indo para a chain INPUT. Se ele passar pela chain INPUT, então a máquina recebe o pacote. 3. Depois, se o kernel não tem suporte a forwarding, ou não sabe como repassar (forward) o pacote, este é descartado. Se há suporte a forwarding e o pacote é destinado a outra interface de rede (se você possui outra), o pacote vai para a chain FORWARD. Se ele for aceito (ACCEPT), ele será enviado. 4. Finalmente, um programa rodando na máquina firewall pode enviar pacotes. Esses pacotes passam pela chain OUTPUT imediatamente: se ela aceitar o pacote, ele continua seu caminho, caso contrário ele é descartado. Existem duas ações básicas que podemos fazer com os pacotes destinados a uma determinada chain: ACCEPT e DROP. ACCEPT deixa o pacote passar entre destino e origem, DROP descarta o pacote como se nunca o tivesse recebido. 3.4.1 INPUT A chain INPUT é empregada na entrada de pacotes que estão destinados a um determinado host. Abaixo exemplos do que se pode fazer na chain INPUT. 1 Exemplo: # iptables -A INPUT -p icmp -s 192.168.1.50 -d 192.168.1.1 -j DROP Explicação: Pacotes do tipo ICMP (Ping) cuja origem é o endereço IP 192.168.1.50 e o destino é 192.168.1.1, serão descartados na entrada (INPUT) sem que a origem receba qualquer notificação. 2 Exemplo: # iptables -A INPUT -p icmp -s 192.168.1.50 -d 192.168.1.1 -j ACCEPT # iptables -A INPUT -p icmp -d 192.168.1.1 -j DROP Explicação: Qualquer pacote cuja origem não é 192.168.1.50 que forem direcionados para o endereço 192.168.1.1, serão descartados na entrada (INPUT). 3 Exemplo: # iptables -A INPUT -p tcp –dport 80 -j ACCEPT # iptables -A INPUT -p tcp -j DROP Explicação: A primeira linha diz: 'aceite todos os pacotes TCP destinados a porta 80 (http) dessa máquina'. A segunda linha diz 'descarte todos os pacotes TCP destinados a essa máquina'. Nesse caso eu estou permitindo a entrada de pacotes apenas na porta 80 TCP desse host e bloqueando outros pacotes para qualquer outra porta (que não seja 80). 4 Exemplo: # iptables -A INPUT -p udp -s 1.2.3.4 –dport 53 -j DROP Explicação: A regra bloqueia a entrada de pacotes UDP na porta 53 (DNS) vindos de um host cujo endereço IP é 1.2.3.4. 3.4.2 OUTPUT A chain OUTPUT é empregada na saída de pacotes da máquina local. Abaixo exemplos do que se pode fazer na chain OUTPUT. Exemplo: # iptables -A OUTPUT -p tcp –dport 23 -j DROP Explicação: Bloqueia a saída de pacotes TCP para a porta 23 (telnet) do host local. 3.4.3 FORWARD A chain FORWARD é empregada em um host intermediário (geralmente um firewall) que realiza o repasse de pacotes entre redes. Observer a ilustração: Rede interna 1 eth2 eth0 eth1 Rede interna 2 Firewall INTERNET pacotes No gráfico acima, o firewall tem a função de repassar (forwarding) os pacotes das redes internas para a internet e vice-versa. A chain FORWARD se aplica no repasse desses pacotes. Para habilitar o repasse de pacotes, não basta implementar regras na chain FORWARD, precisa-se habilitar o recurso no kernel: # echo “1” > /proc/sys/net/ipv4/ip_forward ou editando o arquivo /etc/sysctl.conf e adicionar a seguinte linha: net/ipv4/ip_forward=1 1 Exemplo: # iptables -A FORWARD -p all -s 192.168.1.0/24 -d 0/0 -j ACCEPT Explicação: Habilita o repasse de pacotes da rede 192.168.1.0/255.255.255.0 para outras redes, incluindo a internet. 2 Exemplo: # iptables -A FORWARD -p tcp -s 192.168.1.20 -d 200.181.132.137 –dport 80 -j DROP Explicação: Bloqueia o acesso ao endereço 200.181.132.137 (www.playboy.com.br) da origem cujo endereço IP é 192.168.1.20 descartando os pacotes. 3 Exemplo: # iptables -A FORWARD -p tcp –syn -m limit –limit 1/sec -j ACCEPT Explicação: a regra diz: “receba apenas um pacote TCP por segundo com o bit SYN ativado”. Essa regra caracteriza uma proteção contra o envio desenfreado de pacotes syn (SYNFLOOD) da sua rede interna para a internet e vice-versa. Nota: É importante ressaltar que todas as regras são manipuladas pelo KERNEL, e o método de leitura implementado é como uma fila. Observe, por exemplo, as seguintes regras: 1: # iptables -A INPUT -p icmp -d 192.168.1.1 -j DROP 2: # iptables -A INPUT -p icmp -s 192.168.1.50 -d 192.168.1.1 -j ACCEPT CHAIN TIPO DE PACOTE ORIGEM DESTINO AÇÃO INPUT icmp 0.0.0.0 192.168.1.1 DROP INPUT icmp 192.168.1.50 192.168.1.1 ACCEPT Explicação: Se primeiro eu digo: “descarte pacotes de qualquer origem (0.0.0.0) que chegarem no destino 192.168.1.1”, e depois eu digo: “aceite apenas pacotes da origem 192.168.1.50 que chegarem no destino 192.168.1.1”, faço com que ambas as regras sejam aplicáveis a um pacote cujo endereço de destino é 192.168.1.1, portanto apenas a primeira regra será analisada e o pacote cujo endereço de origem é 192.168.1.50 e o endereço de destino é 192.168.1.1 também será descartado. A segunda regra seria aplicável apenas se adicionada antes da primeira. 3.5 NETWORK ADDRESS TRANSLATION – NAT Introdução: Realizar NAT, consiste em alterar o endereço ou porta de origem e o endereço ou porta de destino do pacote. Quando fazer NAT? • • • Para conectar uma rede de computadores à internet através de um único servidor conectado com endereço IP válido Para disponibilizar um número X de serviços na internet possuindo apenas um endereço IP válido Fazer proxy transparente, ou seja, fazer com que os pacotes que chegam no roteador padrão da rede (default gateway) sejam redirecionados automaticamente para o servidor proxy Tipos de NAT Source NAT (SNAT): ocorre quando o endereço ou porta de origem do pacote é alterado. Source NAT sempre ocorre no momento de post-routing (POSTROUTING), logo antes que o pacote deixa o firewall. MASQUERADING é um exemplo de SNAT. Destination NAT (DNAT): ocorre quando o endereço ou porta de destino do pacote é alterado. Destionation NAT sempre ocorre no momento de pre-routing (PREROUTING), logo quando o pacote chega no firewall. Observação: para realizar DNAT ou SNAT da sua rede interna, é necessário configurar o repasse de pacotes do KERNEL. Esse passo é descrito no item 3.4.3 desse documento. 3.5.1 Exemplos de SNAT 1 Exemplo: # iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to 10.0.0.1 Explicação: Todos os pacotes que sairem pela interface de rede eth0 terão o IP de origem modificado para “10.0.0.1”. 2 Exemplo: # iptables -A POSTROUTING -t nat -p tcp -i eth0 -j MASQUERADE Explicação: Faz com que todos os pacotes originados da interface eth0 saiam para a internet com o endereço de origem do firewall. Essa regra é essencial para que o servidor atue como um servidor proxy. 3 Exemplo: # iptables -t nat -A POSTROUTING -p tcp -o eth0 -j SNAT --to 10.0.0.3:8080 Explicação: Os pacotes que saem pela interface eth0 terão endereço de origem modificado para 10.0.0.3 e a porta de origem modificada para 8080. 3.5.2 Exemplos de DNAT 1 Exemplo: # iptables -t nat -A PREROUTING -p tcp -i eth0 -j DNAT --to 10.0.0.50 Explicação: Pacotes TCP que chegarem através da interface de rede eth0 serão encaminhados para o host, cujo endereço IP é 10.0.0.50. Aplicabilidade: Múltiplos servidores que não possuem endereço IP podem alocar serviços na rede interna e estarem acessíveis na internet. 2 Exemplo: # iptables -t nat -A PREROUTING -p tcp -d 10.0.0.1 --dport 80 -j DNAT --to 10.0.0.30:3128 Explicação: Pacotes que forem destinados ao enderço IP 10.0.0.1 na porta 80 tcp, serão redirecionados para a porta 3128 do host que possui endereço IP 10.0.0.30. Aplicabilidade: Pode ser aplicada fazendo com que o proxy se torne transparente, redirecionando pacotes destinados a porta 80 (http) e 443 (https) para um servidor proxy. 3.6 Exemplo de configuração do firewall baseado em uma topologia Implementando o firewall em uma rede local, disponibilizando o acesso a internet através de um firewall mascarando os pacotes: Topologia: Rede Interna 192.168.1.0/24 servidor web (192.168.1.50) 200.198.10.2 eth1 FIREWALL eth0 192.168.1.1 200.198.10.1 roteador INTERNET A rede 192.168.1.0/255.255.255.0 acessa a internet através do firewall, que está conectado ao roteador, cumprindo o papel de roteador padrão (default gateway). Portanto, o firewall possui duas interfaces de rede. Os pacotes que saem da rede interna para a internet são encaminhados (forwarding) através do firewall, que por sua vez os encaminha para o roteador, onde finalmente são encaminhados para fora (internet). Na volta, ocorre o processo reverso, o roteador recebe o pacote, encaminha-o para o firewall, que novamente o encaminha para o host da rede interna que realizou a requisição original. Antes do pacote sair pelo firewall é aplicado o post-routing (pacotes que ainda serão roteados) e na volta é aplicado o pre-routing (pacotes que já foram roteados). Há ainda um servidor web na rede interna que precisa estar acessível na internet. Vamos disponibilizá-lo fazendo DNAT. Arquivo de script para configuração do firewall: #!/bin/bash #### INÍCIO DA FUNÇÃO stop #### stop() { # desbilita o repasse de pacotes do kernel echo “0” > /proc/sys/net/ipv4/ip_forward # limpa regras existentes nas chains INPUT, OUTPUT E FORWARD /sbin/iptables -F # limpa as regras existentes na tabela de NAT /sbin/iptables -F -t nat } #### FIM DA FUNÇÃO stop #### #### INÍCIO DA FUNÇÃO START #### start () { # habilitando o repasse de pacotes no kernel echo “1” > /proc/sys/net/ipv4/ip_forward ##################################################################### ######################### ROTEAMENTO ################################ ##################################################################### # cria rota padrão para o gateway no provedor (200.198.10.1) # /sbin/route add default gw 200.198.10.1 dev eth1 ##################################################################### ########################## REGRAS ################################### ##################################################################### # Define a política padrão para cada CHAIN /sbin/iptables -P FORWARD DROP /sbin/iptables -P INPUT DROP /sbin/iptables -P OUTPUT DROP # cria uma nova chain denominada filtro /sbin/iptables -N filtro # aceita conexões da rede interna /sbin/iptables -A filtro -m state --state ESTABLISHED,RELATED -j ACCEPT # rejeita novas conexões que não sejam da rede interna /sbin/iptables -A filtro -m state --state NEW ! -i eth0 -j DROP ##################################################################### ################# DETECTA E REGISTRA PORTSCANNERS ################### ##################################################################### # Xmas portscan /sbin/iptables -A filtro -p tcp --tcp-flags ALL FIN,URG,PSH -m limit --limit 2/m --limit-burst 2 -j LOG --log-prefix "Xmas portscanner: " # descarta o pacote /sbin/iptables -A filtro -p tcp --tcp-flags ALL FIN,URG,PSH -j DROP # portscanner do tipo que ativa os bits SYN e FIN /sbin/iptables -A filtro -p tcp --tcp-flags ALL SYN,FIN -m limit --limit 2/m --limit-burst 2 -j LOG --log-prefix "SYN FIN portscanner: " # descarta o pacote /sbin/iptables -A filtro -p tcp --tcp-flags ALL SYN,FIN -j DROP # portscanner do tipo que ativa os bits SYN e RST /sbin/iptables -A filtro -p tcp --tcp-flags SYN,RST SYN,RST -m limit --limit 2/m --limit-burst 2 -j LOG --log-prefix "SYN RST portscanner: " # descarta o pacote /sbin/iptables -A filtro -p tcp --tcp-flags SYN,RST SYN,RST -j DROP # portscanner do tipo que ativa o bit FIN /sbin/iptables -A filtro -p tcp --tcp-flags ALL FIN -m limit --limit 2/m --limit-burst 2 -m state --state ! ESTABLISHED -j LOG --log-prefix "FIN portscanner: " # descarta o pacote /sbin/iptables -A filtro -p tcp --tcp-flags ALL FIN -m state --state ! ESTABLISHED -j DROP # portscanner do tipo que habilita todas as flags tcp /sbin/iptables -A filtro -p tcp --tcp-flags ALL ALL -m limit --limit 2/m --limit-burst 2 -j LOG --log-prefix "ALL portscanner: " # descarta o pacote /sbin/iptables -A filtro -p tcp --tcp-flags ALL ALL -j DROP # portscanner do tipo que não habilita nenhum flag /sbin/iptables -A filtro -p tcp --tcp-flags ALL NONE -m limit --limit 2/m --limit-burst 2 -j LOG --log-prefix "NONE portscanner: " # descarta o pacote /sbin/iptables -A filtro -p tcp --tcp-flags ALL NONE -j DROP ################################################################### ################# PROTEÇÃO CONTRA ATAQUES CONHECIDOS ############## ################################################################### # proteção contra synflood /sbin/iptables -A filtro -p tcp --syn -m limit --limit 1/s -j ACCEPT # proteção contra ping da morte /sbin/iptables -A filtro -p icmp --icmp-type echo-request -m limit --limit 1/s -j ACCEPT # bloqueia outras conexões /sbin/iptables -A filtro -j DROP ###################################################################### ################# POLÍTICA PARA REPASSE DE PORTAS #################### ###################################################################### # libera o repasse de pacotes apenas para portas 53 udp (dns), 80 tcp (http), # 443 tcp (https) /sbin/iptables -A FORWARD -p tcp -s 192.168.1.0/24 --dport 80 -j ACCEPT /sbin/iptables -A FORWARD -p tcp -s 192.168.1.0/24 --dport 443 -j ACCEPT /sbin/iptables -A FORWARD -p udp -s 192.168.1.0/24 --dport 53 -j ACCEPT # aplica a chain filtro na INPUT, ou seja, os pacotes que passarem pela chain INPUT # serão direcionados para a chain filtro /sbin/iptables -A INPUT -j filtro # aplica a chain filtro na FORWARD, ou seja, antes dos pacotes serem repassados (forwarding), serão direcionados pela chain filtro /sbin/iptables -A FORWARD -j filtro #### Regras na tabela de NAT # # # # # mascara os pacotes que chegam na interface eth0 com destino a porta tcp 80 (http) /sbin/iptables -A POSTROUTING -t nat -p tcp -i eth0 --dport 80 -j MASQUERADE # mascara os pacotes que chegam na interface eth0 com destino a porta tcp 443 (https) /sbin/iptables -A POSTROUTING -t nat -p tcp -i eth0 --dport 443 -j MASQUERADE # mascara os pacotes que chegam na interface eth0 com destino a porta udp 53 /sbin/iptables -A POSTROUTING -t nat -p udp -i eth0 --dport 53 -j MASQUERADE # disponibilizando acesso ao servidor web que roda na porta 80 e 443 do host 192.168.1.50 /sbin/iptables -A PREROUTING -t nat -p tcp --dport 80 -j DNAT --to 192.168.1.50:80 /sbin/iptables -A PREROUTING -t nat -p tcp --dport 443 -j DNAT --to 192.168.1.50:443 } #### FIM DA FUNÇÃO start #### ################################################################### ################### INICIANDO E PARANDO O SERVIDOR ################ ################################################################### if [ $# -lt 1 ]; then echo “$1 { start | stop | restart }”; exit 1; fi if [ $1 == “start” ]; then echo “Iniciando o servidor firewall...”; start; fi if [ $1 == “stop” ]; then echo “Parando o servidor firewall...”; stop; fi if [ $1 == “restart” ]; then “Parando o servidor firewall...” stop; “Iniciando o servidor Firewall...” start; fi # # # FIM DO ARQUIVO # # # Agora é preciso configurar o init para executar o script e configurar as rotas na inicialização do sistema. Salve o arquivo com o nome firewall no diretório /etc/init.d e crie um link no diretório do init padrão. Por exemplo, se o seu init padrão está configurado para iniciar no nível 3, execute o seguinte comando: # chmod u+x /etc/init.d/firewall # ln -s /etc/init.d/firewall /etc/rc3.d/S99firewall O script será executado sempre que o sistema for inicializado. 3.7 Opções avançadas do IPTABLES 3.7.1 Especificando múltiplas portas com o módulo multiport O módulo multiport permite especificar um múltiplas portas em uma única regra. Sem usar o multiport seria preciso fazer uma regra para cada porta: # iptables -A INPUT -p tcp -d 1.2.3.4 --dport 25 -j ACCEPT # iptables -A INPUT -p tcp -d 1.2.3.4 --dport 110 -j ACCEPT # iptables -A INPUT -p tcp -d 1.2.3.4 --dport 143 -j ACCEPT Usando o multiport, poderíamos aplicar a mesma configuração com apenas uma regra: # iptables -A INPUT -p tcp -d 1.2.3.4 -m multiport --dports 25,110,143 -j ACCEPT Pode-se especificar no máximo 15 portas diferentes. 3.7.2 Limitando o número de conexões usando o módulo limit É usado para impor um limite de conexões em uma determinada porta ou host. Observe o exemplo: # iptables -A FORWARD -p tcp --dport 25 -i eth0 -m limit –limit 30/hour --limitburst 5 -j ACCEPT Explicação: Limita os hosts que estiverem conectados na interface eth0 a efetuarem apenas 30 conexões na porta 25 a cada hora. A opção --limit-burst limita apenas 5 conexões para cada host. 3.7.3 Criando uma lista de conexões recentes usando o módulo recent O módulo recent permite criar uma lista de endereços IP das conexões recentes. Exemplo: # iptables -A FORWARD -m recent --name portscan --rcheck --seconds 60 -j DROP # iptables -A FORWARD -p tcp --tcp-flags SYN,ACK,FIN,RST RST -m recent – name portscan --set -j DROP Explicação: A primeira regra cria uma lista de endereços que é checada a cada 60 segundos, bloqueando os endereços cadastrados durante esse tempo. A segunda regra, caso seja aplicável a um pacote (nesse caso um pacote suspeito de portscan), inclui o endereço do host que o enviou na lista, bloqueando-o por 60 segundos (um minuto). 3.7.4 Implementando regras baseadas nos valores TTL Exemplo: # iptables -A FORWARD -m ttl --ttl-lt 30 -j DROP Explicação: Descarta pacotes que possuam um valor TTL inferior (--ttl-lt) a 30. Podemos especificar valores maiores (ttl-gt), menores (--ttl-lt) ou iguais (--ttl-eq) durante a checagem do pacote. FIM DO DOCUMENTO Referências: http://www.netfilter.org/ Autor: Diogo Correia Gonzaga Revisão e correções: Ricardo Bimbo Troccoli Brasília, 23 de novembro de 2004