Collecter les journaux d'IOC MISP

Compatible avec :

Ce document explique comment ingérer des journaux d'IOC (indicateurs de compromission) MISP (Malware Information Sharing Platform) dans Google Security Operations à l'aide de Bindplane. Le parseur traite les données aux formats CSV et JSON. Il extrait les attributs d'IOC tels que les adresses IP, les domaines, les hachages et les URL, et les mappe à un modèle de données unifié (UDM) avec des informations sur les menaces telles que la gravité, la fiabilité et les descriptions. L'analyseur gère les entrées d'IOC uniques et multiples dans les données d'entrée, en les normalisant dans une sortie UDM cohérente.

Avant de commencer

Assurez-vous de remplir les conditions suivantes :

  • Une instance Google SecOps.
  • Un hôte Linux avec systemd.
  • Si vous exécutez l'agent derrière un proxy, assurez-vous que les ports de pare-feu sont ouverts conformément aux exigences de l'agent Bindplane.
  • Accès privilégié à votre serveur MISP.

Obtenir le fichier d'authentification d'ingestion Google SecOps

  1. Connectez-vous à la console Google SecOps.
  2. Accédez à Paramètres SIEM> Agents de collecte.
  3. Téléchargez le fichier d'authentification d'ingestion.
    • Enregistrez le fichier de manière sécurisée sur le système sur lequel Bindplane sera installé.

Obtenir l'ID client Google SecOps

  1. Connectez-vous à la console Google SecOps.
  2. Accédez à Paramètres SIEM*> Profil.
  3. Copiez et enregistrez le numéro client de la section Informations sur l'organisation.

Obtenir les identifiants de l'API MISP

  1. Connectez-vous à l'interface Web MISP en tant qu'administrateur.
  2. Accédez à Administration > Lister les clés d'authentification.
  3. Cliquez sur Ajouter une clé d'authentification.
  4. Fournissez les informations de configuration suivantes :
    • Utilisateur : sélectionnez le compte utilisateur associé à la clé.
    • Facultatif : Adresses IP autorisées : spécifiez les adresses IP autorisées pour la clé.
    • Expiration : laissez ce champ vide pour ne définir aucune date d'expiration ou définissez-la selon vos besoins.
  5. Cliquez sur Envoyer.
  6. Copiez et enregistrez la clé API dans un endroit sûr.
  7. Cliquez sur J'ai noté ma clé.

Configurer l'exportation de données MISP

  1. Installez PyMISP sur votre serveur MISP :

    pip3 install pymisp
    
  2. Créez le répertoire d'exportation :

    sudo mkdir -p /opt/misp/scripts
    sudo mkdir -p /opt/misp/ioc_export
    
  3. Créez le fichier d'identifiants /opt/misp/scripts/keys.py :

    misp_url = 'https://<MISP_SERVER_URL>'
    misp_key = '<MISP_API_KEY>'
    misp_verifycert = True
    misp_client_cert = ''
    
    • Remplacez <MISP_SERVER_URL> par l'URL de votre serveur MISP.
    • Remplacez <MISP_API_KEY> par la clé API des prérequis.
  4. Créez le script d'exportation /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. Rendez le script exécutable :
    sudo chmod +x /opt/misp/scripts/misp_export.py
    

    Planifier des exportations de données MISP

    1. Créez des exportations planifiées à l'aide de crontab :
    sudo crontab -e
    
  5. Ajoutez les entrées cron suivantes :

    # 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. Vous pouvez également planifier l'extraction de flux depuis 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
    

Installer l'agent Bindplane

Installez l'agent Bindplane sur votre système d'exploitation Linux en suivant les instructions ci-dessous.

Installation de Linux

  1. Ouvrez un terminal avec les droits root ou sudo.
  2. Exécutez la commande suivante :

    sudo sh -c "$(curl -fsSlL https://github.com/observiq/bindplane-otel-collector/releases/latest/download/install_unix.sh)" install_unix.sh
    

Ressources d'installation supplémentaires

Configurer l'agent Bindplane pour ingérer les journaux MISP et les envoyer à Google SecOps

  1. Accédez au fichier de configuration :

    • Trouvez le fichier config.yaml. Il se trouve généralement dans le répertoire /etc/bindplane-agent/ sous Linux.
    • Ouvrez le fichier à l'aide d'un éditeur de texte (par exemple, nano, vi).
  2. Modifiez le fichier config.yaml comme suit :

    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
    
    • Remplacez <CUSTOMER_ID> par votre numéro client réel indiqué dans les conditions préalables.
    • Remplacez /path/to/ingestion-authentication-file.json par le chemin d'accès à l'emplacement où le fichier d'authentification a été enregistré.

