sexta-feira, 26 de junho de 2009

OpenBSD - PacketFilter (PF)

O texto que segue foi escrito por mim para uma apresentação do Packet Filter (O Filtro de pacotes do OpenBSD). Filtro de pacotes é mais comumente conhecido como: "Firewall".

PACKET FILTER

No dia 29 de Maio de 2001 foi descoberto que a licença do IPFilter (o filtro de pacotes padrão no openBSD até então), não era compatível com a licença do BSD, por isso o IPFilter foi imediatamente retirado da arvore do OpenBSD. Assim por algumas semanas o OpenBSD ficou sem um filtro de pacotes. Até que em 24 de Junho de 2001 foi lançado uma versão do PF sem muitas funcionalidades.

Na versão 3.1 do OpenBSD saiu a versão mais completa do PF. Nessa versão todas as funcionalidades básicas de um gateway/firewall foram satisfeitas: NAT, PAT, Redirecionamento .... Com a maturidade do PF, outros sistemas da família BSD também o adotaram: NetBSD, FreeBSD e DragonflyBSD.


É possível habilitar e desabilitar o PF em tempo de execução com os seguintes comandos respectivamente:

pfctl –e
pfctl –d

Ou habilitar o PF para iniciar junto com o sistema operacional, adicionando ou alterando as seguintes entradas no arquivo: /etc/rc.conf

pf=YES
pf_rules=”/etc/pf.conf”

Se o PF for habilitado em tempo de execução, será necessário carregar as regras de firewall para a execução, pois isso não é feito automaticamente quando o firewall é habilitado. É possível carregar as regras com a seguinte linha de comando:

pfctl –f /etc/pf.conf

Caso seja necessário descarregar as regras que estão em execução use o comando:

pfctl –F rules

ou

pfctl –F nat

As regras acima descarregam (Flush) as regras de filtro e NAT respectivamente. Quando as regras de filtro forem descarregadas o PF passa a ter a regras “pass all” novamente, deixando passar todo o tráfego de entrada e saída.

O PF aceita múltiplas opções em união. Sendo assim para habilitar e carregar o firewall e as regras, poderia se digitar uma única linha de comando:

pfctl –ef /etc/pf.conf

Para usar o PF no FreeBSD é necessário uns cuidados extras. Por exemplo algumas opções específicas para cada versão do freeBSD é necessário, por isso é importante que, antes de se configurar o PF no FreeBSD, o FreeBSD handbook seja consultado. Nesse sistema, o PF funcina como um módulo aparte, isso faz necessário que ele seja carregado manualmente.
Para carregá-lo em tempo de execução:

kldload pf

Ou então, para executá-lo junto com a inicialização do sistema operacional, insira ou altere no arquivo /etc/rc.conf a seguinte entrada:

pf_enable=”YES”

Para usar o Pf no NetBSD é necessário compilar o kernel com suporte ao mesmo. Isso é feito habilitando a opção:

pseudo-device pf

Habilitar as seguintes opções em /etc/rc.conf:

lkm=”YES”
pf=YES

Ou em tempo de execução execute os seguintes comandos:

modload /usr/lkm/pf.o
pfctl –e

Levando em consideração que o Firewall vai trabalhar como gateway, é importante que ele seja capaz de fazer a comutação do pacote (enviar o pacote de uma interface para a outra). Isso é habilitado no arquivo /etc/sysctl.conf adicionando ou alterando a seguinte linha:

net.inet.ip.forwarding=1

Uma regra básica permite que tudo saia pelo firewall mas bloqueia as entradas:

block in all
pass in from $interface_interna:network
pass out all

Para os pacotes poderem voltar em resposta às requisições feitas internamente, o PF implicitamente permite que todo pacote que volte (entre pelo firewall) tendo sido anteriormente requisitado seja aceito.

É característica do PF ler as regras de firewall de cima pra baixo, e mesmo que uma regra se aplique a um determinado pacote, o firewall continuará comparando o mesmo pacote com as demais regras até chegar ao final da lista. Assim se existir outra regra que se aplique a aquele pacote, a regra será sobreposta. Para forçar que a regra seja aplicada ao pacote e não prossiga comparando com as demais regras usa-se a opção “quick” nas regras.

É possível criar variáveis dentro do arquivo de configuração do PF, essas variáveis são mais conhecidas como “macros”, uma macro pode contar um valor únicos ou múltiplos valores. Quando se atribui múltiplos valores a uma macro dá-se o nome de “lista”.

