Recopila registros de IOC de MISP
En este documento, se explica cómo transferir registros de IOC de MISP (Malware Information Sharing Platform) a Google Security Operations con Bindplane. El analizador procesa los datos en formatos CSV y JSON. Extrae atributos de IOC, como direcciones IP, dominios, hashes y URLs, y los asigna a un modelo de datos unificado (UDM) junto con detalles de amenazas, como gravedad, confianza y descripciones. El analizador controla las entradas de IOC únicas y múltiples dentro de los datos de entrada, y las normaliza en una salida de UDM coherente.
Antes de comenzar
Asegúrate de cumplir con los siguientes requisitos previos:
- Es una instancia de Google SecOps.
- Un host de Linux con
systemd
. - Si se ejecuta detrás de un proxy, asegúrate de que los puertos de firewall estén abiertos según los requisitos del agente de Bindplane.
- Acceso con privilegios a tu servidor de MISP
Obtén el archivo de autenticación de transferencia de Google SecOps
- Accede a la consola de Google SecOps.
- Ve a Configuración de SIEM > Agentes de recopilación.
- Descarga el archivo de autenticación de transferencia.
- Guarda el archivo de forma segura en el sistema en el que se instalará BindPlane.
Obtén el ID de cliente de Google SecOps
- Accede a 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.
Obtén credenciales de la API de MISP
- Accede a la interfaz web de MISP como administrador.
- Ve a Administración > List Auth Keys.
- Haz clic en Agregar clave de autenticación.
- Proporciona los siguientes detalles de configuración:
- Usuario: Selecciona la cuenta de usuario asociada con la clave.
- Opcional: IPs permitidas: Especifica las direcciones IP permitidas para la clave.
- Vencimiento: Deja el campo vacío si no quieres que venza o configúralo según sea necesario.
- Haz clic en Enviar.
- Copia y guarda la clave de API en una ubicación segura.
- Haz clic en Anoté mi clave.
Configura la exportación de datos de MISP
Instala PyMISP en tu servidor de 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 = ''
- Reemplaza
<MISP_SERVER_URL>
por la URL de tu servidor de MISP. - Reemplaza
<MISP_API_KEY>
por la clave de API de los requisitos previos.
- Reemplaza
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
Programa exportaciones de datos de MISP
- Crea exportaciones programadas con crontab:
sudo crontab -e
Agrega las siguientes entradas de 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
De manera opcional, programa una extracción de feeds desde 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
Instala el agente de BindPlane
Instala el agente de Bindplane en tu sistema operativo Linux según las siguientes instrucciones.
Instalación en Linux
- Abre una terminal con privilegios de raíz 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 obtener más opciones de instalación, consulta la guía de instalación.
Configura el agente de BindPlane para que ingiera registros de MISP y los envíe a Google SecOps
Accede al archivo de configuración:
- Ubica el archivo
config.yaml
. Por lo general, se encuentra en el directorio/etc/bindplane-agent/
en Linux. - Abre el archivo con un editor de texto (por ejemplo,
nano
,vi
).
- Ubica 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
- Reemplaza
<CUSTOMER_ID>
por tu ID de cliente real de los requisitos previos. - Actualiza
/path/to/ingestion-authentication-file.json
a la ruta de acceso en la que se guardó el archivo de autenticación.
- Reemplaza
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 | Es una asignación directa del campo category en el objeto Attribute . |
Attribute.comment | entity.metadata.threat.summary | Es una asignación directa del campo comment en el objeto Attribute . |
Attribute.deleted | entity.metadata.threat.detection_fields.value | Es una asignación directa del campo deleted en el objeto Attribute . La clave se establece en Attribute deleted . |
Attribute.event_id | entity.metadata.threat.detection_fields.value | Es una asignación directa del campo event_id en el objeto Attribute . La clave se establece en Attribute event_id . |
Attribute.first_seen | entity.metadata.threat.detection_fields.value | Es una asignación directa del campo first_seen en el objeto Attribute . La clave se establece en Attribute first_seen . |
Attribute.id | entity.metadata.threat.detection_fields.value | Es una asignación directa del campo id en el objeto Attribute . La clave se establece en Attribute id o Attribute id $$ según el formato del registro sin procesar. |
Attribute.timestamp | entity.metadata.threat.detection_fields.value | Es una asignación directa del campo timestamp en el objeto Attribute . La clave se establece en Attribute timestamp . |
Attribute.to_ids | entity.metadata.threat.detection_fields.value | Es una asignación directa del campo to_ids en el objeto Attribute . La clave se establece en Attribute to_ids . |
Attribute.type | entity.metadata.threat.category_details | Es una asignación directa del campo type en el 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 | Es una asignación directa del campo uuid en el 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 con un patrón de 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 . |
column1 | entity.metadata.product_entity_id | Asignación directa desde la primera columna de los datos CSV. |
column14 | event_info | Se usa para agregar información adicional al campo threat_sr.description . |
column16 | event_source_org | Asignación directa desde la columna 16 en los datos CSV. |
column18 | threat_level | Asignación directa desde la columna 18 en los datos CSV. |
column21 | descripción | Asignación directa desde la columna 21 en los datos CSV. |
column3 | misp_category | Asignación directa de la tercera columna de los datos CSV. |
column4 | tipo | Asignación directa desde la cuarta columna de los datos CSV. |
column5 | valor | Asignación directa desde la quinta columna de los datos CSV. |
column6 | comentario | Asignación directa desde la sexta columna de los datos CSV. |
column8 | ts1 | Asignación directa desde la octava columna de los datos CSV. |
descripción | ioc.description | El valor se genera combinando el campo description con el campo event_info , separados por - additional info: . |
descripción | 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 clave se establece en 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 | Es una asignación directa del campo publish en el objeto Feed . La clave se establece en 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 | Es una asignación directa del campo category en el objeto log . |
log.category | entity.metadata.threat.category_details | Es una asignación directa del campo category en el 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 | Es una asignación directa del campo comment en el objeto log . La clave se establece en Attribute comment . |
log.comment | entity.metadata.threat.summary | Es una asignación directa del campo comment en el objeto log . |
log.deleted | entity.metadata.threat.detection_fields.value | Es una asignación directa del campo deleted en el objeto log . La clave se establece en Attribute deleted . |
log.event_id | entity.metadata.threat.detection_fields.value | Es una asignación directa del campo event_id en el objeto log . La clave se establece en Attribute event_id . |
log.first_seen | entity.metadata.threat.detection_fields.value | Es una asignación directa del campo first_seen en el objeto log . La clave se establece en Attribute first_seen . |
log.id | entity.metadata.threat.detection_fields.value | Es una asignación directa del campo id en el objeto log . La clave se establece en Attribute id . |
log.timestamp | entity.metadata.threat.detection_fields.value | Es una asignación directa del campo timestamp en el objeto log . La clave se establece en Attribute timestamp . |
log.to_ids | entity.metadata.threat.detection_fields.value | Es una asignación directa del campo to_ids en el objeto log . La clave se establece en Attribute to_ids . |
log.type | ioc.categorization | Es una asignación directa del campo type en el 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 | Es una asignación directa del campo uuid en el 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 con un patrón de 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 | Es una asignación directa del campo name en el objeto Org . La clave se establece en Org name . |
published | entity.metadata.threat.detection_fields.value | Asignación directa del campo published . La clave se establece en published . |
Tag.colour | entity.metadata.threat.detection_fields.value | Es una asignación directa del campo colour en el objeto Tag . La clave se establece en tag colour . |
Tag.exportable | entity.metadata.threat.detection_fields.value | Es una asignación directa del campo exportable en el objeto Tag . La clave se establece en tag exportable . |
Tag.hide_tag | entity.metadata.threat.detection_fields.value | Es una asignación directa del campo hide_tag en el objeto Tag . La clave se establece en tag hide_tag . |
Tag.id | entity.metadata.threat.detection_fields.value | Es una asignación directa del campo id en el objeto Tag . La clave se establece en tag id . |
Tag.is_custom_galaxy | entity.metadata.threat.detection_fields.value | Es una asignación directa del campo is_custom_galaxy en el objeto Tag . La clave se establece en tag is_custom_galaxy . |
Tag.is_galaxy | entity.metadata.threat.detection_fields.value | Es una asignación directa del campo is_galaxy en el objeto Tag . La clave se establece en tag is_galaxy . |
Tag.isinherited | entity.metadata.threat.detection_fields.value | Es una asignación directa del campo isinherited en el objeto Tag . La clave se establece en tag isinherited . |
Tag.name | entity.metadata.threat.detection_fields.value | Es una asignación directa del campo name en el objeto Tag . La clave se establece en tag name . |
Tag.numerical_value | entity.metadata.threat.detection_fields.value | Es una asignación directa del campo numerical_value en el objeto Tag . La clave se establece en tag numerical_value . |
Tag.user_id | entity.metadata.threat.detection_fields.value | Es una asignación directa del campo user_id en el objeto Tag . La clave se establece en 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 clave se establece en 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 con un patrón de Grok. |
|
entity.entity.port | Se asigna 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 establece en regkey . |
|
entity.entity.resource.resource_type | Se asigna si type es mutex o regkey . El valor se establece en 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 se establece en la marca de tiempo de la entrada de registro sin procesar. | |
entity.metadata.description | El valor se establece en el campo type si el registro sin procesar está en formato CSV. De lo contrario, se establece en el campo info . |
|
entity.metadata.entity_type | El valor se determina según el campo type o log_type . Puede ser DOMAIN_NAME , FILE , IP_ADDRESS , MUTEX , RESOURCE o URL . |
|
entity.metadata.interval.end_time | El valor se establece en un valor predeterminado de 253402300799 segundos. | |
entity.metadata.interval.start_time | El valor se establece en el campo first_seen si no está vacío. De lo contrario, se establece en un valor predeterminado de 1 segundo o en la marca de tiempo de la entrada de registro sin procesar. |
|
entity.metadata.product_name | El valor se establece en 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 establece en HIGH_CONFIDENCE , MEDIUM_CONFIDENCE o LOW_CONFIDENCE según el 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 establece en MISP . |
|
ioc.active_timerange.end | El valor se establece en el campo last_seen si no está vacío. |
|
ioc.active_timerange.start | El valor se establece en el campo ts1 o first_seen si no están vacíos. De lo contrario, se establece en un valor predeterminado de 1 segundo. |
|
ioc.categorization | El valor se establece en misp_category IOCs si el registro sin procesar está en formato CSV. De lo contrario, se establece en el 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 establece en el campo event_source_org . |
|
ioc.ip_and_ports.ip_address | Se asigna si el campo ip no está vacío. El valor se convierte en una dirección IP. |
|
ioc.ip_and_ports.ports | Se asigna 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 se establece en la marca de tiempo de la entrada de registro sin procesar. |
¿Necesitas más ayuda? Obtén respuestas de miembros de la comunidad y profesionales de Google SecOps.