Redémarrez l'agent Bindplane pour appliquer les modifications.

  1. Pour redémarrer l'agent Bindplane sous Linux, exécutez la commande suivante :

    sudo systemctl restart observiq-otel-collector
    

Table de mappage UDM

Champ du journal Mappage UDM Logique
Attribute.category entity.metadata.threat.category_details Mappage direct à partir du champ category dans l'objet Attribute.
Attribute.comment entity.metadata.threat.summary Mappage direct à partir du champ comment dans l'objet Attribute.
Attribute.deleted entity.metadata.threat.detection_fields.value Mappage direct à partir du champ deleted dans l'objet Attribute. La clé est définie sur Attribute deleted.
Attribute.event_id entity.metadata.threat.detection_fields.value Mappage direct à partir du champ event_id dans l'objet Attribute. La clé est définie sur Attribute event_id.
Attribute.first_seen entity.metadata.threat.detection_fields.value Mappage direct à partir du champ first_seen dans l'objet Attribute. La clé est définie sur Attribute first_seen.
Attribute.id entity.metadata.threat.detection_fields.value Mappage direct à partir du champ id dans l'objet Attribute. La clé est définie sur Attribute id ou Attribute id $$ en fonction du format du journal brut.
Attribute.timestamp entity.metadata.threat.detection_fields.value Mappage direct à partir du champ timestamp dans l'objet Attribute. La clé est définie sur Attribute timestamp.
Attribute.to_ids entity.metadata.threat.detection_fields.value Mappage direct à partir du champ to_ids dans l'objet Attribute. La clé est définie sur Attribute to_ids.
Attribute.type entity.metadata.threat.category_details Mappage direct à partir du champ type dans l'objet Attribute.
Attribute.type log_type Permet de déterminer le type d'IOC et de le mapper aux champs UDM appropriés.
Attribute.uuid entity.metadata.product_entity_id Mappage direct à partir du champ uuid dans l'objet Attribute.
Attribute.value entity.entity.file.full_path Mappé si Attribute.type est filename.
Attribute.value entity.entity.file.md5 Mappé si Attribute.type est md5.
Attribute.value entity.entity.file.sha1 Mappé si Attribute.type est sha1.
Attribute.value entity.entity.file.sha256 Mappé si Attribute.type est sha256.
Attribute.value entity.entity.hostname Mappé si Attribute.type est domain.
Attribute.value entity.entity.ip Mappé si Attribute.type est ip-dst, ip-dst|port ou ip-src. La valeur est extraite à l'aide d'un modèle Grok.
Attribute.value entity.entity.resource.name Mappé si Attribute.type est mutex.
Attribute.value entity.entity.registry.registry_key Mappé si Attribute.type est regkey.
Attribute.value entity.entity.url Mappé si Attribute.type est uri ou URL.
column1 entity.metadata.product_entity_id Mappage direct à partir de la première colonne des données CSV.
column14 event_info Permet d'ajouter des informations au champ threat_sr.description.
column16 event_source_org Mappage direct à partir de la 16e colonne des données CSV.
column18 threat_level Mappage direct à partir de la 18e colonne des données CSV.
column21 description Mappage direct à partir de la 21e colonne des données CSV.
column3 misp_category Mappage direct à partir de la troisième colonne des données CSV.
column4 type Mappage direct à partir de la quatrième colonne des données CSV.
column5 valeur Mappage direct à partir de la cinquième colonne des données CSV.
column6 commentaire Mappage direct à partir de la sixième colonne des données CSV.
column8 ts1 Mappage direct à partir de la huitième colonne des données CSV.
description ioc.description La valeur est générée en combinant le champ description avec le champ event_info, séparés par - additional info:.
description entity.metadata.threat.description Mappage direct à partir du champ description.
event_creator_email entity.entity.labels.value Mappage direct à partir du champ event_creator_email. La clé est définie sur event_creator_email.
event_source_org ioc.feed_name Mappage direct à partir du champ event_source_org.
event_source_org entity.metadata.threat.threat_feed_name Mappage direct à partir du champ event_source_org.
Feed.publish entity.metadata.threat.detection_fields.value Mappage direct à partir du champ publish dans l'objet Feed. La clé est définie sur Feed publish.
first_seen ioc.active_timerange.start Mappage direct à partir du champ first_seen. La valeur est analysée en tant que date.
first_seen entity.metadata.interval.start_time Mappage direct à partir du champ first_seen. La valeur est analysée en tant que date.
info entity.metadata.description Mappage direct à partir du champ info.
last_seen ioc.active_timerange.end Mappage direct à partir du champ last_seen. La valeur est analysée en tant que date.
log.category ioc.categorization Mappage direct à partir du champ category dans l'objet log.
log.category entity.metadata.threat.category_details Mappage direct à partir du champ category dans l'objet log.
log.comment entity.entity.file.full_path Mappé si log.type est défini sur filename et que le champ comment n'est pas défini sur Artifacts dropped.
log.comment entity.metadata.threat.detection_fields.value Mappage direct à partir du champ comment dans l'objet log. La clé est définie sur Attribute comment.
log.comment entity.metadata.threat.summary Mappage direct à partir du champ comment dans l'objet log.
log.deleted entity.metadata.threat.detection_fields.value Mappage direct à partir du champ deleted dans l'objet log. La clé est définie sur Attribute deleted.
log.event_id entity.metadata.threat.detection_fields.value Mappage direct à partir du champ event_id dans l'objet log. La clé est définie sur Attribute event_id.
log.first_seen entity.metadata.threat.detection_fields.value Mappage direct à partir du champ first_seen dans l'objet log. La clé est définie sur Attribute first_seen.
log.id entity.metadata.threat.detection_fields.value Mappage direct à partir du champ id dans l'objet log. La clé est définie sur Attribute id.
log.timestamp entity.metadata.threat.detection_fields.value Mappage direct à partir du champ timestamp dans l'objet log. La clé est définie sur Attribute timestamp.
log.to_ids entity.metadata.threat.detection_fields.value Mappage direct à partir du champ to_ids dans l'objet log. La clé est définie sur Attribute to_ids.
log.type ioc.categorization Mappage direct à partir du champ type dans l'objet log.
log.type log_type Permet de déterminer le type d'IOC et de le mapper aux champs UDM appropriés.
log.uuid entity.metadata.product_entity_id Mappage direct à partir du champ uuid dans l'objet log.
log.value entity.entity.file.full_path Mappé si log.type est filename.
log.value entity.entity.file.md5 Mappé si log.type est md5.
log.value entity.entity.file.sha1 Mappé si log.type est sha1.
log.value entity.entity.file.sha256 Mappé si log.type est sha256.
log.value entity.entity.hostname Mappé si log.type est domain.
log.value entity.entity.ip Mappé si log.type est ip-dst, ip-dst|port ou ip-src. La valeur est extraite à l'aide d'un modèle Grok.
log.value entity.entity.resource.name Mappé si log.type est mutex.
log.value entity.entity.registry.registry_key Mappé si log.type est regkey.
log.value entity.entity.url Mappé si log.type est uri ou url.
log.value ioc.domain_and_ports.domain Mappé si log.type est domain.
log.value entity.entity.user.email_addresses Mappé si log.type est threat-actor.
misp_category entity.metadata.threat.category_details Mappage direct à partir du champ misp_category.
Org.name entity.metadata.threat.detection_fields.value Mappage direct à partir du champ name dans l'objet Org. La clé est définie sur Org name.
published entity.metadata.threat.detection_fields.value Mappage direct à partir du champ published. La clé est définie sur published.
Tag.colour entity.metadata.threat.detection_fields.value Mappage direct à partir du champ colour dans l'objet Tag. La clé est définie sur tag colour.
Tag.exportable entity.metadata.threat.detection_fields.value Mappage direct à partir du champ exportable dans l'objet Tag. La clé est définie sur tag exportable.
Tag.hide_tag entity.metadata.threat.detection_fields.value Mappage direct à partir du champ hide_tag dans l'objet Tag. La clé est définie sur tag hide_tag.
Tag.id entity.metadata.threat.detection_fields.value Mappage direct à partir du champ id dans l'objet Tag. La clé est définie sur tag id.
Tag.is_custom_galaxy entity.metadata.threat.detection_fields.value Mappage direct à partir du champ is_custom_galaxy dans l'objet Tag. La clé est définie sur tag is_custom_galaxy.
Tag.is_galaxy entity.metadata.threat.detection_fields.value Mappage direct à partir du champ is_galaxy dans l'objet Tag. La clé est définie sur tag is_galaxy.
Tag.isinherited entity.metadata.threat.detection_fields.value Mappage direct à partir du champ isinherited dans l'objet Tag. La clé est définie sur tag isinherited.
Tag.name entity.metadata.threat.detection_fields.value Mappage direct à partir du champ name dans l'objet Tag. La clé est définie sur tag name.
Tag.numerical_value entity.metadata.threat.detection_fields.value Mappage direct à partir du champ numerical_value dans l'objet Tag. La clé est définie sur tag numerical_value.
Tag.user_id entity.metadata.threat.detection_fields.value Mappage direct à partir du champ user_id dans l'objet Tag. La clé est définie sur tag user_id.
threat_level ioc.raw_severity Mappage direct à partir du champ threat_level.
threat_level entity.metadata.threat.severity_details Mappage direct à partir du champ threat_level.
threat_level_id entity.entity.labels.value Mappage direct à partir du champ threat_level_id. La clé est définie sur threat_level_id.
ts1 ioc.active_timerange.start Mappage direct à partir du champ ts1. La valeur est analysée en tant que date.
ts1 entity.metadata.interval.start_time Mappage direct à partir du champ ts1. La valeur est analysée en tant que date.
entity.entity.file.full_path Mappé si type est filename.
entity.entity.file.md5 Mappé si type est md5.
entity.entity.file.sha1 Mappé si type est sha1.
entity.entity.file.sha256 Mappé si type est sha256.
entity.entity.hostname Mappé si type est domain.
entity.entity.ip Mappé si type est ip-dst, ip-dst|port ou ip-src. La valeur est extraite à l'aide d'un modèle Grok.
entity.entity.port Mappé si le champ port n'est pas vide. La valeur est convertie en nombre entier.
entity.entity.resource.name Mappé si type est mutex.
entity.entity.resource.resource_subtype Mappé si type est regkey. La valeur est définie sur regkey.
entity.entity.resource.resource_type Mappé si type est mutex ou regkey. La valeur est définie sur MUTEX ou STORAGE_OBJECT, respectivement.
entity.entity.registry.registry_key Mappé si type est regkey.
entity.entity.url Mappé si type est uri ou url.
entity.metadata.collected_timestamp La valeur correspond au code temporel de l'entrée de journal brute.
entity.metadata.description La valeur est définie sur le champ type si le journal brut est au format CSV. Sinon, elle est définie sur le champ info.
entity.metadata.entity_type La valeur est déterminée en fonction du champ type ou log_type. Il peut s'agir de DOMAIN_NAME, FILE, IP_ADDRESS, MUTEX, RESOURCE ou URL.
entity.metadata.interval.end_time La valeur par défaut est de 253402300799 secondes.
entity.metadata.interval.start_time La valeur est définie sur le champ first_seen s'il n'est pas vide. Sinon, elle est définie sur une valeur par défaut de 1 seconde ou sur le code temporel de l'entrée de journal brute.
entity.metadata.product_name La valeur est définie sur MISP.
entity.metadata.threat.confidence La valeur est définie sur UNKNOWN_CONFIDENCE si le champ confidence est vide ou f. Sinon, elle est définie sur HIGH_CONFIDENCE, MEDIUM_CONFIDENCE ou LOW_CONFIDENCE en fonction de la valeur du champ confidence.
entity.metadata.threat.confidence_details Mappage direct à partir du champ confidence.
entity.metadata.threat.detection_fields La valeur est une liste de paires clé/valeur extraites de différents champs du journal brut.
entity.metadata.vendor_name La valeur est définie sur MISP.
ioc.active_timerange.end La valeur est définie sur le champ last_seen s'il n'est pas vide.
ioc.active_timerange.start La valeur est définie sur le champ ts1 ou first_seen s'ils ne sont pas vides. Sinon, elle est définie sur une valeur par défaut de 1 seconde.
ioc.categorization La valeur est définie sur misp_category IOCs si le journal brut est au format CSV. Sinon, il est défini sur le champ category dans l'objet Attribute ou log.
ioc.confidence_score Mappage direct à partir du champ confidence.
ioc.description La valeur est générée en combinant le champ description avec le champ event_info, séparés par - additional info:.
ioc.domain_and_ports.domain Mappé si type ou log_type est domain.
ioc.feed_name La valeur est définie sur MISP si le champ event_source_org est vide. Sinon, elle est définie sur le champ event_source_org.
ioc.ip_and_ports.ip_address Mappé si le champ ip n'est pas vide. La valeur est convertie en adresse IP.
ioc.ip_and_ports.ports Mappé si le champ port n'est pas vide. La valeur est convertie en entier non signé.
ioc.raw_severity Mappage direct à partir du champ threat_level.
timestamp La valeur correspond au code temporel de l'entrée de journal brute.

Vous avez encore besoin d'aide ? Obtenez des réponses de membres de la communauté et de professionnels Google SecOps.