¿Cómo organizar DDoS para buenos propósitos?

imagen


Antes del lanzamiento de un nuevo servicio, sería bueno asegurarse de que funciona de acuerdo con nuestras expectativas y que está disponible independientemente de cuántos clientes lo usen al mismo tiempo.


¿Y cómo reaccionará este servicio si se organiza un ataque DoS distribuido contra él? ¿El recurso está protegido de posibles atacantes?


Para evaluar los posibles riesgos y aumentar la seguridad, tiene sentido llevar a cabo de forma independiente acciones que simulen un ataque DDoS mientras el recurso aún no se haya lanzado para uso masivo.


En este artículo, hablaremos sobre la experiencia de organizar pruebas de carga para servicios DNS y HTTP.


Preparación


Para provocar la generación de una gran cantidad de tráfico de red en el recurso monitoreado, debe usar muchas máquinas virtuales, cada una de las cuales enviará el número máximo de solicitudes al servicio. Si no tiene un centro de datos potente, tiene sentido alquilar temporalmente máquinas virtuales en una nube. Esta idea tiene una característica: debe asegurarse de que la nube no se arrastre, tomando su actividad por las acciones de un atacante.


Al comparar las políticas de varios servicios en la nube (alguien despiadadamente prohíbe una cuenta con la que, presumiblemente, se tomaron medidas que llevaron a una falla de recursos) con respecto a las pruebas de carga utilizando su funcionalidad, decidimos detenernos en Amazon Web Services (AWS). Sus documentos indican que AWS permite pruebas de carga, pero solicita aprobación enviando un correo electrónico a una dirección específica.


Armonización de las pruebas de resistencia.


Enviamos un mensaje donde hablamos brevemente sobre nuestras intenciones, y recibimos un formulario que debe completarse:


Customer ID: Customer Name: Email Address: AWS Account ID load test will be performed from: Does the customer have an NDA? Target Data EC2 Resources: Cloudfront Distribution: API Gateway / Lambda ID: ELB Names: Non-AWS Target: Region (please list all regions in scope for testing): Source Data: IP Addresses: Source Account ID: Regions involved: Testing Parameters: How much traffic do you plan to generate by region during testing? What is your expected peak load from source by region? (ie xx Gbps) What is your expected peak load at destination? (ie xx Gbps) Are you testing traffic outbound from EC2, inbound into EC2, or both? Are you testing traffic outbound (egress) from EC2, inbound (ingress) into EC2, or both: Egress. What is your expected peak load from source by region? (ie xx Gbps) Ingress. What is your expected peak load from source by region? (ie xx Gbps) Start Date: End Date: Finite testing details including timeline of testing: Summary of Test: Testing Timelines by phase including rps, pps, and Gbps: Peak bandwidth for each source IP: Tools Used for each phase of test: Types of testing to be performed for each phase of the request: What criteria/metrics will you monitor to ensure the success of this test? Who is performing the Load Test? (Please provide contact details): Does the tester have an NDA? Testing Security Do you have a way to monitor the data traffic for the duration of the test to verify bandwidth limits do not exceed approved rates? Do you have a way to immediately stop the traffic if we/you discover any issue? 2 Emergency contact names and phone numbers: 

Hay varios matices:


  1. Nos preguntan a quién "broncearemos". ¿Tenemos derecho a esto? Decimos que este es nuestro recurso (aparentemente, nadie verifica si esto es así) y que las pruebas son completamente consistentes.


  2. Necesitamos designar cuánto tráfico crearemos en cada una de las regiones. Durante la correspondencia, descubrimos que cada región tiene su propio límite en la cantidad de tráfico de red. En total, se les permite solicitar 645 Gb / s. Consideramos cuánto se necesita para el ataque y seleccionamos las regiones de tal manera que se obtenga el valor necesario.


  3. Es necesario describir a qué hora se llevará a cabo el ataque, cuánto durará y cómo crecerá su poder. En forma libre, pero con suficiente detalle hablamos de nuestros planes. El ataque se lleva a cabo con un aumento gradual de la potencia, por lo que pintamos qué etapas tendrá la prueba y qué potencia máxima se espera en cada una de ellas. La fecha del ataque puede omitirse hasta un día; es muy posible indicar un rango de dos a tres semanas.


  4. Y sin falta, estamos haciendo todo lo posible para asegurarnos de que nos comportaremos bien, monitorear cuidadosamente el progreso de las pruebas y detenerlo en la primera solicitud si es necesario.



