OSSEC: LOCALFILES y MySQL

La mayoría de vosotros ya sabréis que OSSEC es un sistema de detección de intrusos basado en host (HIDS). Si aun no lo conocéis, os recomiendo echarle un vistazo a la entrada “OSSEC como herramienta de Incident Handling”.

En esta entrada vamos a comentar la capacidad de monitorizar en tiempo real las salidas de comandos personalizados en un sistema Linux. Esta utilidad se configura en el fichero “ossec.conf”, entre etiquetas “<localfile>” y “<command>”. Si miráis este fichero, podéis ver como ya existen algunos preestablecidos, como df, netstat o last. Nosotros podemos añadir los que queramos y sean de utilidad para nuestro entorno. Por ejemplo, un comando netstat más personalizado o un listado de los módulos cargados en el kernel de Linux con lsmod. En nuestro ejemplo, proponemos el siguiente comando personalizado de netstat:

netstat -antupd |sort |awk 'BEGIN{printf "%-8s %-20s %-20s %-20s %-10s\n","PROTO", 
   "IP/PUERTO LOCAL","IP/PUERTO REMOTO", "ESTADO CONEXION", "PROCESO 
   LOCAL"}/ESTABLISHED/{printf "%-8s %-20s %-20s %-20s %-10s\n",$1,$4,$5,$6,$7}'|uniq

La salida del comando anterior muestra un listado de las conexiones establecidas en el equipo. Hemos utilizado awk para crear un encabezado y filtrar algunas columnas para que solo muestre las que nos interesan. La salida de la ejecución del comando anterior es:

PROTO	IP/PUERTO LOCAL	IP/PUERTO REMOTO	ESTADO CONEXION	   PROCESO LOCAL 
tcp   127.0.0.1:3306	127.0.0.1:40146 	ESTABLISHED        3192/mysqld 
tcp   127.0.0.1:40146   127.0.0.1:3306   	ESTABLISHED    	   3992/ossec-dbd

El comando habrá que definirlo en el fichero de configuración ossec.conf para que sea ejecutado por el agente de OSSEC:

<localfile> 
  <log_format>full_command</log_format> 
  <frequency>60</frequency> 
  <command>netstat -antupd |sort |awk 'BEGIN{printf "%-8s %-20s %-20s %-20s %-10s\n",
        "PROTO","IP/PUERTO LOCAL","IP/PUERTO REMOTO","ESTADO CONEXION","PROCESO
        LOCAL"}/ESTABLISHED/{printf "%-8s %-20s %-20s %-20s %-10s\n",$1,$4,$5,$6,$7}'|
        uniq</command> 
</localfile> 

En las opciones de configuración del comando hemos indicado el tipo de formato de log, así como la frecuencia de repetición en segundos, por lo que se ejecutará cada minuto.

El siguiente paso es crear las reglas para que se disparen cuando se den las condiciones que deseamos. En nuestro caso, la regla que generaremos en el servidor es la siguiente:

<rule id="100006" level="7"> 
    <if_sid>530</if_sid> 
    <match>ossec: output: 'netstat -antupd</match> 
    <check_diff /> 
    <description>Mi netstat personalizado.</description> 
</rule>

La regla se disparará cuando detecte el patrón contenido entre las etiquetas <match>, comprobará la salida de este comando en el log con el generado anteriormente y, en el caso de que no coincidan, generará una alerta indicando que ha ocurrido algún cambio en las conexiones. Los resultados de cada ejecución los guarda en ficheros en el directorio /var/ossec/queue/diff/.

Para comprobar la correcta monitorización de las conexiones abrimos una conexión, podemos hacerlo con la herramienta ncat:

$ ncat -l 50000 | ncat 127.0.0.1 50000

Ahora podemos ver las alertas generadas en el log /var/ossec/logs/alerts/alerts.log:

** Alert 1407164058.25113: mail  - ossec, 
2014 Aug 04 16:54:18 debian->netstat -antupd ...
Rule: 100006 (level 7) -> 'Mi netstat personalizado.' 
ossec: output: 'netstat -antupd … : 
PROTO	IP/PUERTO LOCAL	IP/PUERTO REMOTO    ESTADO CONEXION	PROCESO LOCAL 
tcp	127.0.0.1:3306	  127.0.0.1:40297   ESTABLISHED  	3192/mysqld 
tcp     127.0.0.1:40297   127.0.0.1:3306    ESTABLISHED     	9986/ossec-dbd 
tcp  	127.0.0.1:45827   127.0.0.1:50000   ESTABLISHED     	10093/ncat 
tcp 	127.0.0.1:50000   127.0.0.1:45827   ESTABLISHED      	10092/ncat 
Previous output: 
ossec: output: 'netstat -antupd … : 
PROTO	IP/PUERTO LOCAL    IP/PUERTO REMOTO    ESTADO CONEXION    PROCESO LOCAL 
tcp 	127.0.0.1:3306     127.0.0.1:40293     ESTABLISHED        3192/mysqld 
tcp  	127.0.0.1:40293    127.0.0.1:3306      ESTABLISHED        9986/ossec-dbd

