Integrando Geolocalización IPv6 en Wazuh

Con Wazuh podemos desarrollar scripts de integración para interactuar con casi cualquier servicio API.

La belleza de Wazuh y muchas otras herramientas de código abierto es que podemos crear nuestras propias integraciones. En esta ocasión vamos a integrar un script Python personalizado para Wazuh que envíe solicitudes a un servicio de geolocalización IPv6 y así enriquecer diferentes intentos de inicio de sesión.

Además de un conocimiento básico de Python y Jupyter Notebooks, asumo que ya tienes Wazuh funcionando. Mi entorno actual es una instalación "All-in-One" en una VM CentOS con Proxmox, de todas maneras podrán utilizar cualquier distribución Linux que deseen.

Aclaración: si estan utilizando Wazuh distribuido (en cluster), deberán replicar toda esta configuración en los Managers donde se desea que se ejecute la integración.

Creando la integración paso a paso

Primeramente, debemos construir un script simple de llamada al servicio de Geolocalización por IPv6 para comprobar su funcionamiento y obtener la estructura de la respuesta API.
Para esto, nos registraremos (para obtener una API Key) y utilizaremos el servicio API que provee ipgeolation.

import requests as req
import json

prms = {
        'apiKey': '1111111r22s3333t444uvw55555x66yz',
        'ip': '2001:4860:4860::1'
        }

response = req.get('https://api.ipgeolocation.io/ipgeo', params=prms)

print(json.dumps(response.json(), indent=4))

La respuesta será la siguiente (en formato JSON):

{
    "ip": "2001:4860:4860::1",
    "continent_code": "NA",
    "continent_name": "North America",
    "country_code2": "US",
    "country_code3": "USA",
    "country_name": "United States",
    "country_capital": "Washington, D.C.",
    "state_prov": "California",
    "district": "",
    "city": "Mountain View",
    "zipcode": "94043-1351",
    "latitude": "37.42240",
    "longitude": "-122.08421",
    "is_eu": false,
    "calling_code": "+1",
    "country_tld": ".us",
    "languages": "en-US,es-US,haw,fr",
    "country_flag": "https://ipgeolocation.io/static/flags/us_64.png",
    "geoname_id": "6301403",
    "isp": "Google LLC",
    "connection_type": "",
    "organization": "Google LLC",
    "currency": {
        "code": "USD",
        "name": "US Dollar",
        "symbol": "$"
    },
    "time_zone": {
        "name": "America/Los_Angeles",
        "offset": -8,
        "current_time": "2023-01-23 07:07:07.089-0800",
        "current_time_unix": 1674486427.089,
        "is_dst": false,
        "dst_savings": 1
    }
}

Hemos comprobado que el servicio y respuesta funcionan sin inconvenientes. Ahora, decidiremos que campos enriquecerán los eventos en Wazuh. Como ejemplo, podríamos utilizar los siguientes:

  • ip

  • country_code2

  • country_name

  • state_prov

  • district

  • city

  • latitude

  • longitude

  • isp

  • organization

Aquí es donde aprovecharemos las ventajas de otra herramienta llamada Wazuh Code Generator con la cual podremos generar un script de integración -100% compatible con Wazuh- de manera rápida y sencilla. Los pasos para su instalación y ejecución se encuentran en la descripción del repositorio de Docker Hub.

NOTA: Esta herramienta esta desarrollada en Python bajo JupyterHub y Docker (corre en un contenedor ligero y portable de manera que pueda ejecutarse en cualquier máquina -con Docker instalado- independientemente del sistema operativo.)

Generando el código de integración para Wazuh

Una vez ejecutado nuestro contenedor Docker, Wazuh-Code-Generator estará corriendo en el puerto 8000. En nuestro navegador, ingresamos localhost:8000

Y clickeamos el archivo wazuh_codegen.ipynb que nos conducirá a nuestro Jupyter Notebook para la generación de nuestro script de integración.

Al ejecutar cada uno de los paneles, en especial el panel de Generate form inputs, se visualizarán tres inputs en donde ingresar un nombre (preferentemente corto) para la integración, los campos de la respuesta API que obtuvimos (separados por coma) y el nombre del campo que Wazuh necesita chequear para obtener y enriquecer los eventos. En este caso, como vamos a chequear siempre el valor del campo "ip" para obtener su geolocalizacion, éste será el campo que ingresemos en el input.

A continuación, seguiremos ejecutando panel por panel hasta su finalización:

Nuevamente volvemos al Home de JupyterHub y visualizaremos dos archivos generados:

Un archivo .py correspondiente al script de integración y otro .txt que nos servirá de guía para crear posteriormente las reglas dentro de Wazuh.

Si accedemos al archivo custom-geoipv6.py observaremos que se ha generado casi la totalidad del código necesario para interactuar con Wazuh utilizando los campos arriba descriptos, entre otras funciones.