Lo más probable es que, en respuesta al formulario completado, soliciten alguna aclaración, por lo que nos corresponde y respondemos preguntas hasta que obtengamos permiso para realizar la prueba.


Se tarda unos tres días hábiles en completar el proceso de aprobación si se responde con prontitud.


Preparación de infraestructura


Después de las aprobaciones, nos enfrentamos a la necesidad de preparar la infraestructura para las pruebas. El hecho es que durante el control tendremos que:


• incluir una instancia;


• lanzar un ataque de prueba;


• recopilar estadísticas sobre el progreso;


• detener el ataque de prueba;


• cambiar la dirección IP;


• apague la instancia.


Crear imagen de instancia


Seleccionar tipo de instancia


Primero, creemos una imagen de AWS que contendrá las herramientas y los scripts necesarios para la administración. El primer paso es elegir qué instancia alquilar. Estudiamos las características de diferentes tipos de instancias: observamos el precio, la cantidad de tráfico máximo, la potencia de la CPU (esto último es importante, porque el tráfico es creado por las capacidades del procesador después de todo), luego probamos el rendimiento real y el número máximo de solicitudes. Según nuestras estimaciones, las t3.small instancias son las más convenientes para la prueba, pero aquí todos eligen su gusto.


Las características de las instancias se pueden encontrar aquí . También puede seleccionar y comparar instancias aquí .


Solicitud de límite


Debe pensar de antemano cuántas instancias participarán en la prueba. El hecho es que Amazon proporciona a cada región sus límites en el número de instancias. Si tiene la sensación de que necesitará más instancias de las que están disponibles por defecto, entonces debe solicitar un aumento en el límite lo antes posible. Para hacerlo, vaya a la sección Soporte , cree una llamada de tipo Aumento del límite de servicio. El tiempo de procesamiento de una solicitud puede ser diferente: alguien responde al día siguiente, proporcionando tantas entidades como se le solicite, alguien dice que no permitirá que se ejecuten más de N instancias. Hubo regiones que respondieron a la solicitud durante aproximadamente un mes.


Ajuste de rendimiento


A continuación, debe crear una imagen de instancia que se iniciará durante la prueba. Para hacer esto, activamos la instancia del tipo seleccionado, hacemos todos los ajustes y luego guardamos lo que sucedió como una imagen (en el menú Acciones, donde puede habilitar la instancia, así como la funcionalidad para crear una Imagen Crear Imagen).


Necesitamos obtener el máximo tráfico saliente de cada instancia, por lo que primero optimizamos la configuración de red y memoria para nuestra tarea en la instancia.


Para hacer esto, realice la configuración en el archivo /etc/sysctl.conf :


• Aumente el rango de puertos locales y reduzca el tiempo que pasan los sockets en el estado FIN_WAIT:


 net.ipv4.ip_local_port_range = 1024-65535 ( : 32768-61000) net.ipv4.tcp_fin_timeout = 10 ( : 60) 

El rango de puerto local determina el número máximo de sockets salientes que un host puede crear desde una IP específica.


Con la configuración predeterminada (61,000–32,768), se obtienen 28,233 sockets. Con nuevas configuraciones - 64 500.


Fin_timeout define el tiempo mínimo que los sockets salientes pueden estar en estado FIN_WAIT.


Si se especifican valores predeterminados, el sistema no puede proporcionar más de (61,000–32,768) / 60 = 470 sockets por segundo.


Al aumentar port_range y disminuir fin_timeout, podemos afectar la capacidad del sistema para generar más conexiones salientes.


• Reutilicemos los sockets en el estado TIME_WAIT cuando finalicen los gratuitos:


 net.ipv4.tcp_tw_reuse = 1 

Establecer la opción anterior (que está deshabilitada de manera predeterminada) ayuda a minimizar la pérdida de conexiones "inactivas" ya realizadas.


Muy detallado sobre TIME_WAIT se describe en este artículo .


