Recoger registros de IOC de MISP
En esta guía se describen los pasos para ingerir registros de IOC (indicadores de compromiso) de MISP (plataforma de intercambio de información sobre malware) en Google Security Operations mediante Bindplane. El analizador extrae IOCs de datos de MISP con formato JSON o CSV. Analiza la entrada, asigna campos al modelo de datos unificado (UDM), gestiona varios tipos de IOC (como hashes de IP, dominio y archivo) y enriquece los datos con contexto de inteligencia sobre amenazas, como la confianza y la gravedad. El analizador también lleva a cabo una lógica específica para diferentes formatos de datos y gestiona los casos en los que faltan campos o no se admiten.
Antes de empezar
Asegúrate de que cumples los siguientes requisitos previos:
- Instancia de Google SecOps
- Host de Linux con
systemd
- Si se ejecuta a través de un proxy, los puertos del cortafuegos están abiertos
- Acceso privilegiado a tu servidor MISP
Obtener la clave de API de MISP
- Inicia sesión en la interfaz web de MISP como administrador.
- Vaya a Administración > Listar claves de autenticación.
- Haz clic en Añadir clave de autenticación.
- Proporcione la siguiente configuración de la clave:
- Usuario: selecciona la cuenta de usuario asociada a la clave.
- IPs permitidas: puedes especificar las direcciones IP permitidas para la clave.
- Copia y guarda la clave en un lugar seguro.
- Haz clic en He anotado mi clave.
Configurar la exportación de registros de MISP
- Inicia sesión en tu instancia de MISP mediante SSH.
Instala PyMISP con el siguiente comando:
pip3 install pymisp
Modifica la secuencia de comandos de exportación
get_csv.py
con lo siguiente:#!/usr/bin/env python3 # -*- coding: utf-8 -*- import argparse from pymisp import ExpandedPyMISP from keys import misp_url, misp_key, misp_verifycert if __name__ == '__main__': parser = argparse.ArgumentParser(description='Get MISP data in a CSV format.') parser.add_argument("--controller", default='attributes', help="Attribute to use for the search (events, objects, attributes)") parser.add_argument("-e", "--event_id", help="Event ID to fetch. Without it, it will fetch the whole database.") parser.add_argument("-a", "--attribute", nargs='+', help="Attribute column names") parser.add_argument("-o", "--object_attribute", nargs='+', help="Object attribute column names") parser.add_argument("-t", "--misp_types", nargs='+', help="MISP types to fetch (ip-src, hostname, ...)") parser.add_argument("-c", "--context", action='store_true', help="Add event level context (tags...)") parser.add_argument("-f", "--outfile", help="Output file to write the CSV.") parser.add_argument("-l", "--last", required=True, help="can be defined in days, hours, minutes (for example 5d or 12h or 30m).") args = parser.parse_args() pymisp = ExpandedPyMISP(misp_url, misp_key, misp_verifycert, debug=True) attr = [] if args.attribute: attr += args.attribute if args.object_attribute: attr += args.object_attribute if not attr: attr = None print(args.context) response = pymisp.search(return_format='csv', controller=args.controller, eventid=args.event_id, requested_attributes=attr, publish_timestamp=args.last, type_attribute=args.misp_types, include_context=args.context) if args.outfile: with open(args.outfile, 'w') as f: f.write(response) else: print(response)
Edita el archivo
keys.py
para incluir tus credenciales y URL de la API de MISP, tal como se indica a continuación:misp_url = 'https://<MISP_URL>' misp_key = '<MISP_API_KEY>' misp_verifycert = False misp_client_cert = ''
- Sustituye
<MISP_URL>
por la IP o el nombre de host de tu MISP. - Sustituye
<MISP_API_KEY
por la clave de API que has generado anteriormente.
- Sustituye
Abre crontab con el comando
crontab -e
e introduce lo siguiente:0 20 * * * python3 /opt/misp/<YOUR_EXPORT_SCRIPT_PATH> -f /opt/misp/ioc_export/url.log -t "url" -l 1d -c 0 20 * * * python3 /opt/misp/<YOUR_EXPORT_SCRIPT_PATH> -f /opt/misp/ioc_export/ip-dst.log -t "ip-dst" -l 1d -c 0 20 * * * python3 /opt/misp/<YOUR_EXPORT_SCRIPT_PATH> -f /opt/misp/ioc_export/ip-src.log -t "ip-src" -l 1d -c 0 20 * * * python3 /opt/misp/<YOUR_EXPORT_SCRIPT_PATH> -f /opt/misp/ioc_export/domain.log -t "domain" -l 1d -c 0 20 * * * python3 /opt/misp/<YOUR_EXPORT_SCRIPT_PATH> -f /opt/misp/ioc_export/sha256.log -t "sha256" -l 1d -c 0 20 * * * python3 /opt/misp/<YOUR_EXPORT_SCRIPT_PATH> -f /opt/misp/ioc_export/file.log -t "filename" -l 1d -c 0 20 * * * python3 /opt/misp/<YOUR_EXPORT_SCRIPT_PATH> -f /opt/misp/ioc_export/registry.log -t "registry" -l 1d -c 0 20 * * * python3 /opt/misp/<YOUR_EXPORT_SCRIPT_PATH> -f /opt/misp/ioc_export/mutex.log -t "mutex" -l 1d -c 0 20 * * * python3 /opt/misp/<YOUR_EXPORT_SCRIPT_PATH> -f /opt/misp/ioc_export/threat-actor.log -t "threat-actor" -l 1d -c
- Actualiza
<YOUR_EXPORT_SCRIPT_PATH>
según la ubicación real de la secuencia de comandos de exportación.
- Actualiza
Obtener el archivo de autenticación de ingestión de Google SecOps
- Inicia sesión en la consola de Google SecOps.
- Ve a Configuración de SIEM > Agentes de recogida.
- Descarga el archivo de autenticación de ingestión. Guarda el archivo de forma segura en el sistema en el que se instalará Bindplane.
Obtener el ID de cliente de Google SecOps
- Inicia sesión en la consola de Google SecOps.
- Ve a Configuración de SIEM > Perfil.
- Copia y guarda el ID de cliente de la sección Detalles de la organización.
Instalar el agente de Bindplane en el servidor MISP
Instalación de Linux
- Abre un terminal con privilegios de superusuario o sudo.
Ejecuta el siguiente comando:
sudo sh -c "$(curl -fsSlL https://github.com/observiq/bindplane-agent/releases/latest/download/install_unix.sh)" install_unix.sh
Recursos de instalación adicionales
Para ver más opciones de instalación, consulta la guía de instalación.
Configurar el agente de Bindplane para ingerir archivos de registro de MISP y enviarlos a Google SecOps
- Accede al archivo de configuración:
- Busca el archivo
config.yaml
. Normalmente, se encuentra en el directorio/etc/bindplane-agent/
de Linux. - Abre el archivo con un editor de texto (por ejemplo,
nano
,vi
o Bloc de notas).
- Busca el archivo
Edita el archivo
config.yaml
de la siguiente manera:receivers: filelog: file_path: /opt/misp/ioc_export/*.log log_type: 'file' exporters: chronicle/chronicle_w_labels: compression: gzip # Adjust the path to the credentials file you downloaded in Step 1 creds_file_path: '/path/to/ingestion-authentication-file.json' # Replace with your actual customer ID from Step 2 customer_id: <customer_id> endpoint: malachiteingestion-pa.googleapis.com # Add optional ingestion labels for better organization ingestion_labels: log_type: 'MISP_IOC' raw_log_field: body service: pipelines: logs/source0__chronicle_w_labels-0: receivers: - filelog exporters: - chronicle/chronicle_w_labels
- Sustituye el puerto y la dirección IP según sea necesario en tu infraestructura.
- Sustituye
<customer_id>
por el ID de cliente real. - Actualiza
/path/to/ingestion-authentication-file.json
a la ruta en la que se guardó el archivo de autenticación en la sección Obtener el archivo de autenticación de ingestión de Google SecOps.
Reinicia el agente de Bindplane para aplicar los cambios
Para reiniciar el agente de Bindplane en Linux, ejecuta el siguiente comando:
sudo systemctl restart bindplane-agent
Tabla de asignación de UDM
Campo de registro | Asignación de UDM | Lógica |
---|---|---|
Attribute.category |
event.idm.entity.metadata.threat.category_details |
Se asigna directamente desde Attribute.category en el objeto JSON anidado del campo "data". Se usa en la ruta de análisis de JSON. |
Attribute.comment |
event.idm.entity.metadata.threat.summary |
Se asigna directamente desde Attribute.comment en el objeto JSON anidado del campo "data". Se usa en la ruta de análisis de JSON. |
Attribute.deleted |
event.idm.entity.metadata.threat.detection_fields.value |
Se ha asignado directamente desde Attribute.deleted y se ha añadido como campo de detección con la clave "Attribute deleted". Se usa en la ruta de análisis de JSON. |
Attribute.event_id |
event.idm.entity.metadata.threat.detection_fields.value |
Se ha asignado directamente desde Attribute.event_id y se ha añadido como campo de detección con la clave "Attribute event_id". Se usa en la ruta de análisis de JSON. |
Attribute.first_seen |
event.idm.entity.metadata.threat.detection_fields.value |
Se ha asignado directamente desde Attribute.first_seen y se ha añadido como campo de detección con la clave "Attribute first_seen". Se usa en la ruta de análisis de JSON. |
Attribute.id |
event.idm.entity.metadata.threat.detection_fields.value |
Se asigna directamente desde Attribute.id y se añade como campo de detección con la clave "Attribute id" o "Attribute id $$", según la ruta de análisis. Se usa en las rutas de análisis de CSV y JSON. |
Attribute.timestamp |
event.idm.entity.metadata.threat.detection_fields.value |
Se ha asignado directamente desde Attribute.timestamp y se ha añadido como campo de detección con la clave "Attribute timestamp". Se usa en la ruta de análisis de JSON. |
Attribute.to_ids |
event.idm.entity.metadata.threat.detection_fields.value |
Se ha asignado directamente desde Attribute.to_ids y se ha añadido como campo de detección con la clave "Attribute to_ids". Se usa en la ruta de análisis de JSON. |
Attribute.type |
log_type |
Se asigna directamente desde Attribute.type en el objeto JSON anidado del campo "data". Se usa como campo provisional y, más adelante, para rellenar otros campos de UDM. Se usa en la ruta de análisis de JSON. |
Attribute.uuid |
event.idm.entity.metadata.product_entity_id |
Se asigna directamente desde Attribute.uuid en el objeto JSON anidado del campo "data". Se usa en la ruta de análisis de JSON. |
Attribute.value |
Varios | El valor de este campo se usa para rellenar varios campos de UDM en función del Attribute.type (o log_type si se deriva de Attribute.type ):- event.idm.entity.entity.hostname si type es "domain".- event.idm.entity.entity.file.md5 si type es "md5".- event.idm.entity.entity.file.sha1 si type es "sha1".- event.idm.entity.entity.file.sha256 si type es "sha256".- event.idm.entity.entity.resource.name si type es "mutex".- event.idm.entity.entity.registry.registry_key si type es "regkey".- event.idm.entity.entity.user.email_addresses si type es "threat-actor".- event.idm.entity.entity.url si type es uri o url .- event.idm.entity.entity.file.full_path si type es "filename".: se analiza para obtener la IP y el puerto si type es "ip-dst|port", "ip-dst" o "ip-src". Se usa en la ruta de análisis de JSON. |
column1 |
event.idm.entity.metadata.product_entity_id |
Se asigna directamente desde column1 en la ruta de análisis de CSV. |
column14 |
Parte de event.idm.entity.metadata.threat.description |
Se concatena con description para formar la descripción final en los metadatos de la amenaza. Se usa en la ruta de análisis de CSV. |
column16 |
event.idm.entity.metadata.threat.threat_feed_name , event.ioc.feed_name |
Asignado directamente desde column16 . Se usa en la ruta de análisis de CSV. |
column18 |
event.idm.entity.metadata.threat.severity_details , event.ioc.raw_severity |
Asignado directamente desde column18 . Se usa en la ruta de análisis de CSV. |
column21 |
Parte de event.idm.entity.metadata.threat.description , event.ioc.description |
Se usa como base para la descripción, que se concatena más adelante con event_info . Se usa en la ruta de análisis de CSV. |
column3 |
Parte de event.ioc.categorization |
Se asigna directamente desde column3 y se concatena con "IOCs" para formar la categorización final. Se usa en la ruta de análisis de CSV. |
column4 |
event.idm.entity.metadata.description |
Asignado directamente desde column4 . Se usa en la ruta de análisis de CSV. |
column5 |
Varios | El valor de este campo se usa para rellenar varios campos de UDM en función del campo column4 (que se asigna a type ):- event.idm.entity.entity.hostname si type es "domain".: se analiza para obtener la IP y el puerto si type es "ip-dst|port", "ip-dst" o "ip-src".- event.idm.entity.entity.file.md5 si type es "md5".- event.idm.entity.entity.file.sha1 si type es "sha1".- event.idm.entity.entity.file.sha256 si type es "sha256".- event.idm.entity.entity.resource.name si type es "mutex".- event.idm.entity.entity.registry.registry_key si type es "regkey".- event.idm.entity.entity.user.email_addresses si type es "threat-actor".- event.idm.entity.entity.url si type es uri o url .- event.idm.entity.entity.file.full_path si type es "filename". Se usa en la ruta de análisis de CSV. |
column6 |
event.idm.entity.metadata.threat.summary |
Asignado directamente desde column6 . Se usa en la ruta de análisis de CSV. |
column8 |
event.ioc.active_timerange.start , event.idm.entity.metadata.interval.start_time |
Se analiza como una marca de tiempo UNIX. Se usa en la ruta de análisis de CSV. |
date description |
event.idm.entity.metadata.threat.description |
Se asigna directamente desde description en el objeto JSON anidado del campo "data". Se usa en la ruta de análisis de JSON. |
event_creator_email |
event.idm.entity.entity.labels.value |
Se ha asignado directamente desde event_creator_email y se ha añadido como etiqueta con la clave "event_creator_email". Se usa en la ruta de análisis de JSON. |
event_id Feed.publish |
event.idm.entity.metadata.threat.detection_fields.value |
Se asigna directamente desde Feed.publish y se añade como campo de detección con la clave "Feed publish". Se usa en la ruta de análisis de JSON. |
first_seen |
event.ioc.active_timerange.start , event.idm.entity.metadata.interval.start_time |
Se analiza como una marca de tiempo con el formato "aaaa-MM-ddTHH:mm:ssZZ". Se usa en la ruta de análisis de JSON. |
id info |
event.idm.entity.metadata.description |
Se asigna directamente desde info en el objeto JSON anidado del campo "data". Se usa en la ruta de análisis de JSON. |
last_seen |
event.ioc.active_timerange.end |
Se analiza como una marca de tiempo con el formato "aaaa-MM-ddTHH:mm:ssZZ". Se usa en la ruta de análisis de JSON. |
Org.name |
event.idm.entity.metadata.threat.detection_fields.value |
Se ha asignado directamente desde Org.name y se ha añadido como campo de detección con la clave "Nombre de la organización". Se usa en la ruta de análisis de JSON. |
published |
event.idm.entity.metadata.threat.detection_fields.value |
Se ha asignado directamente desde published y se ha añadido como campo de detección con la clave "published". Se usa en la ruta de análisis de JSON. |
Tag.colour |
event.idm.entity.metadata.threat.detection_fields.value |
Se ha asignado directamente desde Tag.colour y se ha añadido como campo de detección con la clave "tag colour". Se usa en la ruta de análisis de JSON. |
Tag.exportable |
event.idm.entity.metadata.threat.detection_fields.value |
Se ha asignado directamente desde Tag.exportable y se ha añadido como campo de detección con la clave "tag exportable". Se usa en la ruta de análisis de JSON. |
Tag.hide_tag |
event.idm.entity.metadata.threat.detection_fields.value |
Se ha asignado directamente desde Tag.hide_tag y se ha añadido como campo de detección con la clave "tag hide_tag". Se usa en la ruta de análisis de JSON. |
Tag.id |
event.idm.entity.metadata.threat.detection_fields.value |
Se ha asignado directamente desde Tag.id y se ha añadido como campo de detección con la clave "tag id". Se usa en la ruta de análisis de JSON. |
Tag.is_custom_galaxy |
event.idm.entity.metadata.threat.detection_fields.value |
Se ha asignado directamente desde Tag.is_custom_galaxy y se ha añadido como campo de detección con la clave "tag is_custom_galaxy". Se usa en la ruta de análisis de JSON. |
Tag.is_galaxy |
event.idm.entity.metadata.threat.detection_fields.value |
Se ha asignado directamente desde Tag.is_galaxy y se ha añadido como campo de detección con la clave "tag is_galaxy". Se usa en la ruta de análisis de JSON. |
Tag.isinherited |
event.idm.entity.metadata.threat.detection_fields.value |
Se ha asignado directamente desde Tag.isinherited y se ha añadido como campo de detección con la clave "tag isinherited". Se usa en la ruta de análisis de JSON. |
Tag.name |
event.idm.entity.metadata.threat.detection_fields.value |
Se asigna directamente desde Tag.name y se añade como campo de detección con la clave "nombre de etiqueta". Se usa en la ruta de análisis de JSON. |
Tag.numerical_value |
event.idm.entity.metadata.threat.detection_fields.value |
Se ha asignado directamente desde Tag.numerical_value y se ha añadido como campo de detección con la clave "tag numerical_value". Se usa en la ruta de análisis de JSON. |
Tag.user_id |
event.idm.entity.metadata.threat.detection_fields.value |
Se ha asignado directamente desde Tag.user_id y se ha añadido como campo de detección con la clave "tag user_id". Se usa en la ruta de análisis de JSON. |
threat_level_id |
event.idm.entity.entity.labels.value |
Se ha asignado directamente desde threat_level_id y se ha añadido como etiqueta con la clave "threat_level_id". Se usa en la ruta de análisis de JSON. |
timestamp |
event.idm.entity.metadata.collected_timestamp , event.idm.entity.metadata.interval.start_time |
Se analiza como una marca de tiempo UNIX. Se usa en la ruta de análisis de CSV. |
uuid |
event.idm.entity.metadata.vendor_name |
El analizador lo define como "MISP". El analizador lo define como "MISP". Se asigna un valor predeterminado muy lejano en el futuro (253402300799 segundos desde la época). Determinado por el analizador en función del campo type o log_type . Puede ser "FILE", "DOMAIN_NAME", "IP_ADDRESS", "MUTEX", "RESOURCE" o "USER". Se puede derivar de Attribute.comment o Attribute.value en función de Attribute.type . Se analiza a partir de Attribute.value o column5 si el tipo está relacionado con la IP. Se analiza a partir de Attribute.value o column5 si el tipo es "ip-dst|port". Derivado de column3 en el análisis de CSV o de Attribute.category en el análisis de JSON. Derivado de column21 y column14 en el análisis de CSV. Derivado de column8 o first_seen . Derivado de last_seen . Derivado de description mediante un patrón grok. Derivado de column16 o definido como "MISP". Derivado de column18 . Se analiza a partir de Attribute.value o column5 si el tipo está relacionado con la IP. Se analiza a partir de Attribute.value o column5 si el tipo es "ip-dst|port". Derivado de Attribute.value o column5 si el tipo es "domain". Derivado del campo confidence , que se extrae del campo description . Los valores pueden ser "HIGH_CONFIDENCE", "MEDIUM_CONFIDENCE", "LOW_CONFIDENCE" o "UNKNOWN_CONFIDENCE". Se asigna directamente desde el campo confidence , que se extrae del campo description . Se asigna directamente desde el campo threat_level , que se deriva de column18 en la ruta de análisis del archivo CSV. Se asigna directamente desde el campo feed_name , que se deriva de column16 en la ruta de análisis del archivo CSV. Derivado de column21 y column14 en el análisis de CSV. Derivado de column6 en el análisis de CSV o de Attribute.comment en el análisis de JSON. Se añaden varios campos de detección con sus claves correspondientes. Se añaden varios campos como etiquetas con sus claves correspondientes. Copiado del campo timestamp de nivel superior del registro sin procesar. |
¿Necesitas más ayuda? Recibe respuestas de los miembros de la comunidad y de los profesionales de Google SecOps.