DDoS para o resgate: como conduzimos testes de estresse e carga

DDoS para o resgate: como conduzimos testes de estresse e carga

A Variti desenvolve proteção contra bots e ataques DDoS, e também realiza testes de estresse e carga. Na conferência HighLoad++ 2018 falamos sobre como proteger recursos contra vários tipos de ataques. Resumindo: isole partes do sistema, use serviços em nuvem e CDNs e atualize regularmente. Mas você ainda não conseguirá cuidar da proteção sem empresas especializadas :)

Antes de ler o texto, você pode ler os breves resumos no site da conferência.
E se você não gosta de ler ou apenas quer assistir ao vídeo, a gravação da nossa reportagem está abaixo no spoiler.

Gravação de vídeo do relatório

Muitas empresas já sabem fazer testes de carga, mas nem todas fazem testes de estresse. Alguns de nossos clientes pensam que seu site é invulnerável porque possui um sistema de alta carga e protege bem contra ataques. Mostramos que isso não é inteiramente verdade.
Claro que antes de realizar os testes, obtemos autorização do cliente, assinada e carimbada, e com a nossa ajuda um ataque DDoS não pode ser realizado em ninguém. Os testes são realizados no horário escolhido pelo cliente, quando o tráfego para seu recurso é mínimo e os problemas de acesso não afetarão os clientes. Além disso, como sempre algo pode dar errado durante o processo de testes, mantemos contato constante com o cliente. Isso permite não apenas relatar os resultados alcançados, mas também alterar algo durante o teste. Após a conclusão dos testes, elaboramos sempre um relatório no qual apontamos as deficiências detectadas e damos recomendações para eliminar as deficiências do site.

Como estamos trabalhando

Ao testar, emulamos uma botnet. Como trabalhamos com clientes que não estão localizados em nossas redes, para garantir que o teste não termine no primeiro minuto por acionamento de limites ou proteção, fornecemos a carga não de um IP, mas de nossa própria sub-rede. Além disso, para criar uma carga significativa, temos nosso próprio servidor de teste bastante poderoso.

Postulados

Muito não significa bom
Quanto menos carga pudermos levar um recurso à falha, melhor. Se você conseguir fazer o site parar de funcionar com uma solicitação por segundo, ou mesmo uma solicitação por minuto, isso é ótimo. Porque de acordo com a lei da maldade, os usuários ou invasores cairão acidentalmente nesta vulnerabilidade específica.

A falha parcial é melhor que a falha completa
Aconselhamos sempre tornar os sistemas heterogêneos. Além disso, vale a pena separá-los no nível físico, e não apenas pela conteinerização. No caso de separação física, mesmo que algo falhe no site, há uma grande probabilidade de que ele não pare de funcionar completamente e os usuários continuem a ter acesso a pelo menos parte da funcionalidade.

Uma boa arquitetura é a base da sustentabilidade
A tolerância a falhas de um recurso e sua capacidade de resistir a ataques e cargas devem ser estabelecidas na fase de projeto, na verdade, na fase de desenho dos primeiros fluxogramas em um notebook. Porque se surgirem erros fatais, é possível corrigi-los no futuro, mas é muito difícil.

Não só o código deve ser bom, mas também a configuração
Muitas pessoas pensam que uma boa equipe de desenvolvimento é garantia de um serviço tolerante a falhas. Uma boa equipe de desenvolvimento é realmente necessária, mas também deve haver boas operações, um bom DevOps. Ou seja, precisamos de especialistas que configurem corretamente o Linux e a rede, escrevam configurações corretamente no nginx, definam limites, etc. Caso contrário, o recurso funcionará bem apenas em testes, e em algum momento tudo irá quebrar na produção.

Diferenças entre testes de carga e de estresse
O teste de carga permite identificar os limites de funcionamento do sistema. O teste de estresse tem como objetivo encontrar pontos fracos em um sistema e é utilizado para quebrar esse sistema e ver como ele se comportará no processo de falha de determinadas peças. Neste caso, a natureza da carga geralmente permanece desconhecida para o cliente antes do início do teste de estresse.

Características distintivas dos ataques L7

Geralmente dividimos os tipos de carga em cargas nos níveis L7 e L3 e 4. L7 é uma carga no nível do aplicativo, na maioria das vezes significa apenas HTTP, mas nos referimos a qualquer carga no nível do protocolo TCP.
Os ataques L7 têm certas características distintivas. Em primeiro lugar, eles chegam diretamente ao aplicativo, ou seja, é improvável que sejam refletidos via rede. Tais ataques utilizam lógica e por isso consomem CPU, memória, disco, banco de dados e outros recursos de forma muito eficiente e com pouco tráfego.