Hasta aquí todo funciona correctamente, pero el problema ocurre cuando utilizamos bases de datos para almacenar las alertas. Hemos configurado una base de datos MySQL para almacenar la información de OSSEC.

El problema es que cuando se genera la alerta, ésta se almacena en una tabla de la base de datos pero, debido a la sintaxis del comando personalizado que hemos utilizado, la base de datos genera un error. Esto es a causa de la existencia de comillas en el comando, las cuales provocan una ruptura en la sentencia de inserción de la query, generando un error de sintaxis. Este error lo podéis ver en /var/ossec/logs/ossec.log.

2014/08/04 16:54:21 ossec-dbd(5203): ERROR: Error executing query 'INSERT INTO 
   location(server_id, name) VALUES ('1', 'debian->netstat -antupd |sort |awk 
   'BEGIN{...}'|uniq')'. Error: 'You have an error in your SQL syntax; check the manual 
   that corresponds to your MySQL server version for the right syntax to use near 
   'BEGIN...' at line 1'. 

¿Como podemos solucionarlo? Muy fácil, basta con ejecutar el comando a través de un script. De esta forma se almacenará el nombre del script en la base de datos en lugar del comando problemático. Los cambios ha realizar quedarían del siguiente modo:

1. Crear el script con el comando y almacenarlo en el equipo donde se encuentra el agente de OSSEC, por ejemplo en /bin/minetstat.sh:

#!/bin/bash
netstat -antupd |sort |awk 'BEGIN{printf "%-8s %-20s %-20s %-20s %-10s\n","PROTO", 
   "IP/PUERTO LOCAL","IP/PUERTO REMOTO", "ESTADO CONEXION","PROCESO 
   LOCAL"}/ESTABLISHED/{printf "%-8s %-20s %-20s %-20s %-10s\n",$1,$4,$5,$6,$7}'|uniq

2. Cambiar la configuración del agente para que ejecute el script (ossec.conf):

<localfile> 
  <log_format>full_command</log_format> 
  <frequency>60</frequency> 
  <command>/bin/minetstat.sh</command> 
</localfile> 

3. Modificar la regla en el servidor para que detecte la nueva entrada del log:

<rule id="100006" level="7"> 
    <if_sid>530</if_sid> 
    <match>ossec: output: '/bin/minetstat.sh</match> 
    <check_diff /> 
    <description>Mi netstat personalizado.</description> 
</rule>

A continuación podemos ver como se ha sustituido el comando original por la ruta del script y ver como el problema con MySQL ha sido resuelto.

** Alert 1407167245.40847: mail  - ossec, 
2014 Aug 04 17:47:25 debian->/bin/minetstat.sh 
Rule: 100006 (level 7) -> 'Mi netstat personalizado.' 
ossec: output: '/bin/minetstat.sh': 
PROTO	IP/PUERTO LOCAL 	IP/PUERTO REMOTO   ESTADO CONEXION    PROCESO LOCAL 
tcp  	127.0.0.1:3306   	127.0.0.1:40344    ESTABLISHED        3192/mysqld 
tcp  	127.0.0.1:40344  	127.0.0.1:3306     ESTABLISHED        12223/ossec-dbd 
tcp  	127.0.0.1:45873  	127.0.0.1:50000    ESTABLISHED        12274/ncat 
tcp  	127.0.0.1:50000  	127.0.0.1:45873    ESTABLISHED        12273/ncat 
Previous output: 
ossec: output: '/bin/minetstat.sh': 
PROTO	IP/PUERTO LOCAL 	IP/PUERTO REMOTO   ESTADO CONEXION    PROCESO LOCAL 
tcp  	127.0.0.1:3306   	127.0.0.1:40344    ESTABLISHED        3192/mysqld 
tcp  	127.0.0.1:40344 	127.0.0.1:3306     ESTABLISHED        12223/ossec-dbd 

Con estos pasos espero haber ayudado a aquellos que alguna vez se han encontrado con este problema. Además, ejecutar los comandos a través de scripts nos permite desarrollar funcionalidades mas avanzadas y mantenerlas al margen de los ficheros de configuración de reglas, facilitándonos la compresión y edición de los scripts.

Hay que tener en cuenta que estos scripts deben tener los permisos y restricciones adecuados al entorno con el fin de evitar brechas de seguridad en el sistema.

¡Hasta la próxima!