Raccogliere i log IOC di MISP
Questo documento spiega come importare i log IOC (Indicator of Compromise) di MISP (Malware Information Sharing Platform) in Google Security Operations utilizzando Bindplane. Il parser elabora i dati nei formati CSV e JSON. Estrae gli attributi IOC come indirizzi IP, domini, hash e URL, mappandoli a un modello UDM (Unified Data Model) insieme ai dettagli delle minacce come gravità, confidenza e descrizioni. Il parser gestisce voci IOC singole e multiple all'interno dei dati di input, normalizzandole in un output UDM coerente.
Prima di iniziare
Assicurati di soddisfare i seguenti prerequisiti:
- Un'istanza Google SecOps.
- Un host Linux con
systemd
. - Se l'agente viene eseguito tramite un proxy, assicurati che le porte del firewall siano aperte in base ai requisiti dell'agente Bindplane.
- Accesso con privilegi al server MISP.
Recuperare il file di autenticazione importazione di Google SecOps
- Accedi alla console Google SecOps.
- Vai a Impostazioni SIEM > Agenti di raccolta.
- Scarica il file di autenticazione importazione.
- Salva il file in modo sicuro sul sistema in cui verrà installato Bindplane.
Recuperare l'ID cliente Google SecOps
- Accedi alla console Google SecOps.
- Vai a Impostazioni SIEM*> Profilo.
- Copia e salva l'ID cliente dalla sezione Dettagli dell'organizzazione.
Ottenere le credenziali API MISP
- Accedi all'interfaccia web di MISP come amministratore.
- Vai ad Amministrazione > Elenca chiavi di autenticazione.
- Fai clic su Aggiungi chiave di autenticazione.
- Fornisci i seguenti dettagli di configurazione:
- Utente: seleziona l'account utente associato alla chiave.
- (Facoltativo) IP consentiti: specifica gli indirizzi IP consentiti per la chiave.
- Scadenza: lascia vuoto per nessuna scadenza o imposta in base alle esigenze.
- Fai clic su Invia.
- Copia e salva la chiave API in un luogo sicuro.
- Fai clic su Ho annotato la mia chiave.
Configura l'esportazione dei dati MISP
Installa PyMISP sul server MISP:
pip3 install pymisp
Crea la directory di esportazione:
sudo mkdir -p /opt/misp/scripts sudo mkdir -p /opt/misp/ioc_export
Crea il file delle credenziali
/opt/misp/scripts/keys.py
:misp_url = 'https://<MISP_SERVER_URL>' misp_key = '<MISP_API_KEY>' misp_verifycert = True misp_client_cert = ''
- Sostituisci
<MISP_SERVER_URL>
con l'URL del server MISP. - Sostituisci
<MISP_API_KEY>
con la chiave API dei prerequisiti.
- Sostituisci
Crea lo script di esportazione
/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)
- Rendi eseguibile lo script:
sudo chmod +x /opt/misp/scripts/misp_export.py
Pianificare le esportazioni di dati MISP
- Crea esportazioni programmate utilizzando crontab:
sudo crontab -e
Aggiungi le seguenti voci 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
(Facoltativo) Pianifica un pull dei feed da 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
Installa l'agente Bindplane
Installa l'agente Bindplane sul sistema operativo Linux seguendo queste istruzioni.
Installazione di Linux
- Apri un terminale con privilegi root o sudo.
Esegui questo comando:
sudo sh -c "$(curl -fsSlL https://github.com/observiq/bindplane-otel-collector/releases/latest/download/install_unix.sh)" install_unix.sh
Risorse aggiuntive per l'installazione
- Per ulteriori opzioni di installazione, consulta la guida all'installazione.
Configura l'agente Bindplane per importare i log MISP e inviarli a Google SecOps
Accedi al file di configurazione:
- Individua il file
config.yaml
. In genere si trova nella directory/etc/bindplane-agent/
su Linux. - Apri il file utilizzando un editor di testo (ad esempio
nano
,vi
).
- Individua il file
Modifica il file
config.yaml
come segue: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
- Sostituisci
<CUSTOMER_ID>
con il tuo ID cliente effettivo dai prerequisiti. - Aggiorna
/path/to/ingestion-authentication-file.json
al percorso in cui è stato salvato il file di autenticazione.
- Sostituisci
Riavvia l'agente Bindplane per applicare le modifiche
Per riavviare l'agente Bindplane in Linux, esegui questo comando:
sudo systemctl restart observiq-otel-collector
Tabella di mappatura UDM
Campo log | Mappatura UDM | Logic |
---|---|---|
Attribute.category | entity.metadata.threat.category_details | Mappatura diretta dal campo category nell'oggetto Attribute . |
Attribute.comment | entity.metadata.threat.summary | Mappatura diretta dal campo comment nell'oggetto Attribute . |
Attribute.deleted | entity.metadata.threat.detection_fields.value | Mappatura diretta dal campo deleted nell'oggetto Attribute . Il tasto è impostato su Attribute deleted . |
Attribute.event_id | entity.metadata.threat.detection_fields.value | Mappatura diretta dal campo event_id nell'oggetto Attribute . Il tasto è impostato su Attribute event_id . |
Attribute.first_seen | entity.metadata.threat.detection_fields.value | Mappatura diretta dal campo first_seen nell'oggetto Attribute . Il tasto è impostato su Attribute first_seen . |
Attribute.id | entity.metadata.threat.detection_fields.value | Mappatura diretta dal campo id nell'oggetto Attribute . La chiave è impostata su Attribute id o Attribute id $$ a seconda del formato del log non elaborato. |
Attribute.timestamp | entity.metadata.threat.detection_fields.value | Mappatura diretta dal campo timestamp nell'oggetto Attribute . Il tasto è impostato su Attribute timestamp . |
Attribute.to_ids | entity.metadata.threat.detection_fields.value | Mappatura diretta dal campo to_ids nell'oggetto Attribute . Il tasto è impostato su Attribute to_ids . |
Attribute.type | entity.metadata.threat.category_details | Mappatura diretta dal campo type nell'oggetto Attribute . |
Attribute.type | log_type | Utilizzato per determinare il tipo di indicatore di compromissione e mapparlo ai campi UDM appropriati. |
Attribute.uuid | entity.metadata.product_entity_id | Mappatura diretta dal campo uuid nell'oggetto Attribute . |
Attribute.value | entity.entity.file.full_path | Mappato se Attribute.type è filename . |
Attribute.value | entity.entity.file.md5 | Mappato se Attribute.type è md5 . |
Attribute.value | entity.entity.file.sha1 | Mappato se Attribute.type è sha1 . |
Attribute.value | entity.entity.file.sha256 | Mappato se Attribute.type è sha256 . |
Attribute.value | entity.entity.hostname | Mappato se Attribute.type è domain . |
Attribute.value | entity.entity.ip | Mappato se Attribute.type è ip-dst , ip-dst|port o ip-src . Il valore viene estratto utilizzando un pattern grok. |
Attribute.value | entity.entity.resource.name | Mappato se Attribute.type è mutex . |
Attribute.value | entity.entity.registry.registry_key | Mappato se Attribute.type è regkey . |
Attribute.value | entity.entity.url | Mappato se Attribute.type è uri o URL . |
colonna1 | entity.metadata.product_entity_id | Mappatura diretta dalla prima colonna dei dati CSV. |
column14 | event_info | Utilizzato per aggiungere informazioni aggiuntive al campo threat_sr.description . |
column16 | event_source_org | Mappatura diretta dalla sedicesima colonna dei dati CSV. |
column18 | threat_level | Mappatura diretta dalla 18ª colonna dei dati CSV. |
column21 | descrizione | Mappatura diretta dalla 21ª colonna dei dati CSV. |
colonna3 | misp_category | Mappatura diretta dalla terza colonna dei dati CSV. |
column4 | tipo | Mappatura diretta dalla quarta colonna dei dati CSV. |
column5 | valore | Mappatura diretta dalla quinta colonna dei dati CSV. |
column6 | commento | Mappatura diretta dalla sesta colonna dei dati CSV. |
column8 | ts1 | Mappatura diretta dall'ottava colonna dei dati CSV. |
descrizione | ioc.description | Il valore viene generato combinando il campo description con il campo event_info , separati da - additional info: . |
descrizione | entity.metadata.threat.description | Mappatura diretta dal campo description . |
event_creator_email | entity.entity.labels.value | Mappatura diretta dal campo event_creator_email . Il tasto è impostato su event_creator_email . |
event_source_org | ioc.feed_name | Mappatura diretta dal campo event_source_org . |
event_source_org | entity.metadata.threat.threat_feed_name | Mappatura diretta dal campo event_source_org . |
Feed.publish | entity.metadata.threat.detection_fields.value | Mappatura diretta dal campo publish nell'oggetto Feed . Il tasto è impostato su Feed publish . |
first_seen | ioc.active_timerange.start | Mappatura diretta dal campo first_seen . Il valore viene analizzato come data. |
first_seen | entity.metadata.interval.start_time | Mappatura diretta dal campo first_seen . Il valore viene analizzato come data. |
informazioni | entity.metadata.description | Mappatura diretta dal campo info . |
last_seen | ioc.active_timerange.end | Mappatura diretta dal campo last_seen . Il valore viene analizzato come data. |
log.category | ioc.categorization | Mappatura diretta dal campo category nell'oggetto log . |
log.category | entity.metadata.threat.category_details | Mappatura diretta dal campo category nell'oggetto log . |
log.comment | entity.entity.file.full_path | Mappato se log.type è filename e il campo comment non è Artifacts dropped . |
log.comment | entity.metadata.threat.detection_fields.value | Mappatura diretta dal campo comment nell'oggetto log . Il tasto è impostato su Attribute comment . |
log.comment | entity.metadata.threat.summary | Mappatura diretta dal campo comment nell'oggetto log . |
log.deleted | entity.metadata.threat.detection_fields.value | Mappatura diretta dal campo deleted nell'oggetto log . Il tasto è impostato su Attribute deleted . |
log.event_id | entity.metadata.threat.detection_fields.value | Mappatura diretta dal campo event_id nell'oggetto log . Il tasto è impostato su Attribute event_id . |
log.first_seen | entity.metadata.threat.detection_fields.value | Mappatura diretta dal campo first_seen nell'oggetto log . Il tasto è impostato su Attribute first_seen . |
log.id | entity.metadata.threat.detection_fields.value | Mappatura diretta dal campo id nell'oggetto log . Il tasto è impostato su Attribute id . |
log.timestamp | entity.metadata.threat.detection_fields.value | Mappatura diretta dal campo timestamp nell'oggetto log . Il tasto è impostato su Attribute timestamp . |
log.to_ids | entity.metadata.threat.detection_fields.value | Mappatura diretta dal campo to_ids nell'oggetto log . Il tasto è impostato su Attribute to_ids . |
log.type | ioc.categorization | Mappatura diretta dal campo type nell'oggetto log . |
log.type | log_type | Utilizzato per determinare il tipo di indicatore di compromissione e mapparlo ai campi UDM appropriati. |
log.uuid | entity.metadata.product_entity_id | Mappatura diretta dal campo uuid nell'oggetto log . |
log.value | entity.entity.file.full_path | Mappato se log.type è filename . |
log.value | entity.entity.file.md5 | Mappato se log.type è md5 . |
log.value | entity.entity.file.sha1 | Mappato se log.type è sha1 . |
log.value | entity.entity.file.sha256 | Mappato se log.type è sha256 . |
log.value | entity.entity.hostname | Mappato se log.type è domain . |
log.value | entity.entity.ip | Mappato se log.type è ip-dst , ip-dst|port o ip-src . Il valore viene estratto utilizzando un pattern grok. |
log.value | entity.entity.resource.name | Mappato se log.type è mutex . |
log.value | entity.entity.registry.registry_key | Mappato se log.type è regkey . |
log.value | entity.entity.url | Mappato se log.type è uri o url . |
log.value | ioc.domain_and_ports.domain | Mappato se log.type è domain . |
log.value | entity.entity.user.email_addresses | Mappato se log.type è threat-actor . |
misp_category | entity.metadata.threat.category_details | Mappatura diretta dal campo misp_category . |
Org.name | entity.metadata.threat.detection_fields.value | Mappatura diretta dal campo name nell'oggetto Org . Il tasto è impostato su Org name . |
pubblicato | entity.metadata.threat.detection_fields.value | Mappatura diretta dal campo published . Il tasto è impostato su published . |
Tag.colour | entity.metadata.threat.detection_fields.value | Mappatura diretta dal campo colour nell'oggetto Tag . Il tasto è impostato su tag colour . |
Tag.exportable | entity.metadata.threat.detection_fields.value | Mappatura diretta dal campo exportable nell'oggetto Tag . Il tasto è impostato su tag exportable . |
Tag.hide_tag | entity.metadata.threat.detection_fields.value | Mappatura diretta dal campo hide_tag nell'oggetto Tag . Il tasto è impostato su tag hide_tag . |
Tag.id | entity.metadata.threat.detection_fields.value | Mappatura diretta dal campo id nell'oggetto Tag . Il tasto è impostato su tag id . |
Tag.is_custom_galaxy | entity.metadata.threat.detection_fields.value | Mappatura diretta dal campo is_custom_galaxy nell'oggetto Tag . Il tasto è impostato su tag is_custom_galaxy . |
Tag.is_galaxy | entity.metadata.threat.detection_fields.value | Mappatura diretta dal campo is_galaxy nell'oggetto Tag . Il tasto è impostato su tag is_galaxy . |
Tag.isinherited | entity.metadata.threat.detection_fields.value | Mappatura diretta dal campo isinherited nell'oggetto Tag . Il tasto è impostato su tag isinherited . |
Tag.name | entity.metadata.threat.detection_fields.value | Mappatura diretta dal campo name nell'oggetto Tag . Il tasto è impostato su tag name . |
Tag.numerical_value | entity.metadata.threat.detection_fields.value | Mappatura diretta dal campo numerical_value nell'oggetto Tag . Il tasto è impostato su tag numerical_value . |
Tag.user_id | entity.metadata.threat.detection_fields.value | Mappatura diretta dal campo user_id nell'oggetto Tag . Il tasto è impostato su tag user_id . |
threat_level | ioc.raw_severity | Mappatura diretta dal campo threat_level . |
threat_level | entity.metadata.threat.severity_details | Mappatura diretta dal campo threat_level . |
threat_level_id | entity.entity.labels.value | Mappatura diretta dal campo threat_level_id . Il tasto è impostato su threat_level_id . |
ts1 | ioc.active_timerange.start | Mappatura diretta dal campo ts1 . Il valore viene analizzato come data. |
ts1 | entity.metadata.interval.start_time | Mappatura diretta dal campo ts1 . Il valore viene analizzato come data. |
entity.entity.file.full_path | Mappato se type è filename . |
|
entity.entity.file.md5 | Mappato se type è md5 . |
|
entity.entity.file.sha1 | Mappato se type è sha1 . |
|
entity.entity.file.sha256 | Mappato se type è sha256 . |
|
entity.entity.hostname | Mappato se type è domain . |
|
entity.entity.ip | Mappato se type è ip-dst , ip-dst|port o ip-src . Il valore viene estratto utilizzando un pattern grok. |
|
entity.entity.port | Mappato se il campo port non è vuoto. Il valore viene convertito in un numero intero. |
|
entity.entity.resource.name | Mappato se type è mutex . |
|
entity.entity.resource.resource_subtype | Mappato se type è regkey . Il valore è impostato su regkey . |
|
entity.entity.resource.resource_type | Mappato se type è mutex o regkey . Il valore è impostato rispettivamente su MUTEX o STORAGE_OBJECT . |
|
entity.entity.registry.registry_key | Mappato se type è regkey . |
|
entity.entity.url | Mappato se type è uri o url . |
|
entity.metadata.collected_timestamp | Il valore è impostato sul timestamp della voce di log non elaborata. | |
entity.metadata.description | Il valore è impostato sul campo type se il log non elaborato è in formato CSV. In caso contrario, viene impostato sul campo info . |
|
entity.metadata.entity_type | Il valore viene determinato in base al campo type o log_type . Può essere DOMAIN_NAME , FILE , IP_ADDRESS , MUTEX , RESOURCE o URL . |
|
entity.metadata.interval.end_time | Il valore è impostato su un valore predefinito di 253402300799 secondi. | |
entity.metadata.interval.start_time | Il valore è impostato sul campo first_seen se non è vuoto. In caso contrario, viene impostato su un valore predefinito di 1 secondo o sul timestamp della voce di log non elaborata. |
|
entity.metadata.product_name | Il valore è impostato su MISP . |
|
entity.metadata.threat.confidence | Il valore è impostato su UNKNOWN_CONFIDENCE se il campo confidence è vuoto o f . In caso contrario, è impostato su HIGH_CONFIDENCE , MEDIUM_CONFIDENCE o LOW_CONFIDENCE in base al valore del campo confidence . |
|
entity.metadata.threat.confidence_details | Mappatura diretta dal campo confidence . |
|
entity.metadata.threat.detection_fields | Il valore è un elenco di coppie chiave-valore estratte da vari campi del log non elaborato. | |
entity.metadata.vendor_name | Il valore è impostato su MISP . |
|
ioc.active_timerange.end | Il valore è impostato sul campo last_seen se non è vuoto. |
|
ioc.active_timerange.start | Il valore è impostato sul campo ts1 o first_seen se non sono vuoti. In caso contrario, viene impostato su un valore predefinito di 1 secondo. |
|
ioc.categorization | Il valore è impostato su misp_category IOCs se il log non elaborato è in formato CSV. In caso contrario, viene impostato sul campo category nell'oggetto Attribute o log . |
|
ioc.confidence_score | Mappatura diretta dal campo confidence . |
|
ioc.description | Il valore viene generato combinando il campo description con il campo event_info , separati da - additional info: . |
|
ioc.domain_and_ports.domain | Mappato se type o log_type è domain . |
|
ioc.feed_name | Il valore è impostato su MISP se il campo event_source_org è vuoto. In caso contrario, viene impostato sul campo event_source_org . |
|
ioc.ip_and_ports.ip_address | Mappato se il campo ip non è vuoto. Il valore viene convertito in un indirizzo IP. |
|
ioc.ip_and_ports.ports | Mappato se il campo port non è vuoto. Il valore viene convertito in un numero intero senza segno. |
|
ioc.raw_severity | Mappatura diretta dal campo threat_level . |
|
timestamp | Il valore è impostato sul timestamp della voce di log non elaborata. |
Hai bisogno di ulteriore assistenza? Ricevi risposte dai membri della community e dai professionisti di Google SecOps.