• Active la opción tcp_timestamps para que funcione la opción tcp_tw_reuse anterior:


 net.ipv4.tcp_timestamps = 1 –   `tcp_timestamps`     tcp_tw_reuse 

• Otras opciones:


 net.ipv4.tcp_max_tw_buckets = 720000 –       TIME_WAIT net.ipv4.tcp_keepalive_time = 600 –  - keepalive- net.ipv4.tcp_keepalive_probes = 3 –   keepalive- net.ipv4.tcp_keepalive_intvl = 10 –     keepalive- net.ipv4.tcp_window_scaling = 1 –   TCP- net.ipv4.tcp_mem = 8192 131072 196304 –     TCP- net.ipv4.udp_mem = 8192 131072 196304 –     udp- net.ipv4.tcp_slow_start_after_idle=0 –  Slow-Start Restart net.core.wmem_default = 31457280 –         net.core.wmem_max = 33554432 –        net.core.somaxconn = 65535 –        net.core.netdev_max_backlog = 65535 –          vm.swappiness = 30 –    vm.dirty_ratio = 50 –     50 %  vm.pagecache = 90 –     

Probar guiones de ataque


1. ataque DNS


Una de las principales tareas de las pruebas es evaluar el rendimiento de los servidores DNS. Es decir, los servidores DNS pueden convertirse en el cuello de botella de la tolerancia a fallas de un sitio, porque incluso si el servicio más estable no está disponible si hay problemas con DNS. Para crear una carga en los servidores DNS, generaremos muchas consultas DNS diferentes. Las solicitudes deben ser válidas y requieren la mayor respuesta posible y más larga del servidor DNS.


La utilidad DNSPerf es adecuada para generar dicho tráfico.


DNSPerf es una herramienta de prueba de rendimiento de DNS simple, flexible y gratuita. Está diseñado principalmente para servidores DNS autorizados, pero también se puede usar para medir el rendimiento de los servidores de almacenamiento en caché.


En nuestro caso, se cargan servidores DNS autorizados que sirven a una zona: example.com.


Para DNSPerf, primero preparamos un archivo con las solicitudes dns_queries.txt (principalmente CUALQUIERA para aumentar el tiempo y el tamaño de la respuesta del servidor DNS):


 #dns_queries.txt example.com ANY www.example.com ANY test.example.com ANY static.example.com ANY example.com  www.example.com  test.example.com MX 

Ejemplo de ejecución de la utilidad:


 dnsperf -s TARGET_IP -d dns_queries.txt -c 100 -n 100 -s =  IP- -d =      .   – stdin -c =   .         -n =  «»   . 

2. Ataque a ICMP


La siguiente etapa de prueba es evaluar la resistencia a una gran cantidad de tráfico ICMP. Dado que, por razones técnicas, los servidores a menudo necesitan poder responder a las solicitudes de ping, existe la posibilidad de un ataque DDoS mediante solicitudes de ping. Además de especificar configuraciones que excluyen la posibilidad de ping-to-death , debe asegurarse de que los servidores sean resistentes a las cargas máximas de ICMP. Para crear tales cargas, es mejor usar la conocida utilidad hping3 , que le permite ajustar la cantidad de solicitudes, el intervalo entre envíos y el tamaño del paquete.


Ejemplo de ejecución de la utilidad:


 hping3 -i u1000 -d 1500 -c 100000 -1 TARGET_IP -i u100 =     (uX for X microseconds) -d 1500 =    -c 1000000 =     -1 =  ICMP 

3. ataque HTTP


Ahora verificamos la resistencia al estrés, la funcionalidad principal del servicio: procesar el tráfico HTTP (S). Una de las herramientas más flexibles y fáciles para generar tráfico HTTP es el asedio . Siege es una utilidad multiproceso de código abierto diseñada para probar el rendimiento de un recurso web.


Al igual que DNSPerf, el sitio le permite cargar el servidor con solicitudes de un número determinado de usuarios virtuales (la emulación del usuario se lleva a cabo utilizando un puerto separado), así como utilizar un conjunto predefinido de solicitudes. Esto es muy conveniente, ya que puede incluir las consultas más intensivas en recursos en la prueba.


