SYN Flood – Como funciona e Solução

Mas o que é DoS?

DoS significa “Denied of Service” (Negação de serviço). São técnicas de ataque pelas quais o atacante deseja apenas tirar uma máquina ou serviço do ar, ou seja, deixá-la inoperante.

Existem basicamente dois tipos de DoS: local ou remoto. Os locais podem ser facilmente contornados com configurações apropriadas. Já os remotos são mais complicados.

Muitas das negações de serviços remotas tem como origem algum bug de programação que, quando corrigidos, deixam de existir. Outros, no entanto, são “eternos”, pois são baseados na forma como alguns protocolos de rede foram desenvolvidos (como é o caso do Syn Flood descrito adiante).

Basicamente quanto Syn Flood tenho visto muitas tentativas de contorná-lo com regras de iptables. Minha visão (explicada neste artigo) é que este tipo de defesa de nada adianta e não impede a negação.

Mas antes de falar do iptables, a “falsa” defesa e como realmente se pode defender do Syn Flood, iremos explicar os tipos de DOS existentes, o que é e no que se baseia o Syn Flood para poder entender porque o iptables na verdade não o evita.

Este artigo possui alguns conceitos complexos, como números sequenciais de TCP, mas o entendimento do básico, o que é e porque iptables não serve, pode ser facilmente compreendido. Sinta-se a vontade para ignorar o capítulo que explica o funcionamento do Syn cookie, caso queira.

Tipos de negação de serviço

O DoS (Denied of Service) podem ser de dois tipos:

a) DoS local: nesta o atacante possui acesso à máquina, ou porque é um usuário legítimo, ou porque roubou a senha de um usuário ou ainda porque explorou alguma vulnerabilidade (como em scripts PHP mal programados, por exemplo). De qualquer maneira, para que esta técnica tenha sucesso o atacante deve ter condições de executar comandos locais na máquina.

Mas o que o atacante, estando na máquina, pode fazer para derrubar serviços? Muitas coisas! Pode executar comandos em seqüência que esgotem a memória, por exemplo. Ou a capacidade do kernel de criar novos processos. Um exemplo bem típico de DOS local é o atacante fazer:

# dd if=/dev/zero of=/var/spool/mail/usuario

(considerando que /var/spool/mail é partição onde estão os emails dos usuários e que ele possa escrever no arquivo usuario, que é seu)

Se nenhuma defesa existir (neste caso seria o emprego de quotas), o disco ou esta partição será esgotado, impedindo a entrada de novos emails. Causa-se um DoS no serviço de email.

As defesas para DoS locais são fáceis e requerem apenas a sua configuração, como o emprego de quotas, particionamento correto do disco e a adoção de limites de recursos para cada processo ou usuário (no Linux tem o PAM limits que faz isto).

b) DoS remoto: neste o atacante não precisa estar logado na máquina e nem executar comandos nela. Remotamente, de alguma forma, ele derruba o serviço.

Programas mal feitos, com bugs, são os recordistas deste tipo de negação. Devido a descuidos na programação, as vezes só por enviar um pacote devidamente construído já é suficiente para derrubar o serviço.

O lendário ping da morte pode ser citado como um exemplo bem típico. Ou ainda o ataque XMAS (árvore de natal), onde se enviava um pacote TCP com todos os flags ligados (anormal e impossível. Como um pacote teria, por exemplo, flag de SYN, RST e FIN ao mesmo tempo?).

Uma pilha TCP bem programada deveria descartar este pacote, mas implementações antigas se perdiam e caiam. De qualquer forma estes ataques, baseados em erros de programação, acabam tendo vida curta: só existem até que o fabricante do sistema disponibilize correções (se bem que por vezes acabam sendo eternos para aqueles que não aplicam correções nos seus sistemas).

Mas existem as negações de serviços que são baseados na forma como os protocolos TCP/IP foram implementados e alguns, como o SYN flood, não existem correções, ou seja, eles existem e continuarão existindo. Só nos resta nos defender deles.

Um destes ataques de negação de serviço é o SYN flood, que quando realizado de forma distribuída (dDoS) derrubam o serviço mesmo!

O que é o SYN Flood?

Para entender o Syn Flood é preciso, mesmo que rapidamente, falar um pouco do TCP.

O protocolo TCP é orientado a conexão: primeiro cliente e servidor se conectam e somente após esta etapa é que os dados podem ser trocados. Semelhante a uma ligação telefônica, onde deve-se primeiro discar para o número.

A etapa de “discar” no TCP é chamada de handshake de três vias e os flags TCP são usados para sinalizar qual etapa se está realizando. Antes de qualquer bit de dados, a seguinte troca de pacotes acontece entre cliente e servidor:

1. O cliente envia uma solicitação de conexão, com um pacote TCP sem dados, possuindo o flag de SYN ligado e os demais desligados. Por causa da presença do flag de SYN, este pacote é conhecido como pacote SYN