Apoyándonos ahora en nuestro primer script de prueba, indentificamos la función def query_api(ip, apikey) -la misma, contiene una serie de ejemplos y pasos a seguir para completar el script de integracion-. En este caso, los únicos cambios/código que necesitamos agregar son 3:

  • los parámetros de llamada a la API (un diccionario llamado params que contiene dos pares clave/valor el cual se utilizará como parámetros en la solicitud API).

  • la llamada al endpoint de la API (una solicitud GET a la URL pasando los parámetros anteriormente descriptos. La respuesta se almacenara en la variable response).

  • por último utilizamos la variable json_response para procesar y almacenar la respuesta HTTP en formato JSON.

Ahora ya tenemos nuestro código de integración listo para utilizar con Wazuh.

Seleccionamos todo el código del archivo custom-geoipv6.py, lo copiamos y pegamos en nuestro editor de código favorito (VS Code, PyCharm, etc...) con el mismo nombre: custom-geoipv6.py

NOTA: Todas las integraciones personalizadas de Wazuh precisan que el nombre comience con custom-

Por último, vamos nuevamente a nuestro Home de JupyterHub, seleccionamos el archivo geoipv6_ossec_conf_rules.txt y procedemos a copiar, pegar y guardar su contenido en un archivo de texto.

Este archivo "guía" consta de dos fragmentos de configuración -en XML- para configurar dentro de la plataforma más adelante.

El primer fragmento está creando una plantilla para una regla de detección en Wazuh. La regla se activa cuando se detecta una determinada dirección IP (especificada en el campo "geoipv6.ip") intentando conectarse a la red. Esta configuración se añade al archivo de reglas local_rules.xml.

El segundo fragmento permite configurar la integración con el script llamado "custom-geoipv6.py". La integración incluye una URL y la clave de API para comunicarse con el endpoint correspondiente, así como el nivel de alerta y el ID de regla específico para activar la alerta. Esta configuración se añade al archivo ossec.conf.

Administración de archivos de integracion en Wazuh

Acceder en la carpeta de integraciones de Wazuh:

cd /var/ossec/integrations

y copiar dentro el archivo custom-geoipv6.py. También se pueden generar mediante vi o nano, lo importante es guardalo con el mismo nombre y con los permisos de acceso que correspondan.
Ej.
vi custom-geoipv6.py

-pegar el código generado y grabar-

chown root:wazuh custom-geoipv6.py

Deberíamos ver lo siguiente:

Configurando Wazuh

En Wazuh, seleccionamos Management > Rules > Custom Rules.

Luego, clickeamos en local_rules.xml.

En primer lugar queremos crear una regla que genere una alerta cuando una IP version 6 (2001:db8:3333:4444:5555:6666:7777:8888, etc.) intente iniciar sesión en nuestro servidor.

Agregamos las siguientes líneas:

<group name="local,syslog,sshd,">
 <rule id="100006" level="10">
    <if_sid>5760</if_sid>
    <match type="pcre2">\b(?:::|([[:xdigit:]]{1,4})(?::(?1)){7}|(?:(?1):){1,6}:|(?:(?1):){5}:(?1)|(?:(?1):){4}(?::(?1)){1,2}|(?:(?1):){3}(?::(?1)){1,3}|(?:(?1):){2}(?::(?1)){1,4}|(?1):(?::(?1)){1,5}|:(?::(?1)){1,6})</match>
    <description>sshd: Authentication failed from a public IPv6 address > $(srcip).</description>
    <group>authentication_failed,pci_dss_10.2.4,pci_dss_10.2.5,</group>
  </rule>
</group>

El bloque "match" de arriba especifica que queremos realizar una búsqueda RegEx (Expresiones Regulares) que identifiquen direcciones IPv6.

Al finalizar pulsar Save.

Nuevamente en Wazuh, seleccionamos Management > Configuration > Edit configuration.

Ahora, modificaremos el archivo de configuración de Wazuh Manager ossec.conf con el siguiente fragmento para la integración.

  <integration>
    <name>custom-geoipv6.py</name>
    <hook_url>https://api.ipgeolocation.io/ipgeo</hook_url>
    <api_key>1111111r22s3333t444uvw55555x66yz</api_key>
    <level>10</level>
    <rule_id>100006</rule_id>
    <alert_format>json</alert_format>
  </integration>

Esto le indica a Wazuh Manager que haga una solicitud a la API de ipgeolocation.io cada vez que se dispare nuestro ID de regla (100006), creado anteriormente. Solo asegúrense de reemplazar la línea "api_key" con al key propia. Recuerden que deben registrarse en https://ipgeolocation.io/ para obtener una API key gratuita.

Para finalizar, asegurarse de reiniciar Wazuh Manager para que los nuevos cambios tengan efecto.

Conclusión

Esta integración nos permitió recuperar información de geolocalización desde ipgeolocation.io sobre direcciones IP version 6 que intentaron autenticarse por ejemplo, via SSH. La información recuperada se podría utilizar posteriormente con demás reglas para mejorar nuestra detección de amenazas, falsos positivos y mejora continua en nuestra organización.