Recoger registros de IOC de MISP
En este documento se explica cómo ingerir registros de IOC de MISP (Malware Information Sharing Platform) en Google Security Operations mediante Bindplane. El analizador procesa los datos en formato CSV y JSON. Extrae atributos de IOCs, como direcciones IP, dominios, hashes y URLs, y los asigna a un modelo de datos unificado (UDM) junto con detalles de amenazas, como la gravedad, la confianza y las descripciones. El analizador gestiona las entradas de IOC únicas y múltiples de los datos de entrada, normalizándolas en una salida UDM coherente.
Antes de empezar
Asegúrate de que cumples los siguientes requisitos previos:
- Una instancia de Google SecOps.
- Un host Linux con
systemd
. - Si se ejecuta a través de un proxy, asegúrate de que los puertos del cortafuegos estén abiertos según los requisitos del agente de Bindplane.
- Acceso privilegiado a tu servidor MISP.
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.
Obtener credenciales de la 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 los siguientes detalles de configuración:
- Usuario: selecciona la cuenta de usuario asociada a la clave.
- Opcional: IPs permitidas: especifica las direcciones IP permitidas para la clave.
- Vencimiento: deje este campo en blanco si no quiere que caduque o defina el valor que necesite.
- Haz clic en Enviar.
- Copia y guarda la clave de API en un lugar seguro.
- Haz clic en He anotado mi clave.
Configurar la exportación de datos de MISP
Instala PyMISP en tu servidor MISP:
pip3 install pymisp
Crea el directorio de exportación:
sudo mkdir -p /opt/misp/scripts sudo mkdir -p /opt/misp/ioc_export
Crea el archivo de credenciales
/opt/misp/scripts/keys.py
:misp_url = 'https://<MISP_SERVER_URL>' misp_key = '<MISP_API_KEY>' misp_verifycert = True misp_client_cert = ''
- Sustituye
<MISP_SERVER_URL>
por la URL de tu servidor MISP. - Sustituye
<MISP_API_KEY>
por la clave de API de los requisitos previos.
- Sustituye
Crea la secuencia de comandos de exportación
/opt/misp/scripts/misp_export.py
:#!/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='Export MISP IOCs to CSV format.') parser.add_argument("--controller", default='attributes', help="Controller to use for search (events, objects, attributes)") parser.add_argument("--event_id", help="Event ID to fetch. Without it, fetches recent data.") parser.add_argument("--attributes", nargs='*', help="Requested attributes for CSV export") parser.add_argument("--misp_types", nargs='+', help="MISP types to fetch (ip-src, hostname, domain, etc.)") parser.add_argument("--context", action='store_true', help="Add event level context (tags, metadata)") parser.add_argument("--outfile", required=True, help="Output file to write the CSV data") parser.add_argument("--last", required=True, help="Time period: days (d), hours (h), minutes (m) - e.g., 1d, 12h, 30m") args = parser.parse_args() api = ExpandedPyMISP(misp_url, misp_key, misp_verifycert, debug=False) response = api.search( controller=args.controller, return_format='csv', type_attribute=args.misp_types, publish_timestamp=args.last, include_context=args.context, requested_attributes=args.attributes or None ) with open(args.outfile, 'w') as response_file: response_file.write(response)
- Haz que la secuencia de comandos sea ejecutable:
sudo chmod +x /opt/misp/scripts/misp_export.py
Programar exportaciones de datos de MISP
- Crea exportaciones programadas con crontab:
sudo crontab -e
Añade las siguientes entradas cron:
# Export different IOC types daily with context 0 0 * * * python3 /opt/misp/scripts/misp_export.py --outfile /opt/misp/ioc_export/domains.csv --misp_types domain --last 1d --context --attributes uuid event_id category type value comment to_ids date attribute_tag event_info 0 1 * * * python3 /opt/misp/scripts/misp_export.py --outfile /opt/misp/ioc_export/ip-src.csv --misp_types ip-src --last 1d --context --attributes uuid event_id category type value comment to_ids date attribute_tag event_info 0 2 * * * python3 /opt/misp/scripts/misp_export.py --outfile /opt/misp/ioc_export/ip-dst.csv --misp_types ip-dst --last 1d --context --attributes uuid event_id category type value comment to_ids date attribute_tag event_info 0 3 * * * python3 /opt/misp/scripts/misp_export.py --outfile /opt/misp/ioc_export/urls.csv --misp_types url --last 1d --context --attributes uuid event_id category type value comment to_ids date attribute_tag event_info 0 4 * * * python3 /opt/misp/scripts/misp_export.py --outfile /opt/misp/ioc_export/sha256.csv --misp_types sha256 --last 1d --context --attributes uuid event_id category type value comment to_ids date attribute_tag event_info 0 5 * * * python3 /opt/misp/scripts/misp_export.py --outfile /opt/misp/ioc_export/filenames.csv --misp_types filename --last 1d --context --attributes uuid event_id category type value comment to_ids date attribute_tag event_info 0 6 * * * python3 /opt/misp/scripts/misp_export.py --outfile /opt/misp/ioc_export/registries.csv --misp_types regkey --last 1d --context --attributes uuid event_id category type value comment to_ids date attribute_tag event_info 0 7 * * * python3 /opt/misp/scripts/misp_export.py --outfile /opt/misp/ioc_export/mutexes.csv --misp_types mutex --last 1d --context --attributes uuid event_id category type value comment to_ids date attribute_tag event_info
También puede programar una extracción de feeds de MISP:
23 0 * * * curl --insecure --header "Authorization: <MISP_API_KEY>" --header "Accept: application/json" --header "Content-Type: application/json" https://<MISP_SERVER_URL>/feeds/fetchFromAllFeeds
Instalar el agente de Bindplane
Instala el agente Bindplane en tu sistema operativo Linux siguiendo las instrucciones que se indican a continuación.
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-otel-collector/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 registros 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
ovi
).
- Busca el archivo
Edita el archivo
config.yaml
de la siguiente manera:receivers: filelog: file_path: /opt/misp/ioc_export/*.log 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
<CUSTOMER_ID>
por el ID de cliente que has obtenido en los requisitos previos. - Actualiza
/path/to/ingestion-authentication-file.json
a la ruta donde se guardó el archivo de autenticación.
- Sustituye
Reinicia el agente de Bindplane para aplicar los cambios
Para reiniciar el agente de Bindplane en Linux, ejecuta el siguiente comando:
sudo systemctl restart observiq-otel-collector
Tabla de asignación de UDM
Campo de registro | Asignación de UDM | Lógica |
---|---|---|
Attribute.category | entity.metadata.threat.category_details | Asignación directa del campo category del objeto Attribute . |
Attribute.comment | entity.metadata.threat.summary | Asignación directa del campo comment del objeto Attribute . |
Attribute.deleted | entity.metadata.threat.detection_fields.value | Asignación directa del campo deleted del objeto Attribute . La tecla está configurada como Attribute deleted . |
Attribute.event_id | entity.metadata.threat.detection_fields.value | Asignación directa del campo event_id del objeto Attribute . La tecla está configurada como Attribute event_id . |
Attribute.first_seen | entity.metadata.threat.detection_fields.value | Asignación directa del campo first_seen del objeto Attribute . La tecla está configurada como Attribute first_seen . |
Attribute.id | entity.metadata.threat.detection_fields.value | Asignación directa del campo id del objeto Attribute . La clave se define como Attribute id o Attribute id $$ en función del formato del registro sin procesar. |
Attribute.timestamp | entity.metadata.threat.detection_fields.value | Asignación directa del campo timestamp del objeto Attribute . La tecla está configurada como Attribute timestamp . |
Attribute.to_ids | entity.metadata.threat.detection_fields.value | Asignación directa del campo to_ids del objeto Attribute . La tecla está configurada como Attribute to_ids . |
Attribute.type | entity.metadata.threat.category_details | Asignación directa del campo type del objeto Attribute . |
Attribute.type | log_type | Se usa para determinar el tipo de IOC y asignarlo a los campos de UDM correspondientes. |
Attribute.uuid | entity.metadata.product_entity_id | Asignación directa del campo uuid del objeto Attribute . |
Attribute.value | entity.entity.file.full_path | Se asigna si Attribute.type es filename . |
Attribute.value | entity.entity.file.md5 | Se asigna si Attribute.type es md5 . |
Attribute.value | entity.entity.file.sha1 | Se asigna si Attribute.type es sha1 . |
Attribute.value | entity.entity.file.sha256 | Se asigna si Attribute.type es sha256 . |
Attribute.value | entity.entity.hostname | Se asigna si Attribute.type es domain . |
Attribute.value | entity.entity.ip | Se asigna si Attribute.type es ip-dst , ip-dst|port o ip-src . El valor se extrae mediante un patrón grok. |
Attribute.value | entity.entity.resource.name | Se asigna si Attribute.type es mutex . |
Attribute.value | entity.entity.registry.registry_key | Se asigna si Attribute.type es regkey . |
Attribute.value | entity.entity.url | Se asigna si Attribute.type es uri o URL . |
columna1 | entity.metadata.product_entity_id | Asignación directa de la primera columna de los datos CSV. |
column14 | event_info | Se usa para añadir información adicional al campo threat_sr.description . |
column16 | event_source_org | Asignación directa de la columna 16 de los datos CSV. |
column18 | threat_level | Asignación directa de la columna 18 de los datos del archivo CSV. |
column21 | description | Asignación directa de la columna 21 de los datos CSV. |
columna3 | misp_category | Asignación directa de la tercera columna de los datos CSV. |
column4 | tipo | Asignación directa de la cuarta columna de los datos CSV. |
column5 | valor | Asignación directa de la quinta columna de los datos CSV. |
column6 | comentario | Asignación directa de la sexta columna de los datos CSV. |
column8 | ts1 | Asignación directa de la octava columna de los datos CSV. |
description | ioc.description | El valor se genera combinando el campo description con el campo event_info , separados por - additional info: . |
description | entity.metadata.threat.description | Asignación directa del campo description . |
event_creator_email | entity.entity.labels.value | Asignación directa del campo event_creator_email . La tecla está configurada como event_creator_email . |
event_source_org | ioc.feed_name | Asignación directa del campo event_source_org . |
event_source_org | entity.metadata.threat.threat_feed_name | Asignación directa del campo event_source_org . |
Feed.publish | entity.metadata.threat.detection_fields.value | Asignación directa del campo publish del objeto Feed . La tecla está configurada como Feed publish . |
first_seen | ioc.active_timerange.start | Asignación directa del campo first_seen . El valor se analiza como una fecha. |
first_seen | entity.metadata.interval.start_time | Asignación directa del campo first_seen . El valor se analiza como una fecha. |
información | entity.metadata.description | Asignación directa del campo info . |
last_seen | ioc.active_timerange.end | Asignación directa del campo last_seen . El valor se analiza como una fecha. |
log.category | ioc.categorization | Asignación directa del campo category del objeto log . |
log.category | entity.metadata.threat.category_details | Asignación directa del campo category del objeto log . |
log.comment | entity.entity.file.full_path | Se asigna si log.type es filename y el campo comment no es Artifacts dropped . |
log.comment | entity.metadata.threat.detection_fields.value | Asignación directa del campo comment del objeto log . La tecla está configurada como Attribute comment . |
log.comment | entity.metadata.threat.summary | Asignación directa del campo comment del objeto log . |
log.deleted | entity.metadata.threat.detection_fields.value | Asignación directa del campo deleted del objeto log . La tecla está configurada como Attribute deleted . |
log.event_id | entity.metadata.threat.detection_fields.value | Asignación directa del campo event_id del objeto log . La tecla está configurada como Attribute event_id . |
log.first_seen | entity.metadata.threat.detection_fields.value | Asignación directa del campo first_seen del objeto log . La tecla está configurada como Attribute first_seen . |
log.id | entity.metadata.threat.detection_fields.value | Asignación directa del campo id del objeto log . La tecla está configurada como Attribute id . |
log.timestamp | entity.metadata.threat.detection_fields.value | Asignación directa del campo timestamp del objeto log . La tecla está configurada como Attribute timestamp . |
log.to_ids | entity.metadata.threat.detection_fields.value | Asignación directa del campo to_ids del objeto log . La tecla está configurada como Attribute to_ids . |
log.type | ioc.categorization | Asignación directa del campo type del objeto log . |
log.type | log_type | Se usa para determinar el tipo de IOC y asignarlo a los campos de UDM correspondientes. |
log.uuid | entity.metadata.product_entity_id | Asignación directa del campo uuid del objeto log . |
log.value | entity.entity.file.full_path | Se asigna si log.type es filename . |
log.value | entity.entity.file.md5 | Se asigna si log.type es md5 . |
log.value | entity.entity.file.sha1 | Se asigna si log.type es sha1 . |
log.value | entity.entity.file.sha256 | Se asigna si log.type es sha256 . |
log.value | entity.entity.hostname | Se asigna si log.type es domain . |
log.value | entity.entity.ip | Se asigna si log.type es ip-dst , ip-dst|port o ip-src . El valor se extrae mediante un patrón grok. |
log.value | entity.entity.resource.name | Se asigna si log.type es mutex . |
log.value | entity.entity.registry.registry_key | Se asigna si log.type es regkey . |
log.value | entity.entity.url | Se asigna si log.type es uri o url . |
log.value | ioc.domain_and_ports.domain | Se asigna si log.type es domain . |
log.value | entity.entity.user.email_addresses | Se asigna si log.type es threat-actor . |
misp_category | entity.metadata.threat.category_details | Asignación directa del campo misp_category . |
Org.name | entity.metadata.threat.detection_fields.value | Asignación directa del campo name del objeto Org . La tecla está configurada como Org name . |
published | entity.metadata.threat.detection_fields.value | Asignación directa del campo published . La tecla está configurada como published . |
Tag.colour | entity.metadata.threat.detection_fields.value | Asignación directa del campo colour del objeto Tag . La tecla está configurada como tag colour . |
Tag.exportable | entity.metadata.threat.detection_fields.value | Asignación directa del campo exportable del objeto Tag . La tecla está configurada como tag exportable . |
Tag.hide_tag | entity.metadata.threat.detection_fields.value | Asignación directa del campo hide_tag del objeto Tag . La tecla está configurada como tag hide_tag . |
Tag.id | entity.metadata.threat.detection_fields.value | Asignación directa del campo id del objeto Tag . La tecla está configurada como tag id . |
Tag.is_custom_galaxy | entity.metadata.threat.detection_fields.value | Asignación directa del campo is_custom_galaxy del objeto Tag . La tecla está configurada como tag is_custom_galaxy . |
Tag.is_galaxy | entity.metadata.threat.detection_fields.value | Asignación directa del campo is_galaxy del objeto Tag . La tecla está configurada como tag is_galaxy . |
Tag.isinherited | entity.metadata.threat.detection_fields.value | Asignación directa del campo isinherited del objeto Tag . La tecla está configurada como tag isinherited . |
Tag.name | entity.metadata.threat.detection_fields.value | Asignación directa del campo name del objeto Tag . La tecla está configurada como tag name . |
Tag.numerical_value | entity.metadata.threat.detection_fields.value | Asignación directa del campo numerical_value del objeto Tag . La tecla está configurada como tag numerical_value . |
Tag.user_id | entity.metadata.threat.detection_fields.value | Asignación directa del campo user_id del objeto Tag . La tecla está configurada como tag user_id . |
threat_level | ioc.raw_severity | Asignación directa del campo threat_level . |
threat_level | entity.metadata.threat.severity_details | Asignación directa del campo threat_level . |
threat_level_id | entity.entity.labels.value | Asignación directa del campo threat_level_id . La tecla está configurada como threat_level_id . |
ts1 | ioc.active_timerange.start | Asignación directa del campo ts1 . El valor se analiza como una fecha. |
ts1 | entity.metadata.interval.start_time | Asignación directa del campo ts1 . El valor se analiza como una fecha. |
entity.entity.file.full_path | Se asigna si type es filename . |
|
entity.entity.file.md5 | Se asigna si type es md5 . |
|
entity.entity.file.sha1 | Se asigna si type es sha1 . |
|
entity.entity.file.sha256 | Se asigna si type es sha256 . |
|
entity.entity.hostname | Se asigna si type es domain . |
|
entity.entity.ip | Se asigna si type es ip-dst , ip-dst|port o ip-src . El valor se extrae mediante un patrón grok. |
|
entity.entity.port | Asignado si el campo port no está vacío. El valor se convierte en un número entero. |
|
entity.entity.resource.name | Se asigna si type es mutex . |
|
entity.entity.resource.resource_subtype | Se asigna si type es regkey . El valor se ha definido como regkey . |
|
entity.entity.resource.resource_type | Se asigna si type es mutex o regkey . El valor se define como MUTEX o STORAGE_OBJECT , respectivamente. |
|
entity.entity.registry.registry_key | Se asigna si type es regkey . |
|
entity.entity.url | Se asigna si type es uri o url . |
|
entity.metadata.collected_timestamp | El valor que se asigna es la marca de tiempo de la entrada de registro sin procesar. | |
entity.metadata.description | El valor se asigna al campo type si el registro sin procesar está en formato CSV. De lo contrario, se asigna al campo info . |
|
entity.metadata.entity_type | El valor se determina en función del campo type o log_type . Puede ser DOMAIN_NAME , FILE , IP_ADDRESS , MUTEX , RESOURCE o URL . |
|
entity.metadata.interval.end_time | El valor se define con un valor predeterminado de 253402300799 segundos. | |
entity.metadata.interval.start_time | El valor se asigna al campo first_seen si no está vacío. De lo contrario, se le asigna el valor predeterminado de 1 segundo o la marca de tiempo de la entrada de registro sin procesar. |
|
entity.metadata.product_name | El valor se ha definido como MISP . |
|
entity.metadata.threat.confidence | El valor se establece en UNKNOWN_CONFIDENCE si el campo confidence está vacío o es f . De lo contrario, se le asigna el valor HIGH_CONFIDENCE , MEDIUM_CONFIDENCE o LOW_CONFIDENCE en función del valor del campo confidence . |
|
entity.metadata.threat.confidence_details | Asignación directa del campo confidence . |
|
entity.metadata.threat.detection_fields | El valor es una lista de pares clave-valor extraídos de varios campos del registro sin procesar. | |
entity.metadata.vendor_name | El valor se ha definido como MISP . |
|
ioc.active_timerange.end | El valor se asigna al campo last_seen si no está vacío. |
|
ioc.active_timerange.start | El valor se asigna al campo ts1 o first_seen si no están vacíos. De lo contrario, se le asigna el valor predeterminado de 1 segundo. |
|
ioc.categorization | El valor es misp_category IOCs si el registro sin procesar está en formato CSV. De lo contrario, se le asigna el valor del campo category del objeto Attribute o log . |
|
ioc.confidence_score | Asignación directa del campo confidence . |
|
ioc.description | El valor se genera combinando el campo description con el campo event_info , separados por - additional info: . |
|
ioc.domain_and_ports.domain | Se asigna si type o log_type es domain . |
|
ioc.feed_name | El valor se establece en MISP si el campo event_source_org está vacío. De lo contrario, se asigna al campo event_source_org . |
|
ioc.ip_and_ports.ip_address | Asignado si el campo ip no está vacío. El valor se convierte en una dirección IP. |
|
ioc.ip_and_ports.ports | Asignado si el campo port no está vacío. El valor se convierte en un número entero sin signo. |
|
ioc.raw_severity | Asignación directa del campo threat_level . |
|
timestamp | El valor que se asigna es la marca de tiempo de la entrada de registro sin procesar. |
¿Necesitas más ayuda? Recibe respuestas de los miembros de la comunidad y de los profesionales de Google SecOps.