Cuando un cerdo no es suficiente, monta una granja (Optimización de IDS alto tráfico)
No, no estamos hablando de dejar esta vida ajetreada de las ciudades e irnos al campo a vivir y alimentarnos de lo que cultivamos y criamos. Tampoco hablamos de “invertir” nuestro tiempo libre en juegos de una determinada red social para aprender las labores del campo. Este post viene a explicar el proceso que hemos seguido para optimizar el rendimiento de un sistema de detección de intrusos (IDS) en redes con una tasa de tráfico alta.
Hace tiempo se nos propuso preparar para un cliente un sistema de detección de intrusos de alto rendimiento, capaz de procesar una gran cantidad de tráfico totalmente heterogéneo. Así que preparamos una máquina con muy buenas prestaciones para asegurarnos que, por hardware, no iba a ser; a saber, un procesador de 6 cores con 4 GB de memoria RAM, tarjetas Gigabit Ethernet y un sistema NAS para albergar toda la información generada en una red que, suponíamos, iba a ser muy complicada de manejar por la cantidad, la variedad y la naturaleza de su tráfico.
Se optó por una de las soluciones más extendidas en los sistemas de detección de intrusos de código abierto: Snort.
El primer escenario que planteamos consistía en conectar la máquina directamente al firewall a un puerto donde se hacía Port Mirroring con Snort escuchando todo ese tráfico, enviando las alertas a una base de datos MySQL ubicada en la misma máquina, y utilizar BASE para gestionarlas. Pronto nos dimos cuenta de que una máquina con Snort procesando entre 600 y 800 Mbps de tráfico y enviando tal cantidad de alertas necesitaba un buen proceso de puesta a punto.
Antes de nada, lo primero que se definió fue cómo íbamos a evaluar que el sistema estuviera trabajando como se esperaba, así que se configuraron los preprocesadores encargados de generar información sobre el rendimiento: Preprocessor Profiling para ver estadísticas de uso y tiempo de preprocesadores y Rule Profiling para las reglas. A continuación se puede ver las líneas de configuración:
Cita:
## PROFILE#
Preprocesadores
config profile_preprocs: print all, sort avg_ticks,
filename /opt/snort/preprocs_20-avg_stats.log append
#Reglas
config profile_rules: print all, sort matches,
filename /opt/snort/rules_20-avg_stats.log append
Con el módulo Perfmon descubrimos que se estaban descartando entre el 50 y el 70 por cierto de los paquetes que pasaban por la red. Una cifra un tanto desoladora. ¿Qué estaba ocurriendo? ¿Dónde estaba el problema de rendimiento? Hacía falta averiguar por qué se descartaban tantos paquetes y dónde (en qué punto) teníamos el cuello de botella. Empezamos por investigar en la interfaz física o el kernel.
Cita:
eth0
Link encap:Ethernet Hwaddd xx:xx:xx:xx:xx:xx
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:25212974798 errors:0 dropped:0 overruns:0 frame:0
TX packets:6 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:19297324454191 (19.2 TB) TX bytes:4303988140 (4.3 GB)
Interrupt:40 Memory:f2000000-f2012800
Con un simple ifconfig, cuyo resultado se muestra en la captura anterior, se pueden apreciar dos cosas: que efectivamente el kernel no está descartando paquetes (ya que el campo dropped de la tarjeta estaba a cero) y que la cantidad de tráfico que se procesa es realmente elevado (queda para más adelante del estudio, averiguar por qué se ha enviado 4′3 GB de tráfico por una tarjeta que no tiene IP).
Cabe destacar que toda la información generada por Snort se envía a una partición ubicada en la NAS para que, en caso de haber un fallo en el IDS, no se perdiera toda esa información que posteriormente pueda servir para investigar ataques o preparar estadísticas. Descartado como origen del problema la tarjeta de red y viendo que la CPU estaba constantemente al 100%, supusimos que el problema era que Snort no era capaz de procesar tanto tráfico. Así que decidimos tomar medidas.
En resumen: Snort no era capaz de absorber y analizar tal cantidad de tráfico a pesar de estar la CPU (sólo una) al 100%, llegando a descartar entre el 50 y el 70 por ciento del tráfico; el cuello de botella no se encontraba en la tarjeta ya que no perdía paquetes y a su vez se estaban generando del orden de cuatro millones de alertas al día.
Hasta aquí, la primera parte de este artículo. Se insta al lector a proponer ideas o cuestiones que conduzcan a la identificación real del problema (o ayuden a ello) o a la resolución del mismo. En el siguiente artículo veremos qué acciones se tomaron al respecto y cuáles fueron los resultados.
Por Nero Belda en http://www.securityartwork.es/2010/10/20/cuando-un-cerdo-no-es-suficiente-monta-una-granja/?utm_source=feedburner&utm_medium=feed&utm_campaig n=Feed%3A+SecurityArtWork+%28Security+Art+Work%29
Cuando un cerdo no es suficiente, monta una granja (2ª parte)
Después de una semana para dejar pensar a nuestros lectores, seguimos con el artículo sobre la implantación de un sistema IDS en un entorno con una tasa de tráfico muy elevada.
Nos habíamos quedado en un momento donde la tasa de tráfico era tan elevada que, aunque la tarjeta no estaba perdiendo tráfico, Snort no era capaz de procesar todos los paquetes. Teniendo en cuenta la carga de CPU en el sistema, y revisando la documentación de Snort donde se indica que esta aplicación no es multi-hilo, no quedaba otra opción que montar la granja; es decir, levantar varias instancias de Snort y repartir el tráfico para que cada una de ellas analizara una tasa menor. Suponíamos que íbamos a conseguir un buen resultado ya que sólo se estaba utilizando un único core al 100% mientras que el resto no se utilizaba.
Para conseguir esto se deben tener en cuenta varios aspectos para que no entren en conflicto diferentes instancias en un mismo sistema. En resumen, se deben crear filtros BPF para especificar el tráfico que procesará cada instancia, puede haber uno o varios archivos de configuración, debe especificarse un sufijo diferente para el pidfile de cada instancia, debe especificarse un identificador (id) en cada instancia a la hora de escribir en la base de datos y un directorio diferente para almacenar los logs.
Vayamos por partes. El BPF (Berkeley Packet Filter) proporciona una interfaz de comunicación directa en la capa de enlace de datos mediante los cuales además se puede definir cuáles, de todos los paquetes que llegan a la interfaz, queremos procesar, reduciendo así los requisitos de CPU, el espacio del buffer necesario y la pérdida de paquetes. Se utiliza la misma nomenclatura que en otros filtros utilizados, como el conocido tcpdump. Mostramos una línea de ejemplo:
Cita:
net 192.168.2.0/24 or net 172.16.0.0/16
Por tanto, se crearon cuatro archivos BPF con su configuración correspondiente pasándose como parámetro a Snort con la opción “-F bpf_file”. Tres de ellos contemplaban una parte de todo el rango a monitorizar mientras que el cuarto era la negación de la suma de los otros. Con esto conseguimos segregar el tráfico en segmentos de red con tasas similares para que fuera más manejable.
Para el resto de la configuración, el directorio donde se almacenarán los logs de cada instancia se debe especificar con la opción -l diferente para cada instancia; para especificar un identificador se usa la opción -G (SONDA1, SONDA2, SONDA3 y SONDA4, sin espacios). Para el pidfile se utiliza -R “sufijo”. Una idea conceptual de cómo está montado hasta el momento es la siguiente:
http://www.securityartwork.es/wp-content/uploads/2010/10/snort.jpg
Cuando se pusieron los cuatro Snort a trabajar, se consiguió una reducción significativa de la cantidad de tráfico descartado que se podía apreciar mediante las estadísticas creadas por el preprocesador PerfMon (apunte matemático: el porcentaje total de pérdidas no es igual a la suma de los porcentajes individuales, se debe ponderar por el tráfico procesado por cada Snort). A modo ilustrativo, indicar que si las pérdidas (drops) rondaban el 30%, 10%, 15% y del 20%, el total no era el 75% sino de un 20%, aproximadamente.
Bien, tenemos un 20% de paquetes descartados cuando al principio teníamos un 50-70% y se están utilizando cuatro cores entre el 80-100% en los momentos de mayor tráfico. Un gran avance, pero no era suficiente. Uno de cada cinco paquetes no se procesaba y eso seguía siendo inasumible pero, ¿por qué seguían produciéndose descartes? Daremos una pista: cuando se interactuaba con la base de datos mediante BASE, los descartes aumentaban.