Recoger registros de IOC de MISP

Disponible en:

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

  1. Inicia sesión en la consola de Google SecOps.
  2. Ve a Configuración de SIEM > Agentes de recogida.
  3. 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

  1. Inicia sesión en la consola de Google SecOps.
  2. Ve a Configuración de SIEM*> Perfil.
  3. Copia y guarda el ID de cliente de la sección Detalles de la organización.

Obtener credenciales de la API de MISP

  1. Inicia sesión en la interfaz web de MISP como administrador.
  2. Vaya a Administración > Listar claves de autenticación.
  3. Haz clic en Añadir clave de autenticación.
  4. 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.
  5. Haz clic en Enviar.
  6. Copia y guarda la clave de API en un lugar seguro.
  7. Haz clic en He anotado mi clave.

Configurar la exportación de datos de MISP

  1. Instala PyMISP en tu servidor MISP:

    pip3 install pymisp
    
  2. Crea el directorio de exportación:

    sudo mkdir -p /opt/misp/scripts
    sudo mkdir -p /opt/misp/ioc_export
    
  3. 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.
  4. 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)
    
    1. Haz que la secuencia de comandos sea ejecutable:
    sudo chmod +x /opt/misp/scripts/misp_export.py
    

    Programar exportaciones de datos de MISP

    1. Crea exportaciones programadas con crontab:
    sudo crontab -e
    
  5. 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
    
  6. 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

  1. Abre un terminal con privilegios de superusuario o sudo.
  2. 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

Configurar el agente de Bindplane para ingerir registros de MISP y enviarlos a Google SecOps

  1. 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 o vi).
  2. 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.

Reinicia el agente de Bindplane para aplicar los cambios

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