Terror da Internet, os ataques de DDoS ficaram em evidência ultimamente por causa dos grupos AnonOps e LuzSec, que atacaram vários sites usando essa técnica.  

DDoS nada mais é que um ataque do tipo "estouro de boiada".  Utilizando máquinas contaminadas, usa-se um programa "administrador" que envia o agendamento do ataque, com data e horário, para uma máquina de destino.  No caso esse destino foi num dos servidores que administro.  Por acaso onde está o serviço do http://eri.cx entre outros.

O ataque não foi dirigido diretamente à mim, mas um dos sites hospedados lá (não, não foi pro eri.cx).  Durante um ataque DDoS, isso não importa muito pois tudo que está hospedado no servidor é afetado juntamente.  Ou os serviços tornam-se indisponíveis ou a máquina pode travar, o que não deveria acontecer.   Mas um ataque DDoS não abre brechas pra invasão ou algo do gênero.

Felizmente conseguimos mitigar o ataque e minizar seus efeitos com algumas medidas bem simples, que são descritos aqui.

Comecei a suspeitar que algo estava errado quando recebi a mensagem abaixo, da lista de discussão que é mantida nesse servidor.


From: Mail Delivery System <This email address is being protected from spambots. You need JavaScript enabled to view it.>
Date: 2011/7/1
Subject: Undelivered Mail Returned to Sender
To: This email address is being protected from spambots. You need JavaScript enabled to view it.


This is the mail system at host domain.server.com.

I'm sorry to have to inform you that your message could not
be delivered to one or more recipients. It's attached below.

For further assistance, please send mail to postmaster.

If you do so, please include this problem report. You can
delete your own text from the attached returned message.

                  The mail system

<This email address is being protected from spambots. You need JavaScript enabled to view it.>: Command time limit exceeded: "/var/lib/mailman/mail/mailman
   post list"

Imediatamente tentei conectar no servidor e... nada.  Página web igualmente fora do ar.  Achei que poderia ser algum problema de hardware ou mesmo da máquina virtual.  Entrei em contato com a pessoa que tinha o acesso console na máquina e pedi para verificar o que estava acontecendo.

Momentos depois recebi o contato da pessoa avisando que a máquina estava travada e não conseguia dar boot: ela voltava a travar instantes depois.  Nesse momento imaginei que podia ser um ataque.

Pedi então para dar boot em "single mode" e desabilitar acesso ao apache e mysql e tentar o boot normalmente.  Felizmente deu certo, pois ataques DDoS são fortes em volume, mas não muito inteligentes e refinados.

Utilizando o tcpdump, demos uma olhada no tipo de tráfego que chega e vimos que o ataque era direcionado prioritariamente à porta 80 (web):


17:57:01.220234 IP 115.214.63.123.2844 > server.80: Flags [.], ack 1863118067, win 65306, length 0
17:57:01.237522 IP 115.214.63.123.2844 > server.80: Flags [F.], seq 0, ack 1, win 65306, length 0
17:57:01.237582 IP server.80 > 115.214.63.123.2844: Flags [.], ack 1, win 6432, length 0
17:57:01.241481 IP 86.96.227.91.39237 > server.80: Flags [.], ack 1882163284, win 65535, length 0
17:57:01.241527 IP 86.96.227.91.39237 > server.80: Flags [P.], seq 0:285, ack 1, win 65535, length 285
17:57:01.241573 IP server.80 > 86.96.227.91.39237: Flags [.], ack 285, win 6432, length 0
17:57:01.269729 IP server.80 > 86.96.227.91.39237: Flags [.], seq 1:1461, ack 285, win 6432, length 1460
17:57:01.269774 IP server.80 > 86.96.227.91.39237: Flags [P.], seq 1461:2802, ack 285, win 6432, length 1341

Vários pedidos de início de conexão, sem resposta.

O efeito do ataque pode ser visto nesse gráfico, entre as semanas 26 e 27:

Olhando nos logs do apache, pudemos identificar qual o domínio que estava sob ataque.  Confirmamos com tcpdump também que boa parte do ataque buscava tal domínio pelo DNS, verificando o tráfego na porta 53.  Então tomei a primeira providência para mitigar o ataque: troquei os IPs do domínio no DNS para 127.0.0.1 (loopback).

Como anúncios de DNS demoram um pouco para serem propagados, essa solução começou a mostrar um pouco mais de eficiência somente depois de 1 hora.  Mas isso reduziu o ataque na ordem de 60%, ou até mais.

O DNS seria suficiente, mas o ataque poderia voltar buscando somente o IP e esse truque não iria ajudar muito.  Então comecei a olhar como estava configurado o servidor Apache, pois um servidor Unix (ou Linux no caso) não pode travar por conta de um ataque desses, a menos que tenha alguma configuração incorreta.

Como o gráfico mostra, o servidor Apache com suas configurações padrão não foi afetado pelo ataque.  Vários processos foram criados, mas finalizados em seguida.

Tentei então verificar como estava o sistema durante o ataque, para tentar identificar o que o ataque tinha ocasionado para travar.