Inundação HTTP

No caso de qualquer ataque, a carga é mais fácil de criar do que de manusear, e no caso do L7 isso também é verdade. Nem sempre é fácil distinguir o tráfego de ataque do tráfego legítimo e, na maioria das vezes, isso pode ser feito por frequência, mas se tudo for planejado corretamente, é impossível entender pelos logs onde está o ataque e onde estão as solicitações legítimas.
Como primeiro exemplo, considere um ataque HTTP Flood. O gráfico mostra que tais ataques costumam ser muito poderosos; no exemplo abaixo, o número máximo de solicitações ultrapassou 600 mil por minuto.

DDoS para o resgate: como conduzimos testes de estresse e carga

HTTP Flood é a maneira mais fácil de criar carga. Normalmente, é necessário algum tipo de ferramenta de teste de carga, como o ApacheBench, e define uma solicitação e um destino. Com uma abordagem tão simples, há uma grande probabilidade de ocorrer o cache do servidor, mas é fácil contorná-lo. Por exemplo, adicionar strings aleatórias à solicitação, o que forçará o servidor a servir constantemente uma nova página.
Além disso, não se esqueça do agente do usuário no processo de criação de uma carga. Muitos agentes de usuários de ferramentas de teste populares são filtrados pelos administradores do sistema e, nesse caso, a carga pode simplesmente não chegar ao back-end. Você pode melhorar significativamente o resultado inserindo um cabeçalho mais ou menos válido do navegador na solicitação.
Por mais simples que sejam os ataques HTTP Flood, eles também têm suas desvantagens. Em primeiro lugar, são necessárias grandes quantidades de energia para criar a carga. Em segundo lugar, esses ataques são muito fáceis de detectar, especialmente se vierem de um endereço. Como resultado, as solicitações começam imediatamente a ser filtradas pelos administradores do sistema ou mesmo no nível do provedor.

O que procurar

Para reduzir o número de solicitações por segundo sem perder eficiência, é preciso ter um pouco de imaginação e explorar o site. Assim, você pode carregar não apenas o canal ou servidor, mas também partes individuais do aplicativo, por exemplo, bancos de dados ou sistemas de arquivos. Você também pode procurar locais no site que façam cálculos grandes: calculadoras, páginas de seleção de produtos, etc. Finalmente, muitas vezes acontece que o site possui algum tipo de script PHP que gera uma página de várias centenas de milhares de linhas. Esse script também carrega significativamente o servidor e pode se tornar alvo de um ataque.

Onde olhar

Quando verificamos um recurso antes de testá-lo, primeiro olhamos, é claro, para o próprio site. Procuramos todos os tipos de campos de entrada, arquivos pesados ​​- em geral, tudo que pode criar problemas para o recurso e retardar seu funcionamento. Ferramentas de desenvolvimento banais no Google Chrome e Firefox ajudam aqui, mostrando os tempos de resposta da página.
Também verificamos subdomínios. Por exemplo, existe uma determinada loja online, abc.com, e ela possui um subdomínio admin.abc.com. Provavelmente, este é um painel de administração com autorização, mas se você sobrecarregá-lo, poderá criar problemas para o recurso principal.
O site pode ter um subdomínio api.abc.com. Muito provavelmente, este é um recurso para aplicativos móveis. O aplicativo pode ser encontrado na App Store ou Google Play, instalar um ponto de acesso especial, dissecar a API e registrar contas de teste. O problema é que muitas vezes as pessoas pensam que qualquer coisa protegida por autorização é imune a ataques de negação de serviço. Supostamente a autorização é o melhor CAPTCHA, mas não é. É fácil criar de 10 a 20 contas de teste, mas ao criá-las, temos acesso a funcionalidades complexas e indisfarçáveis.
Naturalmente, olhamos para o histórico, para robots.txt e WebArchive, ViewDNS, e procuramos versões antigas do recurso. Às vezes acontece que os desenvolvedores lançaram, digamos, mail2.yandex.net, mas a versão antiga, mail.yandex.net, permanece. Este mail.yandex.net não é mais suportado, os recursos de desenvolvimento não são alocados para ele, mas continua consumindo o banco de dados. Assim, usando a versão antiga, você pode usar efetivamente os recursos do backend e tudo o que está por trás do layout. É claro que isso nem sempre acontece, mas ainda encontramos isso com bastante frequência.
Naturalmente, analisamos todos os parâmetros da solicitação e a estrutura dos cookies. Você pode, digamos, despejar algum valor em uma matriz JSON dentro de um cookie, criar muitos aninhamentos e fazer o recurso funcionar por um tempo excessivamente longo.

Carga de pesquisa

A primeira coisa que vem à mente ao pesquisar um site é carregar o banco de dados, já que quase todo mundo tem uma busca, e para quase todo mundo, infelizmente, está mal protegido. Por alguma razão, os desenvolvedores não prestam atenção suficiente à pesquisa. Mas há uma recomendação aqui: você não deve fazer solicitações do mesmo tipo, pois poderá encontrar cache, como é o caso da inundação HTTP.
Fazer consultas aleatórias ao banco de dados também nem sempre é eficaz. É muito melhor criar uma lista de palavras-chave relevantes para a pesquisa. Se voltarmos ao exemplo de uma loja online: digamos que o site vende pneus de automóveis e permite definir o raio dos pneus, o tipo de carro e outros parâmetros. Conseqüentemente, combinações de palavras relevantes forçarão o banco de dados a funcionar em condições muito mais complexas.
Além disso, vale a pena usar a paginação: é muito mais difícil uma busca retornar a penúltima página dos resultados da pesquisa do que a primeira. Ou seja, com a ajuda da paginação você pode diversificar um pouco a carga.
O exemplo abaixo mostra a carga de pesquisa. Percebe-se que desde o primeiro segundo do teste, a uma velocidade de dez solicitações por segundo, o site caiu e não respondeu.

DDoS para o resgate: como conduzimos testes de estresse e carga

Se não houver pesquisa?

Se não houver pesquisa, isso não significa que o site não contenha outros campos de entrada vulneráveis. Este campo pode ser autorização. Hoje em dia, os desenvolvedores gostam de criar hashes complexos para proteger o banco de dados de login de um ataque à tabela arco-íris. Isso é bom, mas esses hashes consomem muitos recursos da CPU. Um grande fluxo de autorizações falsas leva à falha do processador e, como resultado, o site para de funcionar.
A presença no site de todos os tipos de formulários para comentários e feedback é motivo para enviar textos muito grandes para lá ou simplesmente criar uma inundação massiva. Às vezes, os sites aceitam arquivos anexados, inclusive no formato gzip. Nesse caso, pegamos um arquivo de 1 TB, compactamos em vários bytes ou kilobytes usando gzip e enviamos para o site. Depois é descompactado e obtém-se um efeito muito interessante.

API de descanso

Gostaria de prestar um pouco de atenção a serviços populares como a API Rest. Proteger uma API Rest é muito mais difícil do que um site normal. Mesmo métodos triviais de proteção contra força bruta de senha e outras atividades ilegítimas não funcionam para a API Rest.
A API Rest é muito fácil de quebrar porque acessa o banco de dados diretamente. Ao mesmo tempo, a falha de tal serviço acarreta consequências bastante graves para os negócios. O fato é que a API Rest costuma ser utilizada não apenas para o site principal, mas também para o aplicativo mobile e alguns recursos internos do negócio. E se tudo isso falhar, o efeito será muito mais forte do que no caso de uma simples falha no site.

Carregando conteúdo pesado

Se formos solicitados a testar algum aplicativo comum de página única, página de destino ou site de cartão de visita que não tenha funcionalidades complexas, procuramos conteúdo pesado. Por exemplo, imagens grandes que o servidor envia, arquivos binários, documentação em pdf - tentamos baixar tudo isso. Esses testes carregam bem o sistema de arquivos e obstruem os canais e, portanto, são eficazes. Ou seja, mesmo que você não desligue o servidor, baixando um arquivo grande em baixas velocidades, você simplesmente obstruirá o canal do servidor alvo e então ocorrerá uma negação de serviço.
Um exemplo desse teste mostra que a uma velocidade de 30 RPS o site parou de responder ou produziu o 500º erro de servidor.

DDoS para o resgate: como conduzimos testes de estresse e carga

Não se esqueça de configurar servidores. Muitas vezes você pode descobrir que uma pessoa comprou uma máquina virtual, instalou o Apache lá, configurou tudo por padrão, instalou um aplicativo PHP e abaixo você pode ver o resultado.

DDoS para o resgate: como conduzimos testes de estresse e carga

Aqui a carga foi até a raiz e foi de apenas 10 RPS. Esperamos 5 minutos e o servidor travou. É verdade que não se sabe completamente por que ele caiu, mas supõe-se que ele simplesmente tinha memória demais e, portanto, parou de responder.

Baseado em onda

Nos últimos dois anos, os ataques de ondas tornaram-se bastante populares. Isso se deve ao fato de que muitas organizações compram determinados hardwares para proteção DDoS, o que requer um certo tempo para acumular estatísticas para começar a filtrar o ataque. Ou seja, eles não filtram o ataque nos primeiros 30-40 segundos, pois acumulam dados e aprendem. Assim, nesses 30-40 segundos você pode lançar tanto no site que o recurso ficará parado por muito tempo até que todas as solicitações sejam esclarecidas.
No caso do ataque abaixo, houve um intervalo de 10 minutos, após o qual chegou uma nova porção modificada do ataque.

DDoS para o resgate: como conduzimos testes de estresse e carga

Ou seja, a defesa aprendeu, começou a filtrar, mas chegou uma porção nova e completamente diferente do ataque, e a defesa voltou a aprender. Na verdade, a filtragem para de funcionar, a proteção torna-se ineficaz e o site fica indisponível.
Os ataques de ondas são caracterizados por valores muito elevados no pico, podendo chegar a cem mil ou um milhão de solicitações por segundo, no caso do L7. Se falarmos sobre L3 e 4, então pode haver centenas de gigabits de tráfego ou, respectivamente, centenas de mpps, se contarmos em pacotes.
O problema com tais ataques é a sincronização. Os ataques vêm de uma botnet e exigem um alto grau de sincronização para criar um pico único muito grande. E esta coordenação nem sempre funciona: às vezes o resultado é uma espécie de pico parabólico, o que parece um tanto patético.

Não apenas HTTP

Além do HTTP em L7, gostamos de explorar outros protocolos. Como regra, um site normal, especialmente uma hospedagem regular, possui protocolos de e-mail e MySQL em destaque. Os protocolos de correio estão sujeitos a menos carga do que os bancos de dados, mas também podem ser carregados com bastante eficiência e acabar com uma CPU sobrecarregada no servidor.
Tivemos bastante sucesso ao usar a vulnerabilidade SSH 2016. Agora esta vulnerabilidade foi corrigida para quase todos, mas isso não significa que a carga não possa ser enviada para SSH. Pode. Há simplesmente uma carga enorme de autorizações, o SSH consome quase toda a CPU do servidor e então o site entra em colapso com uma ou duas solicitações por segundo. Conseqüentemente, essas uma ou duas solicitações baseadas nos logs não podem ser distinguidas de uma carga legítima.
Muitas conexões que abrimos em servidores também permanecem relevantes. Anteriormente, o Apache era culpado disso, agora o nginx é realmente culpado disso, já que geralmente é configurado por padrão. O número de conexões que o nginx pode manter abertas é limitado, então abrimos esse número de conexões, o nginx não aceita mais uma nova conexão e como resultado o site não funciona.
Nosso cluster de teste possui CPU suficiente para atacar o handshake SSL. Em princípio, como mostra a prática, às vezes os botnets também gostam de fazer isso. Por um lado, está claro que não se pode prescindir do SSL, por causa dos resultados do Google, da classificação, da segurança. Por outro lado, o SSL infelizmente tem um problema de CPU.

L3 e 4

Quando falamos de um ataque nos níveis L3 e 4, geralmente estamos falando de um ataque no nível do link. Tal carga é quase sempre distinguível de uma carga legítima, a menos que seja um ataque de inundação SYN. O problema com os ataques de inundação SYN para ferramentas de segurança é o seu grande volume. O valor máximo de L3&4 foi de 1,5-2 Tbit/s. Este tipo de tráfego é muito difícil de processar mesmo para grandes empresas, incluindo Oracle e Google.
SYN e SYN-ACK são pacotes usados ​​ao estabelecer uma conexão. Portanto, é difícil distinguir o SYN-flood de uma carga legítima: não está claro se este é um SYN que veio para estabelecer uma conexão ou parte de um Flood.

inundação de UDP

Normalmente, os invasores não possuem os recursos que temos, portanto, a amplificação pode ser usada para organizar ataques. Ou seja, o invasor verifica a Internet e encontra servidores vulneráveis ​​ou configurados incorretamente que, por exemplo, em resposta a um pacote SYN, respondem com três SYN-ACKs. Ao falsificar o endereço de origem do endereço do servidor de destino, é possível aumentar a potência em, digamos, três vezes com um único pacote e redirecionar o tráfego para a vítima.

DDoS para o resgate: como conduzimos testes de estresse e carga

O problema com as amplificações é que elas são difíceis de detectar. Exemplos recentes incluem o caso sensacional do memcached vulnerável. Além disso, agora existem muitos dispositivos IoT, câmeras IP, que também são configurados principalmente por padrão, e por padrão são configurados incorretamente, e é por isso que os invasores costumam atacar por meio de tais dispositivos.

DDoS para o resgate: como conduzimos testes de estresse e carga

Inundação SYN difícil

O SYN-flood é provavelmente o tipo de ataque mais interessante do ponto de vista do desenvolvedor. O problema é que os administradores de sistema costumam usar o bloqueio de IP para proteção. Além disso, o bloqueio de IP afeta não apenas os administradores de sistemas que atuam por meio de scripts, mas também, infelizmente, alguns sistemas de segurança que são adquiridos por muito dinheiro.
Esse método pode se transformar em um desastre, pois se os invasores substituirem os endereços IP, a empresa bloqueará sua própria sub-rede. Quando o Firewall bloqueia seu próprio cluster, a saída falhará nas interações externas e o recurso falhará.
Além disso, não é difícil bloquear a sua própria rede. Se o escritório do cliente possui uma rede Wi-Fi, ou se o desempenho dos recursos é medido por meio de diversos sistemas de monitoramento, então pegamos o endereço IP desse sistema de monitoramento ou do Wi-Fi do escritório do cliente e o utilizamos como fonte. No final, o recurso parece estar disponível, mas os endereços IP de destino estão bloqueados. Assim, a rede Wi-Fi da conferência HighLoad, onde está a ser apresentado o novo produto da empresa, pode ser bloqueada, o que acarreta determinados custos empresariais e económicos.
Durante os testes, não podemos utilizar amplificação através do memcached com quaisquer recursos externos, pois existem acordos para enviar tráfego apenas para endereços IP permitidos. Assim, utilizamos amplificação através de SYN e SYN-ACK, quando o sistema responde ao envio de um SYN com dois ou três SYN-ACKs, e na saída o ataque é multiplicado por duas ou três vezes.

Ferramentas

Uma das principais ferramentas que usamos para carga de trabalho L7 é o Yandex-tank. Em particular, um fantasma é usado como arma, além de existirem vários scripts para gerar cartuchos e analisar os resultados.
Tcpdump é usado para analisar o tráfego de rede e Nmap é usado para analisar o servidor. Para criar a carga no nível L3 e 4, são usados ​​OpenSSL e um pouco de nossa própria magia com a biblioteca DPDK. DPDK é uma biblioteca da Intel que permite trabalhar com uma interface de rede ignorando a pilha do Linux, aumentando assim a eficiência. Naturalmente, usamos DPDK não apenas no nível L3 e 4, mas também no nível L7, porque nos permite criar um fluxo de carga muito alto, na faixa de vários milhões de solicitações por segundo de uma máquina.
Também usamos determinados geradores de tráfego e ferramentas especiais que escrevemos para testes específicos. Se nos lembrarmos da vulnerabilidade no SSH, então o conjunto acima não pode ser explorado. Se atacarmos o protocolo de correio, usaremos utilitários de correio ou simplesmente escreveremos scripts neles.

Descobertas

Como conclusão gostaria de dizer:

  • Além dos testes de carga clássicos, é necessário realizar testes de estresse. Temos um exemplo real onde o subcontratado de um parceiro realizou apenas testes de carga. Mostrou que o recurso pode suportar a carga normal. Mas então apareceu uma carga anormal, os visitantes do site começaram a usar o recurso de maneira um pouco diferente e, como resultado, o subcontratado desistiu. Assim, vale a pena procurar vulnerabilidades mesmo que você já esteja protegido contra ataques DDoS.
  • É necessário isolar algumas partes do sistema de outras. Se você fizer uma pesquisa, precisará movê-la para máquinas separadas, ou seja, nem mesmo para o Docker. Porque se a pesquisa ou autorização falhar, pelo menos algo continuará funcionando. No caso de uma loja online, os usuários continuarão encontrando produtos no catálogo, saindo do agregador, comprando se já estiverem autorizados ou autorizando via OAuth2.
  • Não negligencie todos os tipos de serviços em nuvem.
  • Use CDN não apenas para otimizar atrasos de rede, mas também como meio de proteção contra ataques de esgotamento de canal e simplesmente inundação de tráfego estático.
  • É necessária a utilização de serviços de proteção especializados. Você não pode se proteger de ataques L3 e 4 no nível do canal, porque provavelmente você simplesmente não possui um canal suficiente. Também é improvável que você lute contra ataques L7, pois eles podem ser muito grandes. Além disso, a busca por pequenos ataques ainda é prerrogativa de serviços especiais, algoritmos especiais.
  • Atualize regularmente. Isso se aplica não apenas ao kernel, mas também ao daemon SSH, especialmente se você os tiver abertos externamente. Em princípio, tudo precisa ser atualizado, porque é improvável que você consiga rastrear certas vulnerabilidades por conta própria.

Fonte: habr.com

Adicionar um comentário