2. Se o servidor quiser e puder atender, devolve um pacote ao cliente ainda sem dados, com os flags de SYN e de ACK ligados. Esta segunda etapa é conhecida como SYN/ACK.

3. Se o cliente ainda quiser manter a conexão, devolve ao servidor um terceiro pacote sem dados, apenas com o flag de ACK ligado (SYN desligado).

Somente após a terceira etapa é que os dados podem ser trocados.

O mais importante para entender a gravidade do ataque é saber que o servidor, ao receber o primeiro pacote (SYN), se ele quiser atender (exemplo: serviço HTTP, porta 80), precisa antes de responder com o SYN/ACK, alocar recursos de hardware para atender esta nova conexão.

Como o TCP é um protocolo confiável, que trata de desordenamento e perdas de pacotes, estes recursos não são poucos, pois envolvem buffers de envio e de recebimento, controle de números seqüenciais, relógios diversos, enfim, muitos recursos de memória, principalmente.

E o que acontece se uma máquina fizer o SYN (etapa 1), o servidor alocar recursos e responder com o SYN/ACK (etapa 2) mas o cliente não completa o handshake e não realiza a última etapa? Os recursos ficam alocados?

Ficam, mas não para sempre. O servidor fica esperando o ACK do cliente e se o mesmo não chegar depois de certo tempo, os recursos são desalocados. Mas o fato é que estes recursos realmente permanecem alocados por algum tempo, mesmo que curto.

Aí que entra o SYN Flood (tradução literal: inundação de SYN). Nele o atacante gera quantos SYN’s a máquina dele for capaz e não responde nenhum deles. Tem-se que o servidor vai alocar recursos para cada um, como se fossem requisições legítimas, só desalocando quando acabar o tempo. É perfeitamente compreensível que o atacante consegue gerar pacotes de SYN muito mais rapidamente e facilmente do que o servidor consegue tratá-los.

Claro, hoje temos hardware com capacidades de memória e recursos gigantescos, mas não existem recursos infinitos. Mais cedo ou mais tarde os recursos se esgotarão e o servidor ficará incapaz de atender clientes legítimos.

Este é o SYN flood!
Solução FURADA 1: bloquear o IP do atacante

Alguém pode rapidamente pensar: posso simplesmente bloquear o número IP de quem está me atacando e pronto.

Isto não funciona porque o ataque de SYN flood só tem efetivo sucesso se o atacante realizar Ip spoofing de seus pacotes, falsificando o número Ip em cada novo SYN. Isto é desejável até para não atolar o próprio atacante: ele teria que tratar os SYN/ACKs que recebe!

Assim, a cada novo pacote de SYN ele inventa um IP qualquer e o SYN/ACK será devolvido para este IP inventado, que nada sabe a respeito. Qual IP irei bloquear se a cada nova requisição ele muda?

Tem ferramentas prontas que fazem isto, como o hping!

Como mencionado na introdução, por vezes pode ser que uma única máquina (a do atacante) não consiga gerar tantos SYNs até por questões de limite de banda. Mas se ele tem centenas de máquinas “escravinhas” ao comando dele, um ataque de Syn Flood distribuído é o pior cenário que um administrador de rede pode sofrer e não adianta ele ir brincando de bloquear números ips.

Limitar o número de requisições no iptables funciona?

Esta “solução”, do qual sou crítico, é fartamente encontrada na Internet em scripts receitas de bolo, por vezes até com comentários:

# Protege contra os ataques do tipo Syn-flood
iptables -A FORWARD -p tcp –syn -m limit –limit 10/s -j ACCEPT
iptables -A FORWARD -p tcp –syn -j DROP

Foi a motivação que encontrei para escrever este artigo. A idéia é nobre: como eu limitei as entradas de SYN a uma taxa de apenas 10 por segundo, logo é impossível qualquer um de meus servidores TCP sofrer um SYN flood.

Ok, está certo, realmente o é! Meus servidores não sofrerão o SYN flood.

Mas um atacante não quer realmente realizar um SYN Flood, certo? O que ele quer é causar uma negação de serviço, ou seja, torná-lo indisponível? Estou certo?

Bom, agora a tarefa do atacante ficou ainda mais fácil: basta ele manter uma taxa de requisições do tipo SYN a, no mínimo, 10 por segundo. O que vai acontecer com o décimo primeiro SYN que chegar no mesmo segundo? Será DROPADO? Ótimo, o décimo primeiro, décimo segundo, etc, pode ser um cliente legítimo! Percebam, não é uma solução, é um engodo! Agora o próprio iptables é quem tira meu serviço do ar!

E não adianta querer usar outras variações do limit, como o hashlimit, limitando por IP de origem, pois como mencionei, o atacante pode mudar o número de IP a cada nova tentativa.