Como os gráficos mostram, o ataque não causou nenhum uso excessivo de CPU ou do sistema.  Nada que pudesse levar a máquina ao travamento.  Mas o servidor travava com o serviço do Apache ligado.  Então resolvi olhar os parâmetros TCP do sistema.

Essa imagem me deu a noção clara que os recursos de redes estavam sendo usados em excesso.  Mas mesmo isso não deveria causar o travamento de servidor.

Então resolvi olhar como estava o firewall.

 

A imagem que ajudou a entender o problema foi a de ipconntrack.  Como o netfilter (iptables) utiliza um modo "stateful", cada pacote que entra no sistema ocupa uma posição de memória, para poder identificar (e liberar) as conexões restantes vindas dessa origem.  Como o sistema estava sob ataque, a posição era alocada, mas ficava parada aguardando o fim da conexão, que não acontecia.  Pra piorar a situação, o firewall alocava memória e recursos do sistema em kernel level, motivo pelo qual o sistema travava.

Para mitigar esse problema, alteramos os parâmetros de kernel com sysctl da seguinte forma:


net.netfilter.nf_conntrack_generic_timeout=5
net.netfilter.nf_conntrack_tcp_timeout_syn_sent=120
net.netfilter.nf_conntrack_tcp_timeout_syn_recv=10
net.netfilter.nf_conntrack_tcp_timeout_established=10
net.netfilter.nf_conntrack_tcp_timeout_fin_wait=5
net.netfilter.nf_conntrack_tcp_timeout_close_wait=3
net.netfilter.nf_conntrack_tcp_timeout_last_ack=10
net.netfilter.nf_conntrack_tcp_timeout_time_wait=5
net.netfilter.nf_conntrack_tcp_timeout_close=10
net.netfilter.nf_conntrack_tcp_timeout_max_retrans=300
net.netfilter.nf_conntrack_tcp_timeout_unacknowledged=300
net.netfilter.nf_conntrack_tcp_loose=1
net.netfilter.nf_conntrack_tcp_be_liberal=0
net.netfilter.nf_conntrack_tcp_max_retrans=3
net.netfilter.nf_conntrack_udp_timeout=30
net.netfilter.nf_conntrack_udp_timeout_stream=180
net.netfilter.nf_conntrack_icmp_timeout=30
net.netfilter.nf_conntrack_icmpv6_timeout=30
net.netfilter.nf_conntrack_frag6_timeout=60
net.netfilter.nf_conntrack_frag6_low_thresh=196608
net.netfilter.nf_conntrack_frag6_high_thresh=262144
net.netfilter.nf_conntrack_acct=1
net.netfilter.nf_conntrack_events=1
net.netfilter.nf_conntrack_events_retry_timeout=15
net.netfilter.nf_conntrack_max=15876
net.netfilter.nf_conntrack_count=254
net.netfilter.nf_conntrack_buckets=4096
net.netfilter.nf_conntrack_checksum=1
net.netfilter.nf_conntrack_log_invalid=0
net.netfilter.nf_conntrack_expect_max=64
net.core.somaxconn=128
net.ipv4.netfilter.ip_conntrack_generic_timeout=5
net.ipv4.netfilter.ip_conntrack_tcp_timeout_syn_sent=120
net.ipv4.netfilter.ip_conntrack_tcp_timeout_syn_sent2=120
net.ipv4.netfilter.ip_conntrack_tcp_timeout_syn_recv=20
net.ipv4.netfilter.ip_conntrack_tcp_timeout_established=10
net.ipv4.netfilter.ip_conntrack_tcp_timeout_fin_wait=5
net.ipv4.netfilter.ip_conntrack_tcp_timeout_close_wait=3
net.ipv4.netfilter.ip_conntrack_tcp_timeout_last_ack=10
net.ipv4.netfilter.ip_conntrack_tcp_timeout_time_wait=5
net.ipv4.netfilter.ip_conntrack_tcp_timeout_close=10
net.ipv4.netfilter.ip_conntrack_tcp_timeout_max_retrans=300
net.ipv4.netfilter.ip_conntrack_tcp_loose=1
net.ipv4.netfilter.ip_conntrack_tcp_be_liberal=0
net.ipv4.netfilter.ip_conntrack_tcp_max_retrans=3
net.ipv4.netfilter.ip_conntrack_udp_timeout=30
net.ipv4.netfilter.ip_conntrack_udp_timeout_stream=180
net.ipv4.netfilter.ip_conntrack_icmp_timeout=30
net.ipv4.netfilter.ip_conntrack_max=15876
net.ipv4.netfilter.ip_conntrack_count=254
net.ipv4.netfilter.ip_conntrack_buckets=4096
net.ipv4.netfilter.ip_conntrack_checksum=1
net.ipv4.netfilter.ip_conntrack_log_invalid=0
net.nf_conntrack_max=15876

O padrão de timeout para TCP é de 2 horas.  Alterei para alguns segundos.  Com isso pudemos reiniciar todos os serviços e mitigar totalmente o ataque, tendo a certeza que o servidor não travaria novamente.

We use cookies

We use cookies on our website. Some of them are essential for the operation of the site, while others help us to improve this site and the user experience (tracking cookies). You can decide for yourself whether you want to allow cookies or not. Please note that if you reject them, you may not be able to use all the functionalities of the site.