501 lines
No EOL
18 KiB
Markdown
501 lines
No EOL
18 KiB
Markdown
## 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/
|
|
|
|

|
|
|
|
## 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":
|
|
|
|

|
|
|
|
2. Dentro de Plugin activamos "Enrichment":
|
|
|
|

|
|
|
|
3. Luego "Action" y "Workflow":
|
|
|
|

|
|
|
|

|
|
|
|
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:
|
|
|
|

|
|
|
|
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:
|
|
|
|

|
|
|
|
7. Luego en la misma ventana, vamos a la sección de "List Modules" y activamos el módulo de "Webhook":
|
|
|
|

|
|
|
|

|
|
|
|
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":
|
|
|
|

|
|
|
|
9. Finalmente desde la misma ventana, en "Blocking" activamos "Stop execution":
|
|
|
|

|
|
|
|
## 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 "</>":
|
|
|
|

|
|
|
|
2. Desde la lista de "Actions", Agregamos "Webhook" al plano de diseño arrastrando:
|
|
|
|

|
|
|
|
3. Desde la lista de "Logic", Agregamos "IF :: Count" al plano de diseño arrastrando:
|
|
|
|

|
|
|
|
4. Desde la lista de "Actions", Agregamos "Stop execution" al plano de diseño arrastrando:
|
|
|
|

|
|
|
|
5. Conectamos "Event Publish" con "IF :: Count":
|
|
|
|

|
|
|
|
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:
|
|
|
|

|
|
|
|
7. En el mismo módulo en "Condition" seteamos como "Equals to" y en "Value" queda en 0:
|
|
|
|

|
|
|
|
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":
|
|
|
|

|
|
|
|
9. En caso contrario, que Evento SI tenga atributos, lo conectamos al módulo "Webhook" para que procese los datos:
|
|
|
|

|
|
|
|
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 <MI_JWT_TOKEN>
|
|
|
|
11. Vamos a puntos arriba mano derecha y editamos el módulo para agregar esta información:
|
|
|
|

|
|
|
|
12. Ingresamos la información mencionada en el punto 10 y para finalizar presionamos el botón "Close":
|
|
|
|

|
|
|
|

|
|
|
|
13. Guardamos el Workflow en MISP haciendo clic en "Save":
|
|
|
|

|
|
|
|
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 |