## Descripción Este proyecto permite en tiempo real realizar correcciones (limpieza) en los atributos dentro de cada evento en MISP antes de ser publicado en la plataforma. Esto se lleva a cabo a través de la funcionalidad de Workflows que integra MISP. Como resultado este proyecto implementa una API en un servidor para recibir los datos de cada evento para ser procesados. (Se necesita el servicio gratuito de lookup de IP's, dominios, url y hashes que ofrece Kaspersky© Threat Intelligence Portal para la limpieza de falsos positivos) ## Características: - Limpieza de falsos positivos de cada evento generado en MISP (IP, Domain, SHA256, URL) - Normalización de correlación y activación de tag IDS en cada atributo. Solo se activa tag IDS para el tipo de atributo que corresponde, como a su vez solo se activa la correlación para los tipos de atributos que deben ser correlacionados. - Normalización de tags para eventos que contengan "tlp: white" ( Se agrega tag tlp:clear en cada caso) - Utiliza dentro de Workflows, el trigger "event-publish" ## Requisitos - Se requiere una cuenta en la plataforma Kaspersky© Threat Intelligence Portal. La cuenta es gratuita. ([https://opentip.kaspersky.com]) ## Requisitos de Hardware recomendados - 8/16 GB RAM - 4 vCPU - 100 GB almacenamiento ## Componentes Este proyecto utiliza un BD local SQLite en modo WAL, FastAPI. ## Configuración inicial 1. En el archivo config.py se debe definir los datos de conexión a MISP, como también la API KEY asociada a Kaspersky TIP: ``` python MISP_CONFIG = { "misp_url":"URL_MISP", "misp_authkey":"AUTHKEY_MISP" } # Se si quiere agregar a exclusión de MISP cada atributo al deshabilitar correlación NO_CORRELATIVOS_EXCLUSION = False # Config Lookup KTIP KTIP_CONFIG = { "api_key":"APIKEY_KTIP", "url_base": "https://opentip.kaspersky.com/api/v1/search/" } # Rango de dias para verificar si IoC es falso positivo RANGO_DIAS = 7 # Se debe establecer Manual JWT_TOKEN_GEN = "BEARER_TOKEN" # Máximo de atributos a procesar por evento (2000 es el recomendado) MAX_ATTRS = 2000 def cargar_fp_en_set(ruta_archivo: str) -> set: """ Lee un archivo de texto línea a línea y devuelve un set con cada línea limpia. """ conjunto = set() with open(ruta_archivo, "r", encoding="utf-8") as archivo: for linea in archivo: linea_limpia = linea.strip() if linea_limpia: # Evita líneas vacías conjunto.add(linea_limpia) return conjunto # Falsos positivos comunes # FP Comunes FP_COMUNES = cargar_fp_en_set("fp.txt") # Organizaciones que se puede omitir la revisión de eventos ORG_OMITIR = [] NO_CORRELACIONES = [ "comment", # Comentarios descriptivos "email-subject", # Asuntos de correos electrónicos "email-dst", # Emails de destinatarios "email-src", # Emails de remitentes "hostname", # Nombres de host "port", # Puertos "link", # Enlaces "phone-number", # Números de teléfono "user-agent", # Agentes de usuario "size-in-bytes", # Tamaños en bytes "vulnerability", # Vulnerabilidades (CVE) "whois-registrant-email", # Correos de registrantes WHOIS "whois-registrant-name", # Nombres de registrantes WHOIS "regkey", # Claves de registro de Windows "regkey|value", # Claves de registro con valores "text", # Texto libre "datetime", # Fechas y horas "campaign-name", # Nombres de campaña "attachment", # Archivos adjuntos "email", # Emails de remitentes "email-body", # Cuerpo de Email "email-attachment" # Archivos adjuntos (variante) ] IDS_CORRELACIONES = [ "ip-src", # IP de origen "ip-dst", # IP de destino "domain", # Dominio "domain|ip", # Dominio con IP asociada "url", # URL completas "uri", # URI (fragmentos de rutas) "http-method", # Métodos HTTP (GET, POST, etc.) "email-attachment", # Nombres de archivos adjuntos en correos "filename", # Nombres de archivo "filename|md5", # Nombre de archivo con su hash MD5 "filename|sha1", # Nombre de archivo con su hash SHA1 "filename|sha256", # Nombre de archivo con su hash SHA256 "md5", # Hash MD5 "sha1", # Hash SHA1 "sha256", # Hash SHA256 "authentihash", # Hash Authentihash "impfuzzy", # Hash ImpHash (ejecutable PE) "tlsh", # Hash TLSH "ssdeep", # Hash SSDEEP (fuzzy hash) "mutex", # Nombres de mutex "registry-key", # Claves de registro (si son relevantes) "registry-key|value", # Claves de registro con valores "ip-src|port", # IP de origen con puerto "ip-dst|port", # IP de destino con puerto "asn", # ASN (Autonomous System Number) "cidr", # Rango CIDR (IPs) "mac-address", # Dirección MAC "x509-fingerprint-md5", # Huella de certificados X509 (MD5) "x509-fingerprint-sha1", # Huella de certificados X509 (SHA1) "x509-fingerprint-sha256", # Huella de certificados X509 (SHA256) "ja3-fingerprint-md5", # Huella JA3 (TLS handshake) "btc", # Dirección de Bitcoin "iban", # Número de cuenta bancaria (IBAN) "bank-account-nr", # Número de cuenta bancaria "payment-card-number" # Número de tarjeta de pago ] CONFIG_WL = { "filtros_buscar": ["osint", "google", "ipv4", "1000","domains","websites","microsoft","amazon","cloudflare","tranco","cisco","azure","office"], "max_reg": 10000 } ``` En config.py puedes realizar los ajustes: - MISP_CONFIG: Configuración asociada a MISP - NO_CORRELATIVOS_EXCLUSION: Si es True, cada atributo que sea corregida su correlación, ósea que se desactive, será agregado valor a la lista de exclusión de correlaciones. - KTIP_CONFIG: Configuración de conexión a servicio de Lookup de Kaspersky. Se debe solo configurar "api_key". - RANGO_DIAS: Establece según la fecha del atributo (IoC) cuantos días tomar como rango para verificar falso positivo - JWT_TOKEN_GEN: Token personal generado. - MAX_ATTRS: Cantidad de atributos a procesar por evento. Por defecto el máximo son 2000. No se recomienda aumentar este valor mas alla de los 4000 Attrs. - FP_COMUNES: Falsos positivos conocidos que se obtienen de un archivo txt. - ORG_OMITIR: Organizaciones que se puede omitir la revisión de eventos. - NO_CORRELACIONES: Lista de tipos de atributos que no deben correlacionarse dentro de MISP. - IDS_CORRELACIONES: Lista de tipos de atributos que deberán tener el flag IDS activado dentro de MISP. Por defecto estos atributos son correlacionados dentro de MISP. - CONFIG_WL: Configuración de filtros para obtener falsos positivos de WarningList de MISP. # Configuración Inicial ## Instalación en entorno virtual 1. Se crea entorno virtual de Python ``` shell cd /home/user/misp-fixevent-webhook python3 -m venv venv source venv/bin/activate ``` 2. Instalar bibliotecas de Python: ``` shell pip install -r requirements.txt ``` 3. Se debe desactivar entorno para configurar playwright inicialmente. ```shell deactivate # Instala dependencias en Ubuntu sudo venv/bin/playwright install-deps # instala dependencias de playwright sudo venv/bin/playwright install ``` 4. Se debe crear archivo .sh o editar el archivo existente (start_api.sh) y anexarlo como servicio para que inicie con el sistema operativo: ``` shell #!/bin/bash # Activate source /home/user/misp-fixevent-webhook/venv/bin/activate # Enter folder cd /home/user/misp-fixevent-webhook/ # Actualizar bibliotecas si aplica pip install --upgrade -r requirements.txt > /dev/null 2>&1 # Si vas a utilizar proxy reverso... uvicorn main:app --host 0.0.0.0 --port 8000 # Si no vas a utilizar proxy reverso puedes utilizar certificados genéricos uvicorn main:app --host 0.0.0.0 --port 8000 --ssl-keyfile key.pem --ssl-certfile cert.pem ``` Debe activar SSL en proyecto ## Agregar como servicio 1. Para agregar como servicio necesita crear dentro del directorio /etc/systemd/system (En caso de Ubuntu) un archivo .service(misp_webhooks.service). Podemos crearlo con nano (sudo) usando el siguiente formato: ``` shell sudo nano /etc/systemd/system/misp_webhooks.service [Unit] Description=MISP WebHooks Service After=network.target [Service] Type=simple ExecStart=/home/user/misp-fixevent-webhook/start_api.sh Restart=always [Install] WantedBy=multi-user.target ``` 2. Se deben entregar permisos de ejecución a archivo .sh: ```shell chmod +x /home/user/misp-fixevent-webhook/start_api.sh ``` 3. Se recargan servicios: ```shell sudo systemctl daemon-reload ``` 3. Luego registramos este archivo para que se ejecute al iniciar el sistema: ``` shell sudo systemctl enable misp_webhooks.sevice ``` 4. Ahora podemos iniciar, detener, reiniciar servicio... ``` shell # Iniciar sudo systemctl start misp_webhooks.sevice # Detener sudo systemctl stop misp_webhooks.sevice # Reiniciar sudo systemctl restart mmisp_webhooks.sevice ``` ## Servicios (Endpoints) de API - /webhoook/misp_event_fixer/ ![alt text](https://git.csirt.gob.cl/public/misp-fixevent-webhook/raw/branch/main/img_static/1_docs.png) ## Documentación Debes agregar Puedes acceder a la documentación: SwaggerUI ``` http://URL_PROYECTO:8000/docs ``` Redocly ``` http://URL_PROYECTO:8000/redoc ``` ## Configuración en Servidor MISP Desde MISP necesitamos configurar el Workflow para utilizar nuestra API. Debemos verificar si tenemos "misp-modules" instalados. Estos módulos corren en el puerto 6666. Podemos verificar si el puerto esta activo: ```shell telnet localhost 6666 ``` Si no hay respuesta, necesitamos instalar las siguientes librerías (Ubuntu): ```shell sudo apt install git python3 python3-pip python3-dev libpq5 libjpeg-dev build-essential libssl-dev libffi-dev zlib1g-dev libmagic-dev libxml2-dev libxslt1-dev libpoppler-cpp-dev libzbar0 tesseract-ocr ``` Una vez instaladas, podemos instalar misp-modules en nuestro servidor MISP (como root). Desde la versión 2.5, no se incluye misp-modules (Para más información: https://misp.github.io/misp-modules/install/) 1. Creamos directorio dentro de MISP: ``` shell sudo su cd /var/www/MISP mkdir misp-modules cd /misp-modules ``` 2. Creamos entorno virtual y activamos: ``` shell python3 -m venv venv source venv/bin/activate ``` 3. Instalamos librerías: ``` shell pip install \ misp-modules \ git+https://github.com/cartertemm/ODTReader.git \ git+https://github.com/abenassi/Google-Search-API \ git+https://github.com/SteveClement/trustar-python.git \ git+https://github.com/sebdraven/pydnstrails.git \ git+https://github.com/sebdraven/pyonyphe.git ``` 4. Creamos un .sh (run.sh) para llamar como servicio cada vez que parta el equipo: ``` shell sudo nano run.sh ``` 5. Dentro del archivo definimos las rutas (según sea el caso): ```shell #!/bin/bash # Activate source /var/www/MISP/misp-modules/venv/bin/activate # Enter folder cd /var/www/MISP/misp-modules/venv/bin/ # Ejecutar misp-modules misp-modules ``` 6. Configuramos servicio: ```shell sudo nano /etc/systemd/system/misp-modules.service ``` 7. Dentro del archivo definimos las rutas (según sea el caso): ```shell [Unit] Description=MISP Modules Service After=network.target [Service] Type=simple ExecStart=/var/www/MISP/misp-modules/run.sh Restart=always [Install] WantedBy=multi-user.target ``` 7. Se deben entregar permisos de ejecución a archivo .sh: ```shell chmod +x /var/www/MISP/misp-modules/run.sh ``` 8. Se recargan servicios: ```shell sudo systemctl daemon-reload ``` 9. Luego registramos este archivo para que se ejecute al iniciar el sistema: ``` shell sudo systemctl enable misp-modules.sevice ``` 10. Configuramos carpeta de MISP como owner original "www-data" ```shell sudo chown -R www-data:www-data /var/www/MISP ``` 11. Arrancamos APP: ```shell sudo systemctl start misp-modules.sevice ``` ## Activando / Configurando Workflow en MISP 1. Accedemos a MISP y nos dirigimos a "Administration"->"Server Settings & Maintenance"->"Plugin": ![alt text](https://git.csirt.gob.cl/public/misp-fixevent-webhook/raw/branch/main/img_static/2_plugin.png) 2. Dentro de Plugin activamos "Enrichment": ![alt text](https://git.csirt.gob.cl/public/misp-fixevent-webhook/raw/branch/main/img_static/3_enrich.png) 3. Luego "Action" y "Workflow": ![alt text](https://git.csirt.gob.cl/public/misp-fixevent-webhook/raw/branch/main/img_static/4_action.png) ![alt text](https://git.csirt.gob.cl/public/misp-fixevent-webhook/raw/branch/main/img_static/5_workflow.png) 4. Para poder llamar a nuestro webhook desde MISP necesitamos modificar una propiedad de MISP desde el MISP CLI desde terminal: ```shell sudo -u www-data /var/www/MISP/app/Console/cake Admin setSetting Security.rest_client_enable_arbitrary_urls true ``` 5. Iniciamos sesión en nuestro MISP y nos dirigimos a "Administration"->"Worflows" de MISP: ![alt text](https://git.csirt.gob.cl/public/misp-fixevent-webhook/raw/branch/main/img_static/6_workflow_set.png) 6. El webhook está diseñado para llamarse en el proceso previo a publicar un evento en MISP, este trigger se llama "event-publish" y debemos activarlo yendo a "List Triggers"->"Event Publish" y presionamos el botón de play: ![alt text](https://git.csirt.gob.cl/public/misp-fixevent-webhook/raw/branch/main/img_static/7_ev_publish.png) 7. Luego en la misma ventana, vamos a la sección de "List Modules" y activamos el módulo de "Webhook": ![alt text](https://git.csirt.gob.cl/public/misp-fixevent-webhook/raw/branch/main/img_static/8_list_modules.png) ![alt text](https://git.csirt.gob.cl/public/misp-fixevent-webhook/raw/branch/main/img_static/9_webhook_play.png) 8. Para agregar más control en el flujo (Para el caso de Eventos que no tengan atributos => 0) vamos a activar dentro del "List Modules" en "Logic" el módulo "IF::Count": ![alt text](https://git.csirt.gob.cl/public/misp-fixevent-webhook/raw/branch/main/img_static/9_ifcount_play.png) 9. Finalmente desde la misma ventana, en "Blocking" activamos "Stop execution": ![alt text](https://git.csirt.gob.cl/public/misp-fixevent-webhook/raw/branch/main/img_static/9_stop_execution_play.png) ## Configuración Webhook 1. Ahora vamos a ir a la configuración de nuestro trigger "event-publish" para configurar los datos para enviar al webhook. Nos dirigimos al símbolo "": ![alt text](https://git.csirt.gob.cl/public/misp-fixevent-webhook/raw/branch/main/img_static/10_webhook_edit.png) 2. Desde la lista de "Actions", Agregamos "Webhook" al plano de diseño arrastrando: ![alt text](https://git.csirt.gob.cl/public/misp-fixevent-webhook/raw/branch/main/img_static/11_webhook_add.png) 3. Desde la lista de "Logic", Agregamos "IF :: Count" al plano de diseño arrastrando: ![alt text](https://git.csirt.gob.cl/public/misp-fixevent-webhook/raw/branch/main/img_static/11_ifcount_add.png) 4. Desde la lista de "Actions", Agregamos "Stop execution" al plano de diseño arrastrando: ![alt text](https://git.csirt.gob.cl/public/misp-fixevent-webhook/raw/branch/main/img_static/11_stop_execution_add.png) 5. Conectamos "Event Publish" con "IF :: Count": ![alt text](https://git.csirt.gob.cl/public/misp-fixevent-webhook/raw/branch/main/img_static/12_eventpublish_ifcount.png) 6. En el módulo IF :: Count configuramos "Data selector to count" con el valor "All Attributes", esto quiere decir que contara todos los atributos del evento: ![alt text](https://git.csirt.gob.cl/public/misp-fixevent-webhook/raw/branch/main/img_static/13_ifcount.png) 7. En el mismo módulo en "Condition" seteamos como "Equals to" y en "Value" queda en 0: ![alt text](https://git.csirt.gob.cl/public/misp-fixevent-webhook/raw/branch/main/img_static/13_ifcount_2.png) 8. Si el evento no tiene atributos, se detendrá la ejecución de "publish" en el evento. Debemos conectar en el resultado afirmativo del módulo IF :: Count el módulo "Stop execution": ![alt text](https://git.csirt.gob.cl/public/misp-fixevent-webhook/raw/branch/main/img_static/13_ifcount_3.png) 9. En caso contrario, que Evento SI tenga atributos, lo conectamos al módulo "Webhook" para que procese los datos: ![alt text](https://git.csirt.gob.cl/public/misp-fixevent-webhook/raw/branch/main/img_static/13_ifcount_webhook.png) 10. Ahora necesitamos configurar los datos que tenemos que mandar al Webhook. Los datos son los siguientes: - URL: https://IP_SERVIDOR_API:8000/webhook/misp_event_fixer/ - Payload: { "event_id": "{{ Event.id }}", "event_uuid": "{{ Event.uuid }}", "event_attribute_count": "{{ Event.attribute_count }}" } - Header: Authorization: Bearer 11. Vamos a puntos arriba mano derecha y editamos el módulo para agregar esta información: ![alt text](https://git.csirt.gob.cl/public/misp-fixevent-webhook/raw/branch/main/img_static/14_webhook_edit.png) 12. Ingresamos la información mencionada en el punto 10 y para finalizar presionamos el botón "Close": ![alt text](https://git.csirt.gob.cl/public/misp-fixevent-webhook/raw/branch/main/img_static/14_webhook_config_1.png) ![alt text](https://git.csirt.gob.cl/public/misp-fixevent-webhook/raw/branch/main/img_static/14_webhook_config_2.png) 13. Guardamos el Workflow en MISP haciendo clic en "Save": ![alt text](https://git.csirt.gob.cl/public/misp-fixevent-webhook/raw/branch/main/img_static/14_webhook_save.png) Con estos pasos realizados, desde ahora en adelante dentro de MISP, cada evento generado por la organización local o de instancias remotas, será revisado y corregido por nuestro servicio web. Cualquier duda o consulta envíanos un correo a: misp@anci.gob.cl