Podemos até comentar que alguma vantagem esta regra teria: o servidor ficaria disponível na rede Interna, mas de qualquer maneira, realmente não é nada agradável usar tal regra.

Tudo bem, me convenceu. Qual é a saída?

O problema está na origem: a alocação de recursos. Ela é realizada no primeiro SYN. Mas e se o servidor só alocasse recursos quando receber o terceiro e último pacote do handshake? Esta é a solução e o Linux tem isto há muito tempo. Chama-se SYN cookies:

# ligando proteção para SYN flood. Deve ser feita em todos os servidores
echo 1 > /proc/sys/net/ipv4/tcp_syncookies

Mas não é tão simples assim. Não basta simplesmente mudar a alocação de recursos para o recebimento do ACK final, pois se fosse só isto, rapidamente o ataque de SYN flood se transformaria em ACK flood!

O desafio é a pilha TCP/IP, ao receber o último ACK, alocar recursos mas SOMENTE se o SYN inicial aconteceu, ou seja, se realmente houve o handshake.

Mas como ele pode fazer isto? Será que poderia ser assim:
a. ao receber o SYN, memoriza o IP e porta de origem de quem enviou;
b. devolve o SYN/ACK;
c. quando receber o ACK, verifica se o IP e porta é conhecido, se for, aloca os recursos do TCP.
De maneira alguma! “Memorizar” o IP e porta não significa alocar recursos? Para que o servidor ficasse realmente imune ao SYN flood, ele não deve alocar absolutamente nada ao receber o SYN, mas mesmo assim, deve “lembrar-se” dele ao receber o ACK final!

Isto é possível?

O segredo está na manipulação dos números seqüenciais e de verificação do TCP. Não quero aqui explicar o que são estes números e para que servem, pois o artigo ficaria muito pesado. Mas basta dizer que:

1. quando o cliente envia o primeiro SYN, envia também um número de 32 bits. chamado número de seqüência (vamos chamar de NS-C, número de seqüência do cliente)

2. quando o servidor recebe o SYN, ele também escolhe um NS para si (NS-S, número de seqüência do servidor) e devolve o pacote com dois números: o seu NS-S e o número de verificação, chamando de ACK (diferente do flag, este tem também 32 bits). Este segundo número nada mais é do que NS-C+1.

3. o cliente, ao completar o handshake, devolve NS-C+1 e NS-S + 1.

Ou seja, em cada pacote a máquina devolve como NACK o SN do outro anterior + 1. Ai está o “pulo do gato” da técnica Syn cookie. Quando o servidor escolhe o seu NS (no exemplo, 200), ele o faz através de uma função hash de 32 bits, onde serão consideradas informações como IP/Porta do cliente e dados que só o servidor tem. O servidor gera este número e esquece! (não aloca recursos, portanto).

O fato é que quando vier o último pacote, com o NACK=201, o servidor refaz o cálculo do HASH, pois nenhum dado foi alterado. Refazendo o cálculo ele encontra 200, que é justamente o número recebido menos um. Ou o cliente é legítimo, pois completou o handshake ou é um cara de muita sorte.

Observe que um atacante está impossibilitado de realizar o SYN flood, pois ele não recebe o pacote SYN/ACK que tem o NS-S= 200. Como ele falsificou o IP (ele precisa) este pacote foi lá para o Ip falso que o atacante inventou. Logo o atacante não conhece o valor de NS-S (200) para poder devolvê-lo com mais um(201). Lhe resta adivinhar ou quebrar o fraco hash de 32 bits. Mas veja, ele é fraco mas resolve. Se o atacante precisar de 3 segundos para quebrar, isto já é uma eternidade para que o SYN flood realmente cause uma negação de serviço.

Conclusão
Ataques de SYN flood são sofisticados, envolvem falsificação de números Ips e diversas máquinas atuando em conjunto. Soluções por firewall são insuficientes.

A utilização de firewalls deveria sim ser empregada no sentido de evitar o ip spoofing, coisa que muitos provedores de acesso não fazem. Se sou um provedor de acesso, por exemplo, e minha faixa de ips é 192.168.0.0/16 (estou usando ips privados por questões éticas), como eu deixo um assinante meu gerar um pacote com ip de origem sendo 172.16.5.4?

Ora, eu deveria, ao menos, ter uma regra bem simples no meu firewall:

iptables -A FORWARD -i Placa-Assinantes -s ! 192.168.0.0/16 -j DROP

Pronto. Impedi que meus clientes façam ip spoofing. Ah se todos os provedores do mundo fizessem isto… O fato é que a imensa maioria preocupa-se em não ser atacado, e raramente se preocupam em não permitir que seus clientes ataquem!

  1. No trackbacks yet.

Deixe uma resposta

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s

%d blogueiros gostam disto: