Collecter les journaux d'IOC MISP
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
- Connectez-vous à la console Google SecOps.
- Accédez à Paramètres SIEM> Agents de collecte.
- 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
- Connectez-vous à la console Google SecOps.
- Accédez à Paramètres SIEM*> Profil.
- Copiez et enregistrez le numéro client de la section Informations sur l'organisation.
Obtenir les identifiants de l'API MISP
- Connectez-vous à l'interface Web MISP en tant qu'administrateur.
- Accédez à Administration > Lister les clés d'authentification.
- Cliquez sur Ajouter une clé d'authentification.
- 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.
- Cliquez sur Envoyer.
- Copiez et enregistrez la clé API dans un endroit sûr.
- Cliquez sur J'ai noté ma clé.
Configurer l'exportation de données MISP
Installez PyMISP sur votre serveur MISP :
pip3 install pymisp
Créez le répertoire d'exportation :
sudo mkdir -p /opt/misp/scripts sudo mkdir -p /opt/misp/ioc_export
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.
- Remplacez
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)
- Rendez le script exécutable :
sudo chmod +x /opt/misp/scripts/misp_export.py
Planifier des exportations de données MISP
- Créez des exportations planifiées à l'aide de crontab :
sudo crontab -e
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
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
- Ouvrez un terminal avec les droits root ou sudo.
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
- Pour plus d'options d'installation, consultez le guide d'installation.
Configurer l'agent Bindplane pour ingérer les journaux MISP et les envoyer à Google SecOps
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
).
- Trouvez le fichier
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é.
- Remplacez
Redémarrez l'agent Bindplane pour appliquer les modifications.
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.