Zabbix, como herramienta de monitoreo de código abierto, siempre ha sido visto como un software indispensable para observar métricas de infraestructura de Tecnología de la Información y la Comunicación (TIC), sin embargo, su capacidad va más allá de eso, como el monitoreo de aplicaciones y negocios, monitoreo de baseline y detección de anomalías con uso nativo de Machine Learning (ML), casi nunca es visto como un componente capaz de ayudar al mundo de la ciberseguridad.
Por otro lado, tenemos Suricata, un software también de código abierto para la detección y prevención de intrusiones (IDS/IPS) y monitoreo de tráfico de red de alto rendimiento, desarrollado por la Open Information Security Foundation (OISF). Funciona analizando paquetes de red en tiempo real, identificando actividades maliciosas basadas en firmas y análisis de comportamiento.
¿Te has imaginado lo que puede ocurrir si unimos el poder de fuego de las dos herramientas?
De hecho, ni Zabbix ni Suricata son software del tipo SIEM. Sin embargo, en este artículo demostraremos cómo se puede realizar esta integración y cómo tu empresa puede beneficiarse de esos recursos para la misión de monitorear, detectar y responder a eventos de seguridad de la información y cibernética en sus puntos finales.
¡Buena lectura!
Zabbix Agent2, versión 7.0+
Innegablemente, una de las mejoras más significativas que puedo destacar por ahora en términos de Zabbix Agent2, es la increíble capacidad que ha ganado de recopilar hasta 1000 (mil) métricas por cada plugin que ofrece y, esto incluye Log.
Mira:
En esta versión, un monitoreo de logs agresivo como el que necesitamos en esta integración, no será un problema.
Sobre el monitoreo de logs por Zabbix se puede leer en su documentación: 6 Monitoreo de archivos de registro
Suricata
No es la intención explorar en profundidad Suricata en este artículo, pero vamos a entender algunos puntos importantes para nuestra integración, por ejemplo, la diferencia entre alertas y eventos.
Suricata es capaz de analizar varios tipos de eventos y, dependiendo de las reglas trabajadas, pueden generarse alertas (por ejemplo, para lo que realmente se considere un problema/ataque). Para entender qué tipos de eventos es capaz de analizar, basta con consultar su archivo de configuración en /etc/suricata/suricata.yaml (en una instalación estándar en un endpoint Ubuntu 22.04, por ejemplo). En este sentido, se pueden generar varios tipos de logs para ser leídos por Zabbix Agent2.
Un log simple y fácil de analizar se encuentra en /var/log/suricata/fast.log. En este log, independientemente del tipo de evento y regla activa, se registran las alertas detectadas por Suricata.
El log está estandarizado, es fácil de comprender, lo que facilita nuestra tarea de lectura e interpretación por parte de Zabbix.
Veamos un ejemplo:
04/03/2025-14:20:39.103950 [**] [1:2010937:3] ET SCAN Suspicious inbound to mySQL port 3306 [**] [Classification: Potentially Bad Traffic] [Priority: 2] {TCP} 192.168.100.100:35237 -> 192.168.200.200:3306 04/03/2025-14:20:39.103951 [**] [1:2010939:3] ET SCAN Suspicious inbound to PostgreSQL port 5432 [**] [Classification: Potentially Bad Traffic] [Priority: 2] {TCP} 192.168.100.100:35237 -> 192.168.200.200:5432
Estos registros fueron capturados a partir de un intento de scan mediante nmap para 2 puertos específicos del endpoint monitoreado y podrían ser reproducidos de la siguiente manera:
# nmap -p 5432,3306 <192.168.200.200>
Los mensajes que comienzan con «ET» significan «Threats Emergentes» y son reglas importadas a Suricata, como una forma de tunning, por así decirlo.
EVE Log
Un log más completo y estandarizado en formato json sería el /var/log/suricata/eve.json. En este log, Suricata registra todos los tipos de eventos que su configuración puede capturar, pero no necesariamente todos los eventos también son alertas. Por ejemplo, si estoy monitoreando las consultas de tipo DNS que mi endpoint realiza, encontraré eventos del tipo DNS y no necesariamente eso es un problema. Pero podría serlo si, por ejemplo, el dominio consultado es considerado malicioso o aún, un sitio no deseado o no permitido en mi empresa. Ese es un análisis que se debe realizar en otra etapa y no será abordado en este artículo.
Vea un ejemplo de registro de un evento DNS:
{"timestamp":"2025-04-03T14:26:19.713892-0300","flow_id":1094794285608326,"in_iface":"eth0","event_type":"dns","src_ip":"165.227.65.66","src_port":48656,"dest_ip":"67.207.67.3","dest_port":53,"proto":"UDP","pkt_src":"wire/pcap","dns":{"version":2,"type":"answer","id":2188,"flags":"8180","qr":true,"rd":true,"ra":true,"opcode":0,"rrname":"zabbixbook.wafproject.cloud","rrtype":"AAAA","rcode":"NOERROR","authorities":[{"rrname":"wafproject.cloud","rrtype":"SOA","ttl":292,"soa":{"mname":"ns65.domaincontrol.com","rname":"dns.jomax.net","serial":2024112901,"refresh":28800,"retry":7200,"expire":604800,"minimum":600}}]}}
De la misma manera que monitoreamos eventos del tipo DNS, podemos monitorear eventos de SSH, HTTP, FTP, SFTP, DHCP, etc. Entonces, nos concentraremos en el archivo fast.log y trataremos alertas y no las infinitas posibilidades de eventos.
Monitoreando el archivo fast.log
Con la premisa de que se cumplen todos los requisitos de un monitoreo activo, vamos a crear el ítem de monitoreo de logs para el fast.log.
Name: Suricata main fast.log Type: Zabbix agent (active) Key: log[/var/log/suricata/fast.log] Type of information: Log Update interval: 1s History: Do not store
Añade las etiquetas que desees.
No es necesario preprocesar este elemento.
Ten en cuenta que no aplicamos ningún tipo de regex, por lo tanto, todas las líneas de log serán recolectadas por el Zabbix Agent2 en un primer momento, pero dado que no estamos almacenando historial, necesitaremos crear «Dependent items» para extraer los datos que necesitamos.
Entonces, ¿de qué necesitamos y cómo vamos a extraer tales datos?
- Event date: \1
- Event time: \2
- Event rule ID: \3
- Event message: \4
- Event classification: \5
- Event priority: \6
- Event protocol: \7
- Event source IP: \8
- Event source port: \9
- Event destination IP: \10
- Event destination port: \11
Todos estos datos pueden ser extraídos mediante la siguiente expresión regular, cuando se aplica a la pestaña Preprocesamiento:
(\d\d\/\d\d\/\d\d\d\d)-(\d\d:\d\d:\d\d)\.\d+\s+\[\*\*\]\s+\[\d+:(\d+):\d+\]\s(\S+.*?)\s\[\*\*\]\s\[Classification:\s(\S+.*?)\]\s\[Priority:\s(\d)\]\s\{(\w+)\}\s+(\d+.\d+.\d+.\d+):(\d+).*?(\d+.\d+.\d+.\d+):(\d+)
Los colores nos ayudan a diferenciar los grupos de captura y a relacionarlos con los campos enumerados anteriormente. 1 o 2 corresponden al grupo de captura que se utilizará en Zabbix en la pestaña Preprocessing.
Aquí entonces está un ejemplo de uno de los 11 elementos necesarios:
Un ensayo de Widget
Entre los varios arreglos posibles, pensé que una primera visión de estos eventos podría ser generada usando un widget de frontend relativamente nuevo en Zabbix: Historial de ítems. Mira una vista previa del resultado:
Contando los eventos
Un análisis preciso de datos numéricos y no solo de textos. Por eso, vamos a evaluar el mismo log con otra clave de Zabbix: log.count. La idea es tener un cuantitativo de alertas recibidas por minuto y con eso, podremos crear varias otras métricas, tales como promedios, baseline y tasas de anomalía de los eventos (lo cual es un poco extraño, ya que un evento, en realidad, no debería ocurrir).
Name: The number of Suricata alerts Type: Zabbix agent (active) Key: log.count[/var/log/suricata/fast.log] Type of information: Numeric (unsigned) Update interval: 1m History: 1d Trends: 395
Usando un ítem calculado, también podemos obtener el mayor valor de eventos ocurridos a lo largo de una hora y así, generar un puntito en nuestro gráfico que nos ayude a entender, visualmente, la gravedad de la situación:
Comparación entre periodos
En un ejercicio simple, ya podemos comparar la cantidad de eventos ocurridos en la hora actual y los de la hora anterior, obteniendo una variación porcentual, dándonos una idea de cómo está nuestro entorno. Ten en cuenta que también es posible crear comparaciones entre períodos más largos y la lógica sigue siendo prácticamente la misma que veremos a continuación.
Name: Hourly event percentage change Type: Calculated Key: hourly.event.pchange Type of information: Numeric (float)
Fórmula:
((sum(//log.count[/var/log/suricata/fast.log],1h:now/h+1h) - sum(//log.count[/var/log/suricata/fast.log],1h:now/h)) / sum(//log.count[/var/log/suricata/fast.log],1h:now/h)) * 100 Unit: % Update interval: 1m History: 31d Trends: 395
El resultado parcial en un widget de frontend sería:
Eventos por prioridad (priority)
Anteriormente, extrajimos los datos del campo «priority» del log. Como su propio nombre sugiere, la prioridad refleja la gravedad de cada alerta generada, siendo el nivel «1» el más prioritario y a partir de 4, los menos prioritarios.
Con esto en mente, podemos generar una visión consolidada de la última hora desde la perspectiva de los niveles de alertas generados. Para ello, es necesario crear un ítem calculado para cada tipo de severidad disponible.
Atención: el enfoque que utilicé en esta prueba de concepto no refleja el único camino a seguir, por ejemplo, las prioridades podrían ser descubiertas a través de LLD y así, se crearían a medida que se generaran las alertas, sin embargo, solo se prevén 5 o 6 ítems. Entonces, decidí crearlos manualmente.
Name: The number events with priority 1 last hour Type: Calculated Key: countunique.priority.1 Type of information: Numeric (unsigned) Formula: count(//event.priority,1h,"eq",1) Update interval: 1m
Crea más elementos para las otras prioridades, de manera que haya algo como lo siguiente:
En mi caso, creé otro elemento para prioridades por encima de 5:
count(//event.priority,1h,"gt",5)
A continuación, el reflejo en el widget:
La tarea ahora será contabilizar las alertas por categoría y en este caso, utilicé un enfoque diferente: LLD.
Suricata tiene un archivo de configuración con el registro de las categorías posibles. Se realizó la lectura de este archivo y se extrajo únicamente el contenido que nos interesaba (a diferencia de las prioridades, las categorías son más numerosas y sería un trabajo complicado registrarlas manualmente):
Para leer el archivo, utilicé la clave:
vfs.file.contents[/etc/suricata/rules/rules/classification.config]
Y trabajé en el preprocesamiento para dejarlo listo para ser utilizado en un proceso de Discovery:
El javascript en cuestión, tiene el siguiente contenido:
// Remove linhas vazias ou com espaços em branco e retorna o resultado return value.split('\n').filter(function(line) { return line.trim() !== ''; }).join('\n');
Los prototipos de la LLD tendrán este formato:
Y el resultado será algo así:
Y nuestro widget de frontend, esta vez en formato de Doughnut, tendrá la siguiente configuración y formato:
Machine Learning y patrones de comportamiento
Nuestro monitoreo no se basa solo en la lectura de logs, aunque eso sea muy divertido y fácil. Vamos a aplicar una capa de ML para generar el aprendizaje del patrón de comportamiento de nuestros eventos (Baseline monitoring) y buscar anomalías en el ambiente (Anomaly rate).
Las funciones en Zabbix para esto son:
baselinewma trendstl
Las fórmulas no serán insertadas aquí, sino solo los resultados. La razón por la que opté por esto es sencilla: la baseline se genera en función de mi regla de negocio, o mejor dicho, podemos decir qué, cómo y a partir de cuándo observar para generar un baseline. Por lo tanto, mi fórmula puede no aplicarse a su escenario y, además, la documentación de Zabbix es rica para ayudarle en esta comprensión. Lo mismo para Anomaly Rate.
Vea un resultado previo:
Al final, tendremos un dashboard más o menos así:
Detectando Eventos
Hasta ahora, hemos observado los eventos generados por Suricata y creado un panel para ayudar a la capa visual. Sin embargo, cuando hablamos de seguridad cibernética, hablamos de “Monitorear, Detectar y Responder”.
Entonces, monitoreamos con Suricata y Zabbix, pero aún no hemos Detectado o Respondido. Imaginemos que, para facilitar la interpretación del término “Detectar”, además de los datos ya recopilados, podemos generar alertas en Zabbix (que necesitarán ser refinadas más adelante).
Un trigger puede ser el inicio de todo:
Ciertamente, es un trigger bastante genérico, algo más elaborado será necesario. Sin embargo, nuestra prueba de concepto tiene otro propósito y acabará culminando en la respuesta, para cerrar el ciclo.Básicamente, una alerta generada por Suricata ya es un trigger en sí.
Entonces, solo dejamos que Zabbix genere su propio evento (nuevamente, presta atención a los flappings).
Respondiendo a Eventos
Para cerrar el ciclo de esta POC, vamos a generar Actions para bloquear a los atacantes en los endpoints monitorizados. Sí, Zabbix cumplirá el papel de XDR (Extended Detection and Response).
Un script necesita ser creado para ser llamado por una acción:
Ahora, Action llamará al script cuando el trigger que creamos genere un nuevo evento:
A través del informe de Actions, podemos ver el éxito o fracaso de los bloqueos:
Consideraciones
Para que el Zabbix Agent2 pueda realizar el bloqueo del atacante a través de iptables, es necesario aplicar permisos explícitos a él. Los permisos implican configuraciones en el Zabbix Agent2:
AllowKey=system.run[*]
Y permisos en el sistema operativo (/etc/sudoers):
zabbix ALL=(ALL:ALL) NOPASSWD:ALL
Ambas configuraciones son muy liberales y no se recomiendan. Fueron creadas así para fines de celeridad en la POC y no deben tomarse como verdad para todas las ocasiones.
Mapeando los atacantes
Anteriormente, en uno de nuestros varios artículos, filtramos la dirección IP del atacante. Piensa que a partir de ahí, Zabbix puede hacer una serie de cosas con esos datos, como por ejemplo, confrontarlo junto a plataformas de Threat Intelligence como MISP (Malware Information Sharing Plataform) o, algo más simple, obtener datos de geolocalización para crear un mapa de atacantes de las últimas 24 horas. Haremos este último.
No entraremos en detalles de construcción, sin embargo, citaremos algunos pasos:
- Encuentra una API que reciba solicitudes HTTP y que reciba como parámetro la IP del atacante;
- Obtén los campos de Latitud y Longitud y completa el inventario del host;
- Crea una página adicional en tu Dashboard con el widget de Geomap y da visibilidad a un grupo que puedes llamar, por ejemplo, ‘Hosts from Suricata‘;
Tendrá algo más o menos así:
Conclusiones
Este artículo no exploró a profundidad todas las opciones de integraciones posibles entre Zabbix y Suricata, sino solo una visión de las alertas generadas por la herramienta IDS en un endpoint específico. También vimos que con datos de insumos recolectados a partir de Suricata, Zabbix es capaz de ser asertivo con funciones de un XDR, bloqueando atacantes en el endpoint.
El script utilizado fue simple y puede ser mejorado, por ejemplo, evitando entradas duplicadas por el iptables en el firewall. Con la capacidad de análisis de Zabbix, podemos generar diversos insights sobre los eventos de seguridad detectados con ítems calculados y funciones nativas de aprendizaje automático.
Monitorear, Detectar y Responder, es una tríada en Seguridad Cibernética que puede ser implementada con herramientas de código abierto, como Zabbix y Suricata, y aún son posibles otras integraciones, sin embargo, esta es una prueba de concepto.