Ejemplo de ejecución de la utilidad:


 siege -b -c 100 -f test_urls.txt -b =   ( benchmark) -c =   .         -f =    

Formato de contenido test_urls.txt :


 http://example.com/site/login POST login=username&password=test http://example.com/site/client POST useragent=Mozilla&version=123&date=24May http://example.com/site/order POST user=username&company=ooo&phone=812345678 

Como puede ver, las pruebas se llevaron a cabo utilizando principalmente solicitudes POST que requieren procesamiento en el lado del servidor y ocupan la mayor cantidad de recursos en comparación con otros tipos de solicitudes.


Ninguna de las opciones utiliza suplantación de IP, ya que Amazon no lo permite. Independientemente de lo que se especifique src_IP en el paquete, se cambiará al correcto al salir de la instancia.


Todas las solicitudes generadas deben ser legítimas, sin oleadas de tráfico saliente sin respuesta, ya que la política DDoS de Amazon es bastante estricta. Incluso una prueba de esfuerzo coordinada toma un mínimo de varios días para comunicarse con el soporte técnico, y en las primeras acciones "maliciosas" obtenemos la prohibición del puerto del que salió el tráfico, y el requisito debe explicarse de inmediato.


Scripts para lanzar ataques


Para la gestión remota de pruebas, prepararemos scripts de bash (dns.sh, ping.sh, http.sh) que inician el tipo de ataque deseado y los archivos de carga útil (test_urls.txt, valid_dns_queries.txt).


Cuando cargamos todo esto en la imagen de AWS (desde la cual se crearán todas las instancias), cada prueba se puede ejecutar de forma remota con el comando del siguiente formato:


 ssh instance-amazon 'sudo <stress-script>.sh start <params> &>>stress.log &' 

El script del tipo requerido se especifica como stress-script.sh, y los parámetros son los parámetros correspondientes. En el archivo stress.log, rastrearemos el resultado de la utilidad en ejecución. Para mayor comodidad, utilizaremos diferentes registros para diferentes utilidades: dns.log, ping.log, http.log.


Ejemplo de script dns.sh :


 #!/bin/bash if [[ ! "$1" =~ ^(start|stop|status)$ ]]; then echo "nothing to do: need argument for stop,start or status" exit 1 fi if [[ "$1" = "start" ]]; then shift dnsperf $@ fi if [[ "$1" = "stop" ]]; then kill $(pidof dnsperf) fi if [[ "$1" = "status" ]]; then if [[ ! "$(pidof dnsperf)" = "" ]]; then echo "dnperf is running with PID $(pidof dnsperf)" ps aux | grep dnsperf else echo "dnsperf is not running" fi fi 

Como se puede ver en el código, el script se puede iniciar y detener, así como verificar el estado (en ejecución / no en ejecución).


Las secuencias de comandos para las pruebas ICMP y HTTP se construyen de la misma manera, comenzando hping3 y siege, respectivamente, con la cadena de parámetros pasada a través del argumento.


Ejemplos de comandos:


 ssh instance-amazon 'sudo dns.sh start -s TARGET_IP -d valid_dns_queries.txt -c 1 -n 100 &>>dns.log &' ssh instance-amazon 'sudo ping.sh start -i u1000 -d 1500 -c 100000 -1 TARGET_IP &>>ping.log &' ssh instance-amazon 'sudo http.sh start -b -c 100 -f test_urls.txt &>> http.log &' 

Supervisar guiones


Para evaluar el tráfico saliente y el estado de la infraestructura de prueba, necesitamos una herramienta de monitoreo. Por razones de simplicidad y ahorro de recursos, utilizamos iptables. Para hacer esto, escribiremos un script que cuente la cantidad de MB enviados y lo colocaremos en la imagen de AWS:


 #iptables.sh sudo iptables -N TRAFFIC_OUT sudo iptables -A TRAFFIC_OUT -p tcp sudo iptables -A TRAFFIC_OUT -p udp sudo iptables -A TRAFFIC_OUT -p icmp sudo iptables -A OUTPUT -j TRAFFIC_OUT sudo iptables-save 

El script crea una nueva cadena TRAFFIC_OUT y le agrega filtros para los protocolos necesarios: tcp, udp, icmp.