O PF ainda reconhece o número da porta de um determinado serviço pelo próprio nome do protocolo de camada 7, por exemplo: ao nome “HTTP” é atribuído o valor “80”, para “HTTPS” o valor “443” e assim por diante.

A sintaxe vic0:network (onde vic0 é o nome da placa de rede) se refere ao endereço de rede que se encontra configurado na placa vic0. E a sintaxe (vic0) se refere a endereço IP configurado na placa vic0.

Conexões FTP representam desafios maiores para o administrador do firewall, pois em todos os sentidos o FTP não é confiável. A autenticação é feita em texto claro e após a autenticação, a porta de transmissão de dados é negociada e então a transferência acontece por aquela porta. Dessa maneira o firewall não tem como adivinhar que aquela porta onde a transferência está tentando ser feita é referente a uma conexão já existente, sendo assim, a conexão é negada.

Para lidar com essa conexão problemática, é utilizado um aplicativo à parte do PF chamado Proxy-ftp, ele se encarrega de ligar as portas às conexões, e o papel do PF é apenas redirecionar as conexões FTP para o Proxy-ftp tratar. Isso é feito de uma maneira simples (com ancoras).

Geralmente é da vontade do administrador da rede liberar a requisição de pings feitos a partir de dentro da rede, mas não permitir que alguém de fora da rede o faça. Para isso é importante conhecer as características do ping. Ele usa i protocolo ICMP, e para o ping em específico podemos ter os seguintes tipos de icmp: echo-request e echo-reply. O echo-request é a requisição do ping, e echo-reply é a resposta à requisição. Então queremos permitir apenas a saída de requisições.

Conceitualmente muitos acreditam que liberando o ICMP echo-request o traceroute também funcionará, mas ele usa o protocolo UDP e não o ICMP (apenas a Microsoft implementou o tracert sobre o ICMP), as portas que o traceroute usa para fazer as requisições estão na faixa entre 33433 e 33626. Desta maneira, para liberar também o traceroute é necessio a seguinte regra:

pass out on $ext_if inet proto udp from any to any port 33433> $webpool round-robin \ stick-address

Ainda com o round-robin, temos o problema referente à indisponibilidade de um dos servidores do pool. Caso um servidor fique indisponível algumas requisições ainda serão direcionadas para ele, causando desconforto para os clientes. Para solucionar o problema usa-se um aplicativo à parte ancorado ao PF (assim como o FTP-proxy), esse aplicativo é o “hoststated”. Para o hoststated trabalhar com o PF obrigatoriamente o pool de servidores devem estar numa tabela e não numa lista em macro. Explorar o “hoststated” está fora do escopo da apresentação.

O PF pode agir, em alguns aspectos, como um IPS (Intrusion Prevention System). Em que sentido? Regras podem ser definidas e, caso alguém não cumpra a regra, entra numa tabela com ips bloqueados. Por exemplo, se configuramos o acesso remoto via SSH para a rede externa (internet) não raro haverá uma seqüência de tentativas de acesso remoto por força bruta. Podemos bloquear essas tentativas com as seguintes entradas numa regra:

max-src-conn – Número máximo de conexões a partir de um único host
max-src-conn-rate – Número máximo de requisições de conexão, por um determinado número de segundos, vindos do mesmo host.
overload – Em qual tabela jogar esse endereço de host caso ele desobedeça essas requisitos.
flush global – Derruba qualquer outra conexão vinda daquele host

É importante que a tabela pra onde o “overload” estará jogando o endereço IP do host possua uma regra de bloqueio, exemplo:

block quick from

O problema com essa solução é que não existe um mecanismo interno retirando os endereços de dentro dessa tabela. Desta maneira a tabela irá crescer até não haver mais espaço em memória, além de que se esse for um endereço dinâmico, um outro host poderá pegar esse endereço e ficar sem acesso à nossa rede por esse motivo. Para limpar os endereçamentos em um determinado tempo de dentro da tabela, é necessário executar a seguinte linha de comando:

pfctl -t table –T expire 86400

Esta linha eliminará de dentro da tabela “table” todos os endereços que estejam lá há mais de 86,400 segundos (24 horas). Como isso deve ser executado manualmente, sugere-se que seja agendado uma tarefa no crontab para que este comando seja executado periodicamente.

O PF vem com algumas opções para alguns ataquem específicos, algumas delas são:

Scrub – proteção contra ataque de pacotes mau formados (tratando a fragmentação de pacotes)
Antispoof – proteção contra ataques externos com o endereçamento da rede interna
Set block-policy – Configuração da política padrão
Set skip – Define uma interface de rede na qual as regras em geral não se aplicam

.

0 comentários:

Postar um comentário