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, nanoovi).
 
- Busca el archivo 
- Edita el archivo - config.yamlde 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.jsona 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 categorydel objetoAttribute. | 
| Attribute.comment | entity.metadata.threat.summary | Asignación directa del campo commentdel objetoAttribute. | 
| Attribute.deleted | entity.metadata.threat.detection_fields.value | Asignación directa del campo deleteddel objetoAttribute. La tecla está configurada comoAttribute deleted. | 
| Attribute.event_id | entity.metadata.threat.detection_fields.value | Asignación directa del campo event_iddel objetoAttribute. La tecla está configurada comoAttribute event_id. | 
| Attribute.first_seen | entity.metadata.threat.detection_fields.value | Asignación directa del campo first_seendel objetoAttribute. La tecla está configurada comoAttribute first_seen. | 
| Attribute.id | entity.metadata.threat.detection_fields.value | Asignación directa del campo iddel objetoAttribute. La clave se define comoAttribute idoAttribute id $$en función del formato del registro sin procesar. | 
| Attribute.timestamp | entity.metadata.threat.detection_fields.value | Asignación directa del campo timestampdel objetoAttribute. La tecla está configurada comoAttribute timestamp. | 
| Attribute.to_ids | entity.metadata.threat.detection_fields.value | Asignación directa del campo to_idsdel objetoAttribute. La tecla está configurada comoAttribute to_ids. | 
| Attribute.type | entity.metadata.threat.category_details | Asignación directa del campo typedel objetoAttribute. | 
| 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 uuiddel objetoAttribute. | 
| Attribute.value | entity.entity.file.full_path | Se asigna si Attribute.typeesfilename. | 
| Attribute.value | entity.entity.file.md5 | Se asigna si Attribute.typeesmd5. | 
| Attribute.value | entity.entity.file.sha1 | Se asigna si Attribute.typeessha1. | 
| Attribute.value | entity.entity.file.sha256 | Se asigna si Attribute.typeessha256. | 
| Attribute.value | entity.entity.hostname | Se asigna si Attribute.typeesdomain. | 
| Attribute.value | entity.entity.ip | Se asigna si Attribute.typeesip-dst,ip-dst|portoip-src. El valor se extrae mediante un patrón grok. | 
| Attribute.value | entity.entity.resource.name | Se asigna si Attribute.typeesmutex. | 
| Attribute.value | entity.entity.registry.registry_key | Se asigna si Attribute.typeesregkey. | 
| Attribute.value | entity.entity.url | Se asigna si Attribute.typeesurioURL. | 
| 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 descriptioncon el campoevent_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 comoevent_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 publishdel objetoFeed. La tecla está configurada comoFeed 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 categorydel objetolog. | 
| log.category | entity.metadata.threat.category_details | Asignación directa del campo categorydel objetolog. | 
| log.comment | entity.entity.file.full_path | Se asigna si log.typeesfilenamey el campocommentno esArtifacts dropped. | 
| log.comment | entity.metadata.threat.detection_fields.value | Asignación directa del campo commentdel objetolog. La tecla está configurada comoAttribute comment. | 
| log.comment | entity.metadata.threat.summary | Asignación directa del campo commentdel objetolog. | 
| log.deleted | entity.metadata.threat.detection_fields.value | Asignación directa del campo deleteddel objetolog. La tecla está configurada comoAttribute deleted. | 
| log.event_id | entity.metadata.threat.detection_fields.value | Asignación directa del campo event_iddel objetolog. La tecla está configurada comoAttribute event_id. | 
| log.first_seen | entity.metadata.threat.detection_fields.value | Asignación directa del campo first_seendel objetolog. La tecla está configurada comoAttribute first_seen. | 
| log.id | entity.metadata.threat.detection_fields.value | Asignación directa del campo iddel objetolog. La tecla está configurada comoAttribute id. | 
| log.timestamp | entity.metadata.threat.detection_fields.value | Asignación directa del campo timestampdel objetolog. La tecla está configurada comoAttribute timestamp. | 
| log.to_ids | entity.metadata.threat.detection_fields.value | Asignación directa del campo to_idsdel objetolog. La tecla está configurada comoAttribute to_ids. | 
| log.type | ioc.categorization | Asignación directa del campo typedel objetolog. | 
| 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 uuiddel objetolog. | 
| log.value | entity.entity.file.full_path | Se asigna si log.typeesfilename. | 
| log.value | entity.entity.file.md5 | Se asigna si log.typeesmd5. | 
| log.value | entity.entity.file.sha1 | Se asigna si log.typeessha1. | 
| log.value | entity.entity.file.sha256 | Se asigna si log.typeessha256. | 
| log.value | entity.entity.hostname | Se asigna si log.typeesdomain. | 
| log.value | entity.entity.ip | Se asigna si log.typeesip-dst,ip-dst|portoip-src. El valor se extrae mediante un patrón grok. | 
| log.value | entity.entity.resource.name | Se asigna si log.typeesmutex. | 
| log.value | entity.entity.registry.registry_key | Se asigna si log.typeesregkey. | 
| log.value | entity.entity.url | Se asigna si log.typeesuriourl. | 
| log.value | ioc.domain_and_ports.domain | Se asigna si log.typeesdomain. | 
| log.value | entity.entity.user.email_addresses | Se asigna si log.typeesthreat-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 namedel objetoOrg. La tecla está configurada comoOrg name. | 
| published | entity.metadata.threat.detection_fields.value | Asignación directa del campo published. La tecla está configurada comopublished. | 
| Tag.colour | entity.metadata.threat.detection_fields.value | Asignación directa del campo colourdel objetoTag. La tecla está configurada comotag colour. | 
| Tag.exportable | entity.metadata.threat.detection_fields.value | Asignación directa del campo exportabledel objetoTag. La tecla está configurada comotag exportable. | 
| Tag.hide_tag | entity.metadata.threat.detection_fields.value | Asignación directa del campo hide_tagdel objetoTag. La tecla está configurada comotag hide_tag. | 
| Tag.id | entity.metadata.threat.detection_fields.value | Asignación directa del campo iddel objetoTag. La tecla está configurada comotag id. | 
| Tag.is_custom_galaxy | entity.metadata.threat.detection_fields.value | Asignación directa del campo is_custom_galaxydel objetoTag. La tecla está configurada comotag is_custom_galaxy. | 
| Tag.is_galaxy | entity.metadata.threat.detection_fields.value | Asignación directa del campo is_galaxydel objetoTag. La tecla está configurada comotag is_galaxy. | 
| Tag.isinherited | entity.metadata.threat.detection_fields.value | Asignación directa del campo isinheriteddel objetoTag. La tecla está configurada comotag isinherited. | 
| Tag.name | entity.metadata.threat.detection_fields.value | Asignación directa del campo namedel objetoTag. La tecla está configurada comotag name. | 
| Tag.numerical_value | entity.metadata.threat.detection_fields.value | Asignación directa del campo numerical_valuedel objetoTag. La tecla está configurada comotag numerical_value. | 
| Tag.user_id | entity.metadata.threat.detection_fields.value | Asignación directa del campo user_iddel objetoTag. La tecla está configurada comotag 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 comothreat_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 typeesfilename. | |
| entity.entity.file.md5 | Se asigna si typeesmd5. | |
| entity.entity.file.sha1 | Se asigna si typeessha1. | |
| entity.entity.file.sha256 | Se asigna si typeessha256. | |
| entity.entity.hostname | Se asigna si typeesdomain. | |
| entity.entity.ip | Se asigna si typeesip-dst,ip-dst|portoip-src. El valor se extrae mediante un patrón grok. | |
| entity.entity.port | Asignado si el campo portno está vacío. El valor se convierte en un número entero. | |
| entity.entity.resource.name | Se asigna si typeesmutex. | |
| entity.entity.resource.resource_subtype | Se asigna si typeesregkey. El valor se ha definido comoregkey. | |
| entity.entity.resource.resource_type | Se asigna si typeesmutexoregkey. El valor se define comoMUTEXoSTORAGE_OBJECT, respectivamente. | |
| entity.entity.registry.registry_key | Se asigna si typeesregkey. | |
| entity.entity.url | Se asigna si typeesuriourl. | |
| 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 typesi el registro sin procesar está en formato CSV. De lo contrario, se asigna al campoinfo. | |
| entity.metadata.entity_type | El valor se determina en función del campo typeolog_type. Puede serDOMAIN_NAME,FILE,IP_ADDRESS,MUTEX,RESOURCEoURL. | |
| 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_seensi 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_CONFIDENCEsi el campoconfidenceestá vacío o esf. De lo contrario, se le asigna el valorHIGH_CONFIDENCE,MEDIUM_CONFIDENCEoLOW_CONFIDENCEen función del valor del campoconfidence. | |
| 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_seensi no está vacío. | |
| ioc.active_timerange.start | El valor se asigna al campo ts1ofirst_seensi no están vacíos. De lo contrario, se le asigna el valor predeterminado de 1 segundo. | |
| ioc.categorization | El valor es misp_category IOCssi el registro sin procesar está en formato CSV. De lo contrario, se le asigna el valor del campocategorydel objetoAttributeolog. | |
| ioc.confidence_score | Asignación directa del campo confidence. | |
| ioc.description | El valor se genera combinando el campo descriptioncon el campoevent_info, separados por-  additional info:. | |
| ioc.domain_and_ports.domain | Se asigna si typeolog_typeesdomain. | |
| ioc.feed_name | El valor se establece en MISPsi el campoevent_source_orgestá vacío. De lo contrario, se asigna al campoevent_source_org. | |
| ioc.ip_and_ports.ip_address | Asignado si el campo ipno está vacío. El valor se convierte en una dirección IP. | |
| ioc.ip_and_ports.ports | Asignado si el campo portno 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.