El reenvío de paquetes a TRAFFIC_OUT se agrega a la cadena OUTPUT.


El comando puede encontrar la cantidad de datos transferidos:


 # iptables -L TRAFFIC_OUT -v -n -x | tail -n 3 | awk '{print $2/1024/1024,"Mb\t\t\t",$3}' : 2.2 Mb tcp 4.4 Mb udp 3.2 Mb icmp 

Instale el script como un servicio. Para hacer esto, cree un archivo tracking.service y muévalo al directorio /etc/systemd/system de nuestra imagen:


 # /etc/systemd/system/monitoring.service [Unit] After=network.target [Service] ExecStart=/usr/local/bin/monitoring.sh [Install] WantedBy=default.target 

Ahora puede agregar el servicio al inicio:


 systemctl enable monitoring.service systemctl start monitoring.service 

Gestión de instancias


Ahora tratemos con la administración de instancias remota (lo más automatizada posible).


Para estos fines, puede usar el mecanismo de AWS CLI : administración de la consola.


Cree una clave secreta (claves de acceso (ID de clave de acceso y clave de acceso secreta)) y configure la consola.


Ahora tenemos acceso a todas las funciones de la cuenta.


La peculiaridad de trabajar con AWS es que todas las acciones se realizan para una región específica y deben repetirse si hay varias regiones involucradas.


Para crear una nueva instancia a partir de la imagen que creamos anteriormente (suponemos que hay una ID-ami pública que usamos en el script), haremos lo siguiente:


  • cree una clave SSH y agréguela a AWS:

 yes n |ssh-keygen -q -t rsa -f $KEYNAME -m pem -N "" > /dev/null chmod 400 $KEYNAME aws ec2 import-key-pair --region $REGION --key-name $KEYNAME --public-key-material file:///$(pwd)/$KEYNAME.pub 

  • cree un grupo de seguridad que permita el acceso a la máquina a través de SSH. De lo contrario, se denegarán las conexiones SSH entrantes:

 SECURITY="ssh-group" aws ec2 create-security-group --region $REGION --group-name $SECURITY --description "Just ssh. Nothing more" IP_RANGE="0.0.0.0/24" aws ec2 authorize-security-group-ingress --region $REGION --group-name $SECURITY --protocol tcp --port 22 --cidr $IP_RANGE 

  • cree una instancia con la clave y el grupo de seguridad creados anteriormente y especifique la ID de la imagen. El número de instancias creadas a la vez puede ser arbitrario:

 IMG='ami-0d0eaed20348a3389' NUM=1 aws ec2 run-instances --region $REGION --image-id $IMG --count $NUM --instance-type t2.micro --key-name $KEYNAME --security-groups default $SECURITY > instances.json 

  • espere hasta que la máquina se inicialice. Esto lleva algo de tiempo: primero obtenemos una respuesta correcta (instancias.json), pero en ese momento la máquina se acaba de crear pero aún no se ha iniciado (por ejemplo, aún no se le ha asignado una dirección IP). Es necesario esperar a que se complete el lanzamiento (por lo general, un minuto es suficiente para esto).

Entonces puede conectarse a través de SSH si conocemos la dirección IP. Simplemente solicite una lista de máquinas que se están ejecutando actualmente. Entre sus parámetros encontramos PublicDnsName o PublicIpAddress.


 aws ec2 describe-instances --region 

A continuación, ejecutamos los comandos SSH, indicando la clave SSH creada anteriormente:


 ssh -I $KEYNAME -oStrictHostKeyChecking=no ubuntu''+ins_dns echo''O'' 

Los comandos SSH le permiten controlar el ataque y obtener toda la información sobre el estado del ataque, ya que proporcionamos a las instancias todos los scripts y herramientas necesarios.


Debe comprender que la mayoría de las defensas contra los ataques de denegación de servicio bloquean la dirección IP desde la que se reciben de manera anómala muchas solicitudes. Por lo tanto, las direcciones IP de las máquinas virtuales deben cambiar constantemente para mantener el poder de ataque.


AWS asigna una nueva dirección IP cada vez que se inicia la máquina. Por lo tanto, para cambiar la IP, debe apagar y volver a encender la máquina (¡no es necesario quitarla!).


La diferencia entre apagar y eliminar es que enviamos diferentes señales. Detener - para apagar, finalizar - para apagar y eliminar de inmediato.


Para monitorear el tráfico entrante de una instancia, utilizamos el siguiente comando con el ID de la instancia: cuando comienza la medición del tráfico, cuando finaliza, durante qué período se suman los valores:


 aws cloudwatch get-metric-statistics --region REGION --namespace AWS/EC2 \ --statistics Sum --metric-name NetworkIn --start-time $STARTTIME --end-time $FINISHTIME --period $PERIOD --dimensions Name=InstanceId,Value=$INCTANCEID 

Servicio de Monitoreo de Disponibilidad


Además, para realizar un ataque, deberá observar si el servicio que estamos probando está activo.


Creamos y ejecutamos el script "ping" más simple que monitorea la disponibilidad de los puertos de destino (53 y 80 en nuestro caso).


Ejemplo de código Python que automatiza la verificación de disponibilidad:


 def http(url): cmd = ['curl', '-w', '"%{time_total}"', '-o', '/dev/null', '-s', url] result = check_output(cmd).decode('utf-8') result = float(json.loads(result)) return result * 1000000 def dns(ip, domain): cmd = ['dig', 'any', '@'+ip, domain ] result = check_output(cmd).decode('utf-8') result = int(result.split('Query time:')[1].split('msec')[0]) return result 

La información recibida se almacena en un archivo de registro, sobre la base de la cual, en función de los resultados del ataque, será posible construir un gráfico de disponibilidad de recursos.


Durante las pruebas, es necesario verificar constantemente el registro de "ping" para no eliminar el recurso por completo e irrevocablemente. Tan pronto como aparezca una degradación significativa y la respuesta a la solicitud tarde demasiado, el ataque debe detenerse.


Si la desaceleración es insignificante y el poder de ataque ha alcanzado el máximo establecido, entonces tiene sentido esperar uno o dos minutos, y si el servicio continúa funcionando sin interrupciones, entonces la verificación se considera exitosa.


Problema financiero


Vale la pena discutir otro tema relacionado con la organización de las pruebas: el costo de todo este evento.


Amazon proporciona información detallada sobre precios, pero debe comprender que tiene que pagar por casi todo. Sin embargo, muchos cálculos pueden ser descuidados. En primer lugar, vale la pena calcular el costo del tráfico (depende de la región y de cuánto se transmitirá la cantidad total de información) y el costo de las instancias de alquiler (pago por minuto). Estos artículos representan aproximadamente el 99% del costo de todo el ataque.


Por lo tanto, el costo del ataque se calcula en cada caso por separado, dependiendo de la potencia máxima de ataque [escala de hostilidades] y el número de lanzamientos planeados.


Desde el punto de vista de la simplificación de los cálculos, es mejor usar una cuenta de Amazon, que se registró hace no más de un año. Entonces, parte de las operaciones serán gratuitas. Lea más sobre los límites de uso gratuito aquí .


Para ilustrar el cálculo del costo de realizar pruebas de carga, digamos que queremos verificar la estabilidad del servidor DNS a una carga de 10 Gb / s.


Sabemos que las herramientas utilizadas y las capacidades de la instancia t3.small lanzada en Mumbai le permiten emitir 500 Mb / s desde una instancia en ejecución. El precio por alquilar una entidad es de $ 0.0224 por hora, por tráfico: $ 0.01093 por 1 GB. Es decir, el pico del ataque significa la operación simultánea de 20 entidades.


Incrementaremos el poder de ataque gradualmente, para esto primero lanzamos una entidad, luego agregamos otra cada 60 s.


La fórmula para calcular el costo toma la forma:


 60  * (   ) + 60  * 0,5 /c * (  ) =       60 . 1 * (    ) + 2 * (    ) + ... + 20 * (    ) =    

Resulta que el costo de un ataque con una capacidad de 10 Gb / s para un servidor DNS es de aproximadamente $ 70. Tenga en cuenta que esta es una estimación aproximada, ya que el volumen de tráfico no se puede predecir con precisión. . , – , .


. .

Source: https://habr.com/ru/post/481756